缺失值的处理
任何类型的数据都可能存在缺失值,如数值中的缺失、无序类别的缺失、有序类别的缺失、文本的缺失、时间序列的缺失。缺失不意味着无用,有时候还蕴含了很多信息。本章将介绍缺失数据的统计、删除、填充、插值和Nullable类型。
import pandas as pd
df = pd.read_csv('../data/data168290/learn_pandas.csv')
df
df = df[['Grade','Name','Gender','Height','Weight','Transfer']]
缺失值的统计和删除
缺失信息的统计
可以使用isna()
和isnull()
这两个函数来查看DataFrame单元格是否缺失数据,在这之后还可以结合聚合函数,如mean()
计算每列缺失值所占的比例。
df.isna().mean()
如果想要查看某一列是否缺失,或非缺失的行,可以在Series
上使用isna()
货notna()
进行布尔索引。如果想同时对几个列,检索出全部缺失、至少一个缺失或没有缺失的行,可以使用isna(), any()
的组合,例如对身高、体重这2列数据分别进行以上3种情况的检索
df[df.Height.isna()] # 传入布尔列表来选择指定行
# 这里是查看身高数据缺失的行
sub_set = df[['Height', 'Weight']]
df[sub_set.isna().any(1)] # 至少有一个缺失值
df[sub_set.notna().all(1)] # 没有缺失值
df[sub_set.isna().all(1)] # 身高体重全部缺失
缺失信息的删除
数据处理中有时候需要根据缺失值的大小、占比以及其他特征来进行行样本和列特征的删除,这些可以用dropna()
方法来实现,其主要参数为axis=0
(默认删除行),删除方式how=<any,all>
和删除的非缺失值个数阈值thresh
(非缺失值没有达到这个数量的相应纬度会被删除),备选的删除子集subset
例如删除身高、体重两列至少有一个缺失值的行:
res = df.dropna(how='any', subset=['Height', 'Weight'])
res = df.dropna(axis=1, thresh=df.shape[0]-15) # 删除超过15个缺失值的列,这里身高列被删除
res.columns
# 用布尔索引实现删除操作
res = df.loc[df[['Height', 'Weight']].notna().all(1)]
res = df.loc[:, ~(df.isna().sum()>15)]
res.columns
缺失值的填充和插值
fillna()
fillna()
有3个常用参数:
value
: 代表填充值,可以是标量,也可以是索引到元素的字典映射method
: 填充方法,有用前面的元素填充为ffill
,和用后面的元素填充bfill
两种类型limit
: 表示连续缺失值的最大填充次数
有时候为了更加合理地填充,需要先完成数据分组再填充,例如根据年级进行学生身高地平均值填充:
df.groupby('Grade')['Height'].transform(lambda x: x.fillna(x.mean()))
插值函数
pandas地插值主要由interpolate()
方法来实现,待补充
Nullable类型
缺失值地表示和处理非常麻烦,框架为了兼容缺失值地表示和处理,需要做许多额外工作。本节将讲述python,numpy和pandas中的缺失值表示、Nullable类型引入的原因、缺失数据的计算规则和分组规则。
缺失记号及其缺陷
- python: 使用
None
来表示缺失值,其与除自身之外的对象都不相等 - numpy: 使用
np.nan
表示缺失值,与自己不相等,与任何对象都不相等
在对缺失序列或表的元素进行比较操作时,np.nan
的对应位置会返回False
,但是在使用equals()
函数进行两个表或两个序列的相同性检验时,会自动跳过两侧都是缺失值的位置s1 = pd.Series([1, np.nan]) s2 = pd.Series([1, 2]) s3 = pd.Series([1, np.nan]) s1 == 1 s1.equals(s2) s1.equals(s3) # -> True
- pandas: 在时间序列的对象中,用
pd.NaT
来指代缺失值,其作用和np.nan
一致。
为什么不用np.nan
呢?因为这个本身是一种浮点类型,当其和时间类型混合会变成object
类型,存储整数的Series中出现缺失值,Series的存储类型会转换为float64,存储bool类型的Series中出现缺失值,Series的存储类型会转换为object而不是bool
Nullable类型的性质
缺失数据的计算和分组
习题
Ex1
# (1)
dff.loc[dff.isna().sum(axis=1)>520,dff.isna().mean()<0.5]
# loc索引不熟练
# (2)
print(-1 in dff.values) # 证明这里面不含有-1这个值
dff_fill = dff.fillna(value=-1)
res2 = dff.loc[:, (dff_fill.rolling(window=21, axis=0).sum()<-20).any()]
# 使用了滑窗函数来代替apply方法
# 参考答案
def missing_helper(s):
temp = s.isna().astype("int").rename("temp_col")
temp = pd.concat([s, (temp != temp.shift()).cumsum()], axis=1)
return temp[s.isna()].groupby("temp_col").size().max() > 20
res = df.loc[:, df.apply(missing_helper)]
# (3)
cols = []
for i in range(1, 999):
temp = df.iloc[:,[i-1,i+1]]
if temp.isna().all(1).mean() > 0.1:
cols.append("f%d"%i)
Ex2
Ex3