4. 缺失值的处理

面对大量数据经常会出现残缺不全的情况,面对这样的数据我们需要对缺失值进行预先处理。

填充缺失值一般用两个值:

  • None: 对象类型内容的默认缺失值
  • NaN: 数值类型的默认缺失值,用numpy.nan表示

需要注意的是:

  • 不同语言/工具可能对缺失值的默认处理方式不同,所以,如果拿到的是别的处理过的文件,可能需要对已经替换过的缺失值再进行替换一次。
  • NaN的使用具有传染性,就是任何数据跟NaN进行操作,最终的结果都是NaN, 性质很像乘法中的0,所以在有的操作函数中,numpy提供了另外一套操作,对NaN缺失值自动过滤掉,而不是让他传染给所有结果
  • None和NaN可以互换,或者可以认为这两个值在Pandas中等价

4.1. 对NaN不敏感的操作函数

有时候NaN的传染性并不是让人喜欢,他会导致我们的结果出现重大偏差甚至错误,所以在处理的时候我们还提供了另外一套对NaN不敏感的函数:

  • np.nansum
  • np.nanmin
  • np.nanmax
# 创建带有NaN的数组
a = np.array([3, 2, 3, np.nan, 4])
print("a = \n", a)

print()
# 对于普通的函数操作,NaN具有传染性
print("np.sum = ", np.sum(a))
print("np.min = ", np.min(a))
print("np.max = ", np.max(a))b'

# 如果想避免NaN传染性带来的问题,需要使用相应NaN非敏感函数
print("np.nansum = ", np.nansum(a))
print("np.nanmin = ", np.nanmin(a))
print("np.nanmax = ", np.nanmax(a))
a = 
 [ 3.  2.  3. nan  4.]

np.sum =  nan
np.min =  nan
np.max =  nan
np.nansum =  12.0
np.nanmin =  2.0
np.nanmax =  4.0


/Users/augs/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py:83: RuntimeWarning: invalid value encountered in reduce
  return ufunc.reduce(obj, axis, dtype, out, **passkwargs)

4.2. 缺失值的发现

发现缺失值可以使用两个函数:

  • isnull
  • notnull

每个函数都返回布尔类型的掩码数据。

# 准备的实验数据
data = pd.Series([23, np.nan, "hahaha", "two", 23, None])
print("data = \n ", data)
data = 
  0        23
1       NaN
2    hahaha
3       two
4        23
5      None
dtype: object
# isnull用来判断是否是空

# isnull返回的是布尔值
print("\n data.isnull = \n", data.isnull())

# notnull返回的是布尔值
print("\n data.notnull = \n", data.notnull())

# 可以使用这个作为掩码操作
print("\n data[data.notnull()] = \n", data[data.notnull()])
 data.isnull = 
 0    False
1     True
2    False
3    False
4    False
5     True
dtype: bool

 data.notnull = 
 0     True
1    False
2     True
3     True
4     True
5    False
dtype: bool

 data[data.notnull()] = 
 0        23
2    hahaha
3       two
4        23
dtype: object

4.3. 剔除缺失值

对于缺失值的处理一般是剔除或者用一个特殊的值来进行填充:

  • dropna: 剔除缺失值,常用的两个参数:
    • axis: 控制剔除行或者列
    • thresh:如果有效数据数量低于这个值,则对应的行或列将被剔除
  • fillna: 缺失值用别的值进行填充
# 剔除缺失值
# 剔除后只留下原来的真正的值
print("\n data.dropna = \n", data.dropna())
 data.dropna = 
 0        23
2    hahaha
3       two
4        23
dtype: object
# 需要注意的是,如果是二维数据,剔除后需要把整行都剔除,不仅仅是把NaN的一个值剔除
df = pd.DataFrame([[1, np.nan, 3],
                  [2, 4, 9],
                  [np.nan, np.nan, 9]])
print("\n df.dropna = \n", df.dropna())
 df.dropna = 
      0    1  2
1  2.0  4.0  9
# 如果改变剔除的默认行为,比如剔除包含NaN的行,则需要axis参数
print("\n df.dropna(axis='columns') = \n", df.dropna(axis='columns'))
 df.dropna(axis='columns') = 
    2
0  3
1  9
2  9
# thresh参数
# 数据列中,低于thresh=2的列被剔除
print("\n df.dropna(axis='columns') = \n", df.dropna(axis='columns', thresh=2))
 df.dropna(axis='columns') = 
      0  2
0  1.0  3
1  2.0  9
2  NaN  9

4.4. 填充缺失值

对于缺失值一般使用换一个特定的值进行填充就可以。填充的时候可以使用一些特定的值,比如0,-1等,也可以使用一些处理后的值,比如填充(imputation)或者转换(interpolation)之后的数据。

填充函数是fillna,常用参数为:

  • axis: 坐标轴,行或者列
  • method: 填充方式
    • ffill: forward-fill, 从前向后填充
    • bfill: backward-fill, 从后向前填充
# 准备数据
df = pd.DataFrame([[1, np.nan, 3],
                  [2, 4, 9],
                  [np.nan, np.nan, 9]])
print("\n df = \n", df)
 df = 
      0    1  2
0  1.0  NaN  3
1  2.0  4.0  9
2  NaN  NaN  9
# 使用某一个值进行填充
print("df.fillna = \n", df.fillna(-1))
df.fillna = 
      0    1  2
0  1.0 -1.0  3
1  2.0  4.0  9
2 -1.0 -1.0  9
# forward-fill
print("df.fillna(ffill) = \n", df.fillna( method="ffill"))
df.fillna(ffill) = 
      0    1  2
0  1.0  NaN  3
1  2.0  4.0  9
2  2.0  4.0  9
# backward-fill
print("df.fillna(bfill) = \n", df.fillna(axis=1,  method="bfill"))
df.fillna(bfill) = 
      0    1    2
0  1.0  3.0  3.0
1  2.0  4.0  9.0
2  9.0  9.0  9.0