【Pandas】【缺失数据处理】

1.基础概念

1.1两种类型的缺失值

可忽略的缺失值

完全随机缺失:缺失数据发生的概率与已观察数据未观察数据无关
随机缺失:缺失数据发生的概率与所观察到的变量有关,与未观察到的数据无关

不可忽略的缺失值

不完全变量中数据的缺失既依赖于完全变量,又依赖于不完全变量本身,那么不可忽略

1.2缺失值的处理方法

删除存在缺失值的个案

  • 简单删除法:直接删除存在缺失值的个案,如果删除小部分样本可以解决缺失问题,那么是最好的方法
  • 权重法:当缺失值的类型为非完全随机缺失的时候,可以通过对完整的数据加权来减小偏差。把数据不完全的个案标记后,将完整的数据个案赋予不同的权重,个案的权重可以通过logistic或probit回归求得。

如果解释变量中存在对权重估计起决定行因素的变量,那么这种方法可以有效减小偏差。如果解释变量和权重并不相关,它并不能减小偏差。对于存在多个属性缺失的情况,就需要对不同属性的缺失组合赋不同的权重,这将大大增加计算的难度,降低预测的准确性,这时权重法并不理想。

插补缺失值(以最可能的值)

  • 均值插补:属于单值插补。数据的属性分为定距型和非定距型。

如果缺失值是定距型的,就以该属性存在值的平均值来插补缺失的值;如果缺失值是非定距型的,就用该属性的众数来补齐缺失的值。

  • 利用同类均值插补:属于单值插补。用层次聚类模型预测缺失变量的类型,再以该类型的均值插补。

假设X=(X1,X2,…,XP)为信息完全的变量,Y为存在缺失值的变量,那么首先对X或其子集行聚类,然后按缺失个案所属类来插补不同类的均值。 如果在以后统计分析中还需以引入的解释变量和Y做分析,那么这种插补方法将在模型中引入自相关,给分析造成障碍。

  • 极大似然估计:在缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么通过观测数据的边际分布可以对未知参数进行极大似然估计,常用EM算法

该方法比删除个案和单值插补更有吸引力,前提是适用于大样本,有效样本的数量足够以保证ML估计值是渐近无偏的并服从正态分布。这种方法可能会陷入局部极值,收敛速度也不是很快,并且计算很复杂。

  • 多重插补:思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。
  • 为每个空值产生一套可能的插补值,这些值反映了无响应模型的不确定性;每个值都可以被用来插补数据集中的缺失值,产生若干个完整数据集合。
  • 每个插补数据集合都用针对完整数据集的统计方法进行统计分析。
  • 对来自各个插补数据集的结果,根据评分函数进行选择,产生最终的插补值。
  • 多重插补弥补贝叶斯估计的不足之处:
    贝叶斯估计以极大似然的方法估计,极大似然的方法要求模型的形式必须准确,如果参数形式不正确,将得到错误得结论,即先验分布将影响后验分布的准确性。而多重插补所依据的是大样本渐近完整的数据的理论,在数据挖掘中的数据量都很大,先验分布将极小的影响结果,所以先验分布的对结果的影响不大。
    贝叶斯估计仅要求知道未知参数的先验分布,没有利用与参数的关系。而多重插补对参数的联合分布作出了估计,利用了参数间的相互关系。

2.观测缺失值与其类型

2.1 如何探索数据中的缺失值

isnull()判断是否为空
sum() 查看每一列的空值个数
notna()就是判断不是为空的
all()返回是否所有元素都为真
any() 返回是否有任意一个元素都为真

  1. isna和notna方法
  • 对Series使用返回布尔列表,对DataFrame使用返回布尔表格
df['Physics'].isna().head()
df['Physics'].notna().head()
df.isna().head()
  • 获取每一列有多少缺失值
df.isna().sum()
# info也可以查看
df.info()
  1. 查看缺失值所在的行
df[df['Physics'].isna()]
  1. 找出所有非缺失值的行
    本行中每一列都不能有缺失值,那么需要跨列去查看,所以用1
