1.缺失值概要
数据的缺失主要包括记录的缺失和记录中某个字段信息的缺失,两者都会造成分析结果的不准确,以下从缺失值产生的原因及影响扥方面展开分析。
(1)缺失值产生的原因
1)有些信息暂时无法获取,或者获取信息的代价太大;
2)有些信息是被遗漏的。可能是因为输入时认为不重要、忘记填写或对数据理解错误等一些人为因素而遗漏,也可能是由于数据采集设置的故障、存储介质的故障、传输媒体的故障灯非人为原因而丢失;
3)属性值不存在。在某些情况下,缺失值并不意味着数据有错误。对一些对象来说某些属性是不存在的,如一个未婚者的配偶姓名、一个儿童的固定收入等。
(2)缺失值的影响
1)数据挖掘建模将丢失大量的有用信息;
2)数据挖掘模型所表现出的不确定性更加显著,模型中蕴涵的规律更难把握。
3)包含空值的数据会使建模过程陷入混乱,导致不可靠的输出。
(3)缺失值的分析
使用简单的统计分析,可以得到含有缺失值的属性的个数,以及每个属性的未缺失数、缺失数与缺失率等。
从总体上来说,缺失值的处理分为删除存在缺失值的记录、对可能值进行插补和不处理3种情况。
2.缺失值处理
import pandas as pd
import numpy as np
df = pd.read_csv('data/table_missing.csv')
#默认输出DataFrame的前5行
df.head()
(1)了解缺失数据
函数isna和notna方法
df['Physics'].isna().head()
df['Physics'].notna().head()
统计每列(每行)的缺失情况
#统计每列的缺失
df.isna().sum()#或者df.isnull().sum()
#统计每行的缺失
df.isna(axis=0).sum()#或者df.isnull(axis=0).sum()
挑出该列缺失值的行
df[df['Physics'].isna()]
挑选出所有非缺失值的列
这里介绍了all和any的用法,all是全部值,any是至少有一个值
#all是全部非缺失值
df[df.notna().all(1)]
#any至少有一个不是缺失值
df[df.notna().any(1)]
(2)三种缺失符号
(a)np.nan
它不等与任何东西,甚至不等于自己¶
在用equals函数比较时,自动略过两侧全是np.nan的单元格
在numpy中的类型为浮点,由此导致数据集读入时,即使原来是整数的列,只要有缺失值就会变为浮点型
对于布尔类型的列表,如果是np.nan填充,那么它的值会自动变为True而不是False,但当修改一个布尔列表时,会改变列表类型,而不是赋值为True
在所有的表格读取后,无论列是存放什么类型的数据,默认的缺失值全为np.nan类型,因此整型列转为浮点;而字符由于无法转化为浮点,因此只能归并为object类型('O'),原来是浮点型的则类型不变。
(b)None
None比前者稍微好些,至少它会等于自身
它的布尔值为False
修改布尔列表不会改变数据类型
在传入数值类型后,会自动变为np.nan
只有当传入object类型是保持不动,几乎可以认为,除非人工命名None,它基本不会自动出现在Pandas中
在使用equals函数时不会被略过,因此下面的情况下返回False¶
(c)NaT
NaT是针对时间序列的缺失值,是Pandas的内置类型,可以完全看做时序版本的np.nan,与自己不等,且使用equals是也会被跳过。
(3)Nullable类型与NA符号
(a)Nullable整形
对于该种类型而言,它与原来标记int上的符号区别在于首字母大写:‘Int’,好处在于缺失值的类型都被替换成统一的NA符号,且不改变数据类型。
(b)Nullable布尔
与Nullable整型一致,且数据类型不会变成浮点型
(c)string类型
为了区分开原本含糊不清的object类型,它本质上也属于Nullable类型,因为不会含有缺失而改变类型;
与object类型的一点重要区别就在于,在调用字符方法后,string类型返回的是Nullable类型,object则会根据缺失类型和数据类型而改变。
(4)NA的特性
(a)逻辑运算
只需看该逻辑运算的结果是否依赖pd.NA的取值,如果依赖,则结果还是NA,如果不依赖,则直接计算结果,取值不明直接报错
(b)算术运算和比较运算
当出现pd.NA**0和1**pd.NA时结果为1,其他情况为NA
(5)convert_dtypes方法
在读取数据时,就把数据列转为Nullable,是pandas1.0的新函数。
pd.read_csv('data/table_missing.csv').convert_dtypes().dtypes
3.缺失数据的运算与分组
(a)加号和乘号规则
使用加法时,缺失值为0;
使用乘法时,缺失值为1;
使用累计函数时,缺失值自动略过
(b)groupby方法中的缺失值
自动忽略为缺失值的组
df_g = pd.DataFrame({'one':['A','B','C','D',np.nan],'two':np.random.randn(5)})
print(df_g)
df_g.groupby('one').groups
4.填充与剔除
(a)fillna方法(值填充与前后向填充,methods=ffill or bfill)
#值填充
df['Physics'].fillna('missing').head()
#前向填充
df['Physics'].fillna(method='ffill').head()
#后向填充
df['Physics'].fillna(method='backfill').head()
指定列填充
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())
#填充A,B两列
df_f.fillna(df_f.mean()[['A','B']])
(b)dropna方法
axis参数是行或列的参数,如果axis=0,则对应是每一行,如果axis=1,则对应没一列
how参数是可以选择all或者是any,表示全为缺失去除或存在缺失去除
subset参数是在某一列范围中搜索缺失值
5.插值(interpolation)
常见的数据插补方法有:
(1)线性插值
(a)与索引无关的线性插值
默认状态下,interpolate会对缺失的值进行线性插值
s = pd.Series([1,10,15,-5,-2,np.nan,np.nan,28])
s.interpolate()
(b)与索引有关的线性插值
method中的index和time选项可以是插值线性地依赖索引,即插值为索引的线性函数
s.interpolate(method='index')
如果索引是时间,那么可以按照时间长短插值。
s_t = pd.Series([0,np.nan,10],index=[pd.Timestamp('2012-05-01'),pd.Timestamp('2012-05-07'),pd.Timestamp('2012-06-03')])
#未按照time插值(图1)
s_t.interpolate()
#按照time插值(图2)
s_t.interpolate(method='time')
(2)高级插值方法
与线性插值相比较,例如样条插值、多项式插值、阿基玛插值等,可进一步学习。
ser = pd.Series(np.arange(1, 10.1, .25) ** 2 + np.random.randn(37))
missing = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29])
ser[missing] = np.nan
methods = ['linear', 'quadratic', 'cubic']
df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods})
df.plot()
(3)interpolate的限制参数
(a)limit最多插入多少个,s.interpolate(limit=2)
(b)limit_direction表示插值方向,可选forword,backward,both,默认前向,s.interpolate(limit_direction='backward')
(c)limit_area表示插值区域,可选inside,outside,默认None,s.interpolate(limit_area='inside')
练习题:
(1)如何删除缺失值在25%以上的列
s.drop(s.columns[s.isna().sum()/s.shape[0]>0.25],axis=1)