pyspark之数据处理学习【缺失值处理】(2)

来源:互联网 发布:淘宝宝贝上下架软件 编辑:程序博客网 时间:2024/06/04 18:18

在我们拿到的数据集中常常会存在某个属性的数值缺失这种情况。面对这种情况有两种办法:

  • 删除这种数据(如果你的数据负担得起)
  • 对缺失值进行填充处理(有如下方法)
    • 如果是离散布尔型,可以简单地添加第三个类别--missing,将其转化为一个分类变量
    • 对于数值类型的数据,可以填充任何平均数、中值或者一些其他预定义的值。

from pyspark.sql import SparkSessionspark = SparkSession.builder.appName("dataDeal").getOrCreate()df_miss = spark.createDataFrame([    (1, 143.5, 5.6, 28,   'M',  100000),    (2, 167.2, 5.4, 45,   'M',  None),    (3, None , 5.2, None, None, None),    (4, 144.5, 5.9, 33,   'M',  None),    (5, 133.2, 5.7, 54,   'F',  None),    (6, 124.1, 5.2, None, 'F',  None),    (7, 129.2, 5.3, 42,   'M',  76000)    ], ['id', 'weight', 'height', 'age', 'gender', 'income'])
根据上面的数据,我们可以直观看出:

  • id为3的记录只有一条有用信息(height)
  • id为6的记录只有一个缺失值(age)
且根据列,我们可以发现:

  • income列的大部分值都是缺失的
  • weight列和gender列都各有一个缺失
  • age列有两个缺失
我们可以通过以下方法查找每行记录的缺失值

#查看每行记录的缺失值print df_miss.rdd.map(lambda row:(row['id'],sum([c==None for c in row]))).collect()
[(1, 0), (2, 1), (3, 4), (4, 1), (5, 1), (6, 2), (7, 0)]

通过结果我们可以看出id为3的记录有4个缺失值

#查看id3的记录df_miss.where('id==3').show()
+---+------+------+----+------+------+
| id|weight|height| age|gender|income|
+---+------+------+----+------+------+
|  3|  null|   5.2|null|  null|  null|
+---+------+------+----+------+------+

现在,我们来检查每一列中缺失的观测数据的百分比:

#检查每一列中缺失数据的百分比import pyspark.sql.functions as fndf_miss.agg(*[(1-(fn.count(c) /fn.count('*'))).alias(c+'_missing') for c in df_miss.columns]).show()

其中.count()方法的*参数(列名的位置)表示该方法计算所有的列。且前面的*表示.agg()方法将该列表处理为一组独立的参数传递给函数

从结果中我们可以看出,weight列和gender列的缺失率为14%,而age的缺失率是它们的两倍,income的缺失率达到71%。

首先,将‘income’属性移除,因为它的大部分值都是缺失的。

#移除‘income'属性df_miss_no_income = df_miss.select([c for c in df_miss.columns if c != 'income'])df_miss_no_income.show()
+---+------+------+----+------+| id|weight|height| age|gender|+---+------+------+----+------+|  1| 143.5|   5.6|  28|     M||  2| 167.2|   5.4|  45|     M||  3|  null|   5.2|null|  null||  4| 144.5|   5.9|  33|     M||  5| 133.2|   5.7|  54|     F||  6| 124.1|   5.2|null|     F||  7| 129.2|   5.3|  42|     M|+---+------+------+----+------+

由结果可以看出,我们需要移除id为3的记录,因为这一行下'weight'和‘age’列中有足够的观测数据来计算均值并且填充缺失值。

但是如果你决定移除观测数据,可以使用.dropna()方法。在这里我们还会利用thresh参数,该参数允许我们为每一行缺失数据的数量指定一个阈值,从而限定要删除的行。

#移除id3的行df_miss_no_income.dropna(thresh=3).show()
+---+------+------+----+------+| id|weight|height| age|gender|+---+------+------+----+------+|  1| 143.5|   5.6|  28|     M||  2| 167.2|   5.4|  45|     M||  4| 144.5|   5.9|  33|     M||  5| 133.2|   5.7|  54|     F||  6| 124.1|   5.2|null|     F||  7| 129.2|   5.3|  42|     M|+---+------+------+----+------+

另一方面,如果想要填充数据,可以使用.fillna()方法。该方法能够填充单个整型(integer、长整型long)、浮点型(float)、字符串(string)类型。也可以传递一个{‘<colName>’:<value>}形式的字典。

#计算均值means = df_miss_no_income.agg(*[fn.mean(c).alias(c) for c in df_miss_no_income.columns if c != 'gender']).toPandas().to_dict('records')[0]means['gender']='missing'#填充df_miss_no_income.fillna(means).show()
+---+-------------+------+---+-------+| id|       weight|height|age| gender|+---+-------------+------+---+-------+|  1|        143.5|   5.6| 28|      M||  2|        167.2|   5.4| 45|      M||  3|140.283333333|   5.2| 40|missing||  4|        144.5|   5.9| 33|      M||  5|        133.2|   5.7| 54|      F||  6|        124.1|   5.2| 40|      F||  7|        129.2|   5.3| 42|      M|+---+-------------+------+---+-------+

pandas to_dict()方法的record参数表示会创建如下的字段:

{'age':[9.0,51.0], 'height':[4.899999999995,5.6], 'weight':[115.0,146.849999999997]}