df[df.notna().all(1)]
  • 关于all()的作用
    返回是否所有元素都为真(可能在轴上)。返回布尔型,带有参数axis,默认为0,0是跨行,1是跨列,可参考下图。
    在这里插入图片描述

2.2 三种缺失符号

2.2.1 np.nan

np.nan很特别,它不等于任何东西,包括自己

np.nan == np.nan   #False
np.nan == 0  #False
np.nan == None  #False

df.equals(df) #用equals函数比较时,自动略过两侧全是np.nan的单元格,因此结果不会影响。

其次,它在numpy中的类型为浮点,由此导致数据集读入时,即使原来是整数的列,只要有缺失值就会变为浮点型。

type(np.nan)  #float
pd.Series([1,2,3]).dtype  #dtype('int64')
pd.Series([1,np.nan,3]).dtype   #dtype('float64')

此外,对于布尔类型的列表,如果是np.nan填充,那么它的值会自动变为True而不是False。
但当修改一个布尔列表时,会改变列表类型,而不是赋值为True。

pd.Series([1,np.nan,3],dtype='bool')
#true,true,false

s = pd.Series([True,False],dtype='bool')
s[1]=np.nan

在这里插入图片描述
在所有的表格读取后,无论列是存放什么类型的数据,默认的缺失值全为np.nan类型。
因此整型列转为浮点;而字符由于无法转化为浮点,因此只能归并为object类型(‘O’),原来是浮点型的则类型不变

2.2.2 None

None等于自身,布尔值为False,修改布尔列表不会改变数据类型,在传入数值类型后,会自动变为np.nan,只有当传入object类型是保持不动,几乎可以认为,除非人工命名None,它基本不会自动出现在Pandas中,在使用equals函数时不会被略过,因此下面的情况下返回False

pd.Series([None]).equals(pd.Series([np.nan]))

2.2.3 NaT

NaT是针对时间序列的缺失值,是Pandas的内置类型,可以完全看作时序版本的np.nan,与自己不等,且使用equals是也会被跳过

s_time = pd.Series([pd.Timestamp('20120101')]*5)
s_time[2] = None   #or  np.nan  or pd.NaT
s_time

在这里插入图片描述

type(s_time[2])  #pandas._libs.tslibs.nattype.NaTType

s_time[2] == s_time[2]   #False

s_time.equals(s_time)    #True

s = pd.Series([True,False],dtype='bool')
s[1]=pd.NaT
s

在这里插入图片描述
可以看出基本的特性都与np.nan相关

2.3 Nullable类型与NA符号

官方鼓励用户使用新的数据类型和缺失类型pd.NA,这个符号的出现是为了统一缺失值的处理,把刚刚上面提到的三个符号归纳成一个符号。

2.3.1 Nullable整型

该类型使用首字母为大写的 “Int”,前面提到的三种缺失值类型都会统一替换为 < N A > <NA> <NA>符号,且不改变数据类型

s_new[1] = np.nan
s_new[1] = None
s_new[1] = pd.NaT
s_new

在这里插入图片描述

2.3.2 Nullable布尔

对于该种类型而言,作用与上面的类似,记号为boolean

s_new = pd.Series([0, 1], dtype="boolean")

需要注意的是,含有pd.NA的布尔列表在1.0.2之前的版本作为索引时会报错,这是一个之前的bug,现已经修复。

2.3.3 string类型

该类型是1.0的一大创新,目的之一就是为了区分开原本含糊不清的object类型,这里将简要地提及string,因为它是第7章的主题内容。它本质上也属于Nullable类型,因为并不会因为含有缺失而改变类型。


s = pd.Series(['dog','cat'],dtype='string')

s[0] = np.nan   # dtype:string

此外,和object类型的一点重要区别就在于,在调用字符方法后,string类型返回的是Nullable类型,object则会根据缺失类型和数据类型而改变。
在这里插入图片描述

2.3.4 NA的特性

  • 逻辑运算的依赖
    只需看该逻辑运算的结果是否依赖pd.NA的取值,如果依赖,则结果还是NA,如果不依赖,则直接计算结果。
