一、缺失预测及其类型
- 了解缺失值信息
- df.isna() #或者df.列名.isna()
- df.info()
- df.notna()# 非空信息
- df[~df.列名.isna()] 对空取反操作,就是找非空
- 求缺失个数 df.isna().sum()
- 通过布尔值选择缺失值所在行 df[df.列名.isna()]
- 选择所有非缺失值列 df[df.notna().all(1)] 就是每一列都没有缺失值,相当于寻找一条完整记录。
- 三种缺失值符号
- np.nan 特点
- 浮点类型的数据,填充np.nan后会变为object类型
- 修改布尔列表时,会改变列表类型,s=pd.Series([True,False],dtype='bool') s[1]=np.nan dtype 为float
- 对于布尔类型,如果事np.nan填充,值会变为True pd.Series([1,np.nan,3],dtype='bool') True True True
- 整数列,如果存在缺失值就会变成浮点型pd.Series([1,2,3]) .dtype int64 pd.Series([1,np.nan,3]).dtype flost64
- 在numpy中,np.nan的类型为float,可以通过type(np.nan)得到
- 在使用equals时,自动掠夺两侧全是空值的单元,df.equals(df)会得到True
- np.nan 不等于None
- np.nan 不等于0
- 自身不等于自身
- None
- None==None True
- 布尔值为False
- 修改布尔值时,不改变数据类型
- 传入数值后,自动变为np.nan
- 传入object类型时保持不变
- 使用equals函数时不会掠过,pd.Series([None]).equals(pd.Series([np.nan])
- NaT
- NaT是针对时间序列的缺失值,是pandas的内置类型,时序版本的np.nan与自己不等,使用equals是也会被跳过
- pd.Series([pd.Timestamp('20200202')]*5) datetime64[ns]类型
- 为datetime64添加空值,类型为NaT pd.NaT
- None NaT np.nan 在datetime类型中都是NaT
- pd.NaT==pd.NaT false
- pd.NaT.equals(pd.NaT)
- np.nan 特点
- Nullable类型与Na符号
- Nullable 是1.0新本中引入的,目的是为了统一缺失值处理方法。
- 整型 s_new=pd.Series([1,2],dtype='Int64) 更新后的是使用大写Int,在这个基础上无论是np.nan None还是pd.NaT最后都是显示<NA> 不改变之前的类型;
- 布尔 s_new=pd.Series([0,1],dtype='boolean') 不改变类型
- string pd.Series(['dog','cat'],dtype='string) 添加缺失值,不会改变类型 <NA>
- Na的特性
- 逻辑运算
- 逻辑运算的结果根据是否依赖pd.NA的取值,依赖的话就是NA,不依赖的直接计算结果
- 算数运算和比较运算
- pd.NA**0 结果为1
- 1**pd.NA 结果为1
- 其他结果都是NA
- pd.NA+1 <NA>
- 'a'*pd.NA <NA>
- pd.NA==pd.NA <NA>
- pd.NA<2.5 <NA>
- 逻辑运算
- convert_dtype方法
- pd.read_csv(''路径').convert_dtypes() 把数据转化为Nullable类型
二、缺失数据的运算与分组
- 使用加法时缺失值为0 s.sum()
- 使用乘法缺失值为1 s.prod()
- 使用累加函数时缺失值自动略过 s.cumsum()
- 使用累乘函数缺失值自动掠过 s.cumprod()
- 默认比较和前一个的比值 s.pct_change() 第一个值之前没有值,结果为NaN 缺失值一列为0
- groupby时自动忽略缺失值的组
三、填充与剔除
- fillna方法
-
值填充与向前后填充
df.列名.fillna('missing')
df.列名.fillna(method='ffill')
df.列名.fillna(method='backfill')
-
- 填充中的对齐特性(不是特别懂)
- df_f=pd.DataFrame({'A':[1,3,np.nan],'B':[2,4,np.nan],'C':[3,5,np.nan]})
- df_f.fillna(df_f.mean())
- df_f.fillna(df_f.mean()[['A','B']]) 返回的结果没有c,不会被填充
- dropna方法
- df.dropna(axis=0) 行
- df.dropna(axis=1) 列
- df.dropna(axis=1,how='all) 全部为缺失值时去除
- df.dropna(axis=0,subset=['B','C']) 只为BC两列去除空值
四、插值
s.interpolate(method='linear', axis=0, limit=None, inplace=False, limit_direction='forward', limit_area=None, downcast=None, **kwargs)
s=pd.Series([1,10,15,-5,-2,np.nan,np.nan,28])
s
out:
0 1.0
1 10.0
2 15.0
3 -5.0
4 -2.0
5 NaN
6 NaN
7 28.0
dtype: float64
带有多索引的只支持线性插值方法
- method
- linear :忽略索引,平等对待间隔。多值索引的唯一方法。
- time 时间索引,和索引无关
- pad 使用过去的值填充
-
s.interpolate(method='pad') Out[104]: 0 1.0 1 10.0 2 15.0 3 -5.0 4 -2.0 5 -2.0 6 -2.0 7 28.0
-
- ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘spline’, ‘barycentric’, ‘polynomial’
- ‘spline’和‘polynomial’需要添加order
df.interpolate(method='polynomial', order=5)
-
'krogh', 'piecewise_polynomial', 'spline', 'pchip', 'akima'
-
'from_derivatives'
- limit 表示最多插入多少个
- inplace
- limit_direction 表示插值方向,默认前向
- forward
- backword
- both
- limit_area 表示插值区域
问题1:如何删除缺失值占比超过25%的列?
方法一:
l=(df.isna().sum()/df.shape[0]).sort_values()>0.25 #先找到缺失值大于0.25的布尔值
df.drop(columns=l[l].index) l[l].index 找到男足条件的列
方法二:
df.dropna(axis=1,thresh=df.shape[0]*(1-0.25)) thresh 保留至少n个不为空的 使用axis选择行或者列
问题2:什么是Nullable类型?请谈谈为什么要引入这个设计?
它是一种特殊的整型,是为了解决pandas前几个版本对于空值不统一的问题。
问题3 对于一份有缺失值的数据,可以采取哪些策略或方法深化对它的了解
- 判断缺失值数量及特征重要性再选择策略;
- 对于不是特别重要的特征且缺失数据量较大,考虑删除特征,dropna或者drop;
- 对于重要特征,那么考虑进行插值,除了本文所说的插值,也可以考虑使用决策树等机器学习方法进行填补
练习
现有一份虚拟数据集,列类型分别为string/浮点/整型,请解决如下问题:
- 请以列类型读入数据,并选出C为缺失值的行。
data=pd.read_csv('data/Missing_data_one.csv').convert_dtypes()
data[data.C.isna()]
A B C
1 not_NaN 0.700 <NA>
5 not_NaN 0.972 <NA>
11 not_NaN 0.736 <NA>
19 not_NaN 0.684 <NA>
21 not_NaN 0.913 <NA>
- 现需要将A中的部分单元转为缺失值,单元格中的最小转换概率为25%,且概率大小与所在行B列单元的值成正比。
total_b = data['B'].sum() min_b = data['B'].min() data['A'] = pd.Series(list(zip(data['A'].values ,data['B'].values))).apply(lambda x:x[0] if np.random.rand()>0.25*x[1]/min_b else np.nan) data.head()
现有一份缺失的数据集,记录了36个人来自的地区、身高、体重、年龄和工资,请解决如下问题
- 统计各列缺失的比例并选出在后三列中至少有两个非缺失值的
#读入数据 d=pd.read_csv('data/Missing_data_two.csv').convert_dtypes() #查看各列缺失比例 d.isnull().sum()/d.shape[0] #后三列至少有两个非缺失值的行 d[d.iloc[:,-3:].notna().sum(axis=1)>=2]
- 请结合身高列和地区列中的数据,对体重进行合理插值。
d3 = d2.copy() for name,group in d2.groupby('地区'): d2.loc[group.index,'体重'] = group[['身高','体重']].sort_values(by='身高')['体重'].interpolate() d2['体重'] = d2['体重'].round(decimals=2) d2.head() def set_missing_w(data): # 把已有的数值型特征取出来丢进Random Forest Regressor中 df=data.copy() dis = {'A':'0','B':'1','C':'2'} df['地区'] = df['地区'].map(dis) w_df = df[['地区','身高', '体重']] # 分成已知体重和未知体重两部分 known_w = w_df[w_df.体重.notnull()] unknown_w = w_df[w_df.体重.isna()] # y即目标体重 y = known_w.iloc[:, 2] # print(y) # X即特征属性值 X = known_w.iloc[:, :2] # print(X) # fit到RandomForestRegressor之中 rfr = RandomForestClassifier(random_state=0, n_estimators=2000, n_jobs=-1) rfr.fit(X, y.astype('int')) # 用得到的模型进行未知体重结果预测 predictedAges = rfr.predict(unknown_w.iloc[:,:2]) # 用得到的预测结果填补原缺失数据 df.loc[ (df.体重.isnull()), '体重' ] = predictedAges return df, rfr