一、缺失值的统计和删除
1. 缺失信息的统计
- 缺失数据可以使用
isna
或isnull
(两个函数没有区别)来查看每个单元格是否缺失,结合mean
可以计算出每列缺失值的比例:
df = pd.read_csv('../data/learn_pandas.csv', usecols = ['Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer'])
df.isna().head()
df.isna().mean() # 查看缺失的比例
- 如果想要查看某一列缺失或者非缺失的行,可以利用
Series
上的isna
或者notna
进行布尔索引。例如,查看身高缺失的行:
df[df.Height.isna()].head()
- 如果想要同时对几个列,检索出全部为缺失或者至少有一个缺失或者没有缺失的行,可以使用
isna, notna
和any, all
的组合。例如,对身高、体重和转系情况这3列分别进行这三种情况的检索:
sub_set = df[['Height', 'Weight', 'Transfer']]
df[sub_set.isna().all(1)] # 全部缺失
df[sub_set.isna().any(1)].head() # 至少有一个缺失
df[sub_set.notna().all(1)].head() # 没有缺失
2. 缺失信息的删除
数据处理中经常需要根据缺失值的大小、比例或其他特征来进行行样本或列特征的删除,pandas
中提供了dropna
函数来进行操作。
dropna
的主要参数为轴方向axis
(默认为0,即删除行)、删除方式how
、删除的非缺失值个数阈值thresh
(
非
缺
失
值
\color{red}{非缺失值}
非缺失值没有达到这个数量的相应维度会被删除)、备选的删除子集subset
,其中how
主要有any
和all
两种参数可以选择。
二、缺失值的填充和插值
1. 利用fillna进行填充
在fillna
中有三个参数是常用的:value, method, limit
。其中,value
为填充值,可以是标量,也可以是索引到元素的字典映射;method
为填充方法,有用前面的元素填充ffill
和用后面的元素填充bfill
两种类型,limit
参数表示连续缺失值的最大填充次数。
2. 插值函数
在关于interpolate
函数的 文档 <https://pandas.pydata.org/docs/reference/api/pandas.Series.interpolate.html#pandas.Series.interpolate>
__ 描述中,列举了许多插值法,包括了大量Scipy
中的方法。由于很多插值方法涉及到比较复杂的数学知识,因此这里只讨论比较常用且简单的三类情况,即线性插值、最近邻插值和索引插值。
对于interpolate
而言,除了插值方法(默认为linear
线性插值)之外,有与fillna
类似的两个常用参数,一个是控制方向的limit_direction
,另一个是控制最大连续缺失值插值个数的limit
。其中,限制插值的方向默认为forward
,这与fillna
的method
中的ffill
是类似的,若想要后向限制插值或者双向限制插值可以指定为backward
或both
。
s = pd.Series([np.nan, np.nan, 1, np.nan, np.nan, np.nan, 2, np.nan, np.nan])
s.values
- 例如,在默认线性插值法下分别进行
backward
和双向限制插值,同时限制最大连续条数为1:
res = s.interpolate(limit_direction='backward', limit=1)
res.values
res = s.interpolate(limit_direction='both', limit=1)
res.values
- 第二种常见的插值是最近邻插补,即缺失值的元素和离它最近的非缺失值元素一样:
s.interpolate('nearest').values
- 最后来介绍索引插值,即根据索引大小进行线性插值。例如,构造不等间距的索引进行演示:
s = pd.Series([0,np.nan,10],index=[0,1,10])
s
s.interpolate() # 默认的线性插值,等价于计算中点的值
s.interpolate(method='index') # 和索引有关的线性插值,计算相应索引大小对应的值
【NOTE】关于polynomial和spline插值的注意事项
- 在
interpolate
中如果选用polynomial
的插值方法,它内部调用的是scipy.interpolate.interp1d(*,*,kind=order)
,这个函数内部调用的是make_interp_spline
方法,因此其实是样条插值而不是类似于numpy
中的polyfit
多项式拟合插值;而当选用spline
方法时,pandas
调用的是scipy.interpolate.UnivariateSpline
而不是普通的样条插值。这一部分的文档描述比较混乱,而且这种参数的设计也是不合理的,当使用这两类插值方法时,用户一定要小心谨慎地根据自己的实际需求选取恰当的插值方法。