True & pd.NA
False | pd.NA
#这两个是依赖于NA的,输出结果是<NA>
  • 算数运算和比较运算
pd.NA ** 0
1 ** pd.NA
#两个输出都是1
pd.NA + 1
"a" * pd.NA
pd.NA == pd.NA
pd.NA < 2.5
np.log(pd.NA)
np.add(pd.NA, 1)
#输出都是<NA>

2.3.5 convert_dtypes方法

这个函数的功能往往就是在读取数据时,就把数据列转为Nullable类型,是1.0的新函数。

pd.read_csv('data/table_missing.csv').convert_dtypes().dtypes

在这里插入图片描述

3.缺失值的运算和分组

3.1加号与乘号规则

s = pd.Series([2,3,np.nan,4])
# 使用加法,缺失值看作0
s.sum()   #9.0

# 使用乘法时,缺失值看作1
s.prod()  #24.0

# 使用累计函数时,缺失值自动忽略
s.cumsum()  # 2.0 -> 5.0 ->NaN -> 9.0

s.cumprod() # 累乘积函数,也是忽略,不做演示

3.2 groupby中的缺失值

自动忽略为缺失值的组

df_g = pd.DataFrame({'one':['A','B','C','D',np.nan],'two':np.random.randn(5)})
df_g.groupby('one').groups

在这里插入图片描述

4.填充与剔除

4.1 fillna方法

使用fillna可以直接填充,或者使用method参数的ffill和bfill来前后填充

df['Physics'].fillna('missing').head()
df['Physics'].fillna(method='ffill').head()
df['Physics'].fillna(method='bfill').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())

在这里插入图片描述
返回的结果中没有C,根据对齐特点不会被填充

df_f.fillna(df_f.mean()[['A','B']])

在这里插入图片描述

4.2 dropna方法

  • axis参数
df_d = pd.DataFrame({'A':[np.nan,np.nan,np.nan],'B':[np.nan,3,2],'C':[3,2,1]})

df_d.dropna(axis=0)
df_d.dropna(axis=1)

在这里插入图片描述
axis=0 , 删除了所有的行
axis=1, 留下C列

  • how参数
    可以选all或者any,表示全为缺失去除和存在缺失去除
df_d.dropna(axis=1,how='all')
  • subset参数
    在某一组列范围中搜索缺失值,即只拿范围内没有缺失值的行或列
df_d.dropna(axis=0,subset=['B','C'])

5.插值

这里不说原理,只说使用的方法,可自行理解插值算法

5.1 线性插值

  • 与索引无关的线性插值
s = pd.Series([1,10,15,-5,-2,np.nan,np.nan,28])
s.interpolate()
s.interpolate().plot()
  • 与索引有关的插值
s.interpolate(method='index').plot()

如果索引是时间,那么可以按照时间长短插值。

s_t = pd.Series([0,np.nan,10]
        ,index=[pd.Timestamp('2012-05-01'),pd.Timestamp('2012-05-07'),pd.Timestamp('2012-06-03')])
s_t.interpolate().plot()
s_t.interpolate(method='time').plot()

5.2 高级插值

此处的高级指的是与线性插值相比较,例如样条插值、多项式插值、阿基玛插值等(需要安装Scipy)

  • 例子:
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()

在这里插入图片描述
有三个常用参数:

  1. limit表示最多插入多少个
  2. limit_direction表示插值方向,可选forward,backward,both,默认前向
  3. limit_area表示插值区域,可选inside,outside,默认None

问题总结

  • 如何删除缺失值占比超过25%的列?
    计算列的缺失值数量,然后除以总数得到比例,得到一个布尔列表,然后根据布尔列表进行删除
df.loc[:,(df.isna().sum()/df.isna().count()<0.25).values]
  • 采取什么方法去深入理解有缺失值的数据?
  1. 看缺失值比例
  2. 看缺失值之间关联性
  3. 看总体缺失信息
  4. 根据缺失信息判断是否为有效信息
  5. 看确实情况去清洗数据
  6. 等等
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值