数据预处理——4种缺失值处理方法

1.删除含有缺失值的个案

主要有简单删除法权重法。简单删除法是对缺失值进行处理的最原始方法。它将存在缺失值的个案删除。如果数据缺失问题可以通过简单的删除小部分样本来达到目标,那么这个方法是最有效的。当缺失值的类型为非完全随机缺失的时候,可以通过对完整的数据加权来减小偏差。把数据不完全的个案标记后,将完整的数据个案赋予不同的权重,个案的权重可以通过logistic或probit回归求得。如果解释变量中存在对权重估计起决定行因素的变量,那么这种方法可以有效减小偏差。如果解释变量和权重并不相关,它并不能减小偏差。对于存在多个属性缺失的情况,就需要对不同属性的缺失组合赋不同的权重,这将大大增加计算的难度,降低预测的准确性,这时权重法并不理想。

data1=data.dropna()#丢弃缺失值 dropna()删除缺失值所在行(axis=0)或列(axis=1),默认为 axis=0

2.补全

统计法: 对于数值型的数据, 使用均值、 加权均值、 中位数等方法补足; 对于分类型数据, 使用类别众数最多的值补足。

# 1.均值补全
data['age'] = data['age'].fillna(data['age'].mean()))
# 2.众数补全
import pandas as pd
data = [ 1,1,1,2,2,2,3]
data = pd.Series(data)
print(data.mode())
data['age'] = data['age'].fillna(data['age'].mode()))
# 3.用插值法填充
data['age'] = data['age'].interpolate()
# 4.上下数据补全
data['age'] = data['age'].fillna(method='pad'))
data['age'] = data['age'].fillna(method='bfill'))

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

模型法: 更多时候我们会基于已有的其他字段, 将缺失字段作为目标变量进行预测, 从而得到最为可能的补全值。 如果带有缺失值的列是数值变量, 采用回归模型补全; 如果是分类变量, 则采用分类模型补全。
(1)回归填充
a. 确定充填缺失值的变量(特征列)
b. 拆分原始数据集:
根据需要充填缺失值的变量,把原始数据集拆分为2个子集(1. 不含有缺失值:dataset_train; 2. 只含有缺失值dataset_pred)
c. 辨析并检验相关变量的相关性:
经验分析判定与充填缺失值的变量相关的属性列有哪些,应用统计分析工具,在dataset_train数据集上查看验证所选择的属性列之间的相关性。
d. 建模并预测:
使用dataset_train数据集建立线性回归模型,并应用建好的模型对dataset_pred数据集中的缺失变量进行预测估计
e. 合并还原数据集:
将两个子集合并还原为一个数据集,为后续建模准备好数据。
————————————————————————
引用于

https://blog.csdn.net/weixin_45914452/article/details/103570155

# 1.KNN填充
from fancyimpute import BiScaler, KNN, NuclearNormMinimization, SoftImpute
dataset = KNN(k=3).complete(dataset)

专家补全: 对于少量且具有重要意义的数据记录, 专家补足也是非常重要的一种途径。
其他方法: 例如随机法、 特殊值法、 多重填补等。
多重插补(Multiple Imputation,MI)。多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。具体实践上通常是估计出待插补的值,然后再加上不同的噪声,形成多组可选插补值。根据某种选择依据,选取最合适的插补值。

多重插补方法分为三个步骤:①为每个空值产生一套可能的插补值,这些值反映了无响应模型的不确定性;每个值都可以被用来插补数据集中的缺失值,产生若干个完整数据集合。②每个插补数据集合都用针对完整数据集的统计方法进行统计分析。③对来自各个插补数据集的结果,根据评分函数进行选择,产生最终的插补值。

假设一组数据,包括三个变量Y1,Y2,Y3,它们的联合分布为正态分布,将这组数据处理成三组,A组保持原始数据,B组仅缺失Y3,C组缺失Y1和Y2。在多值插补时,对A组将不进行任何处理,对B组产生Y3的一组估计值(作Y3关于Y1,Y2的回归),对C组作产生Y1和Y2的一组成对估计值(作Y1,Y2关于Y3的回归)。

当用多值插补时,对A组将不进行处理,对B、C组将完整的样本随机抽取形成为m组(m为可选择的m组插补值),每组个案数只要能够有效估计参数就可以了。对存在缺失值的属性的分布作出估计,然后基于这m组观测值,对于这m组样本分别产生关于参数的m组估计值,给出相应的预测即,这时采用的估计方法为极大似然法,在计算机中具体的实现算法为期望最大化法(EM)。对B组估计出一组Y3的值,对C将利用 Y1,Y2,Y3它们的联合分布为正态分布这一前提,估计出一组(Y1,Y2)。

上例中假定了Y1,Y2,Y3的联合分布为正态分布。这个假设是人为的,但是已经通过验证(Graham和Schafer于1999),非正态联合分布的变量,在这个假定下仍然可以估计到很接近真实值的结果。

3.真值转换

该思路的根本观点是, 我们承认缺失值的存在, 并且把数据缺失也作为数据分布规律的一部分, 这将变量的实际值和缺失值都作为输入维度参与后续数据处理和模型计算。 但是变量的实际值可以作为变量值参与模型计算, 而缺失值通常无法参与运算, 因此需要对缺失值进行真值转换。以用户性别字段为例, 很多数据库集都无法对会员的性别进行补足, 但又舍不得将其丢弃, 那么我们将选择将其中的值, 包括男、 女、未知从一个变量的多个值分布状态转换为多个变量的真值分布状态。
转换前: 性别(值域: 男、 女、 未知) 。
转换后: 性别_男(值域1或0) 、 性别_女(值域1或0) 、 性别_未知(值域1或0) 。
然后将这3列新的字段作为输入维度用以替换原来的1个字段参与后续模型计算。
一、分类数据和顺序数据
分类数据:
分类数据☞某些数据属性只能归于某一类别的非数值型数据。例如性别中的男、女就是分类数据。分类数据中的值没有明显的高、低、大、小等包含等级、顺序、排序、好坏等逻辑的划分,只是用来区分两个或多个具有相同或相同价值的属性。
顺序数据:
顺序数据☞能归于某一有序类别的非数值型数据,例如用户的价值度分为高、中、低,学历分为博士、硕士、学士,这些都属于顺序数据。在顺序数据中,有明显的的排序规律和逻辑层次的划分。

二、运用标志方法处理分类和顺序变量
  分类数据和顺序数据要参与模型计算,通常都会转化为数值型数据。当然,某些算法是允许这些数据直接参与计算的,例如分类算法中的决策树、关联规则等。将非数值型数据转换为数值型数据的最佳方法是:将所有分类或顺序变量的值域从一列多值的形态转为多列只包含真值的形态,其中的真值可用True,False或0,1的方式来表示。这种标志转换的方法有时候也称真值转换。
因此,可以使用LabelEncoder,OneHotEncoder

在本示例中, 将模拟有两列数据分别出现分类数据和顺序数据的情
况, 并通过自定义代码以及sklearn代码分别进行标志转换。

import pandas as pd # 导入pandas库
from sklearn.preprocessing import OneHotEncoder # 导入OneHotEncoder库
生成数据
df = pd.DataFrame({'id': [3566841, 6541227, 3512441],
'sex': ['male', 'Female', 'Female'],
'level': ['high', 'low', 'middle']})
print (df) # 打印输出原始数据框
自定义转换主过程
df_new = df.copy() # 复制一份新的数据框用来存储转换结果
for col_num, col_name in enumerate(df): # 循环读出每个列的索引值和列名
col_data = df[col_name] # 获得每列数据
col_dtype = col_data.dtype # 获得每列dtype类型
if col_dtype == 'object': # 如果dtype类型是object(非数值型) , 执行条件
df_new = df_new.drop(col_name, 1) # 删除df数据框中要进行标志转换的列
value_sets = col_data.unique() # 获取分类和顺序变量的唯一值域
for value_unique in value_sets: # 读取分类和顺序变量中的每个值
col_name_new = col_name + '_' + value_unique # 创建新的列名, 使用“原标题+值”的方式命名
col_tmp = df.iloc[:, col_num] # 获取原始数据列
new_col = (col_tmp == value_unique) # 将原始数据列与每个值进行比较, 相同为True, 否则为False
df_new[col_name_new] = new_col # 为最终结果集增加新列值
print (df_new) # 打印输出转换后的数据框
使用sklearn进行标志转换
df2 = pd.DataFrame({'id': [3566841, 6541227, 3512441],
'sex': [1, 2, 2],
'level': [3, 1, 2]})
id_data = df2.values[:, :1] # 获得ID列
transform_data = df2.values[:, 1:] # 指定要转换的列
enc = OneHotEncoder() # 建立模型对象
df2_new = enc.fit_transform(transform_data).toarray() # 标志转换
df2_all = pd.concat((pd.DataFrame(id_data), pd.DataFrame(df2_new)), axis=1) # 组合为数据框
print (df2_all) # 打印输出转换后的数据框

该代码段按空行分为4个部分:
第一部分导入库, 本示例使用Pandas库和sklearn。
第二部分生成原始数据, 数据为3行3列的数据框, 分别包含id、 sex和level列, 其中的id为模拟的用户ID, sex为用户性别(英文) , level为用户等级(分别用high、 middle和low代表三个等级) 。 该段代码输出原始数据框如下:

id level sex
0 3566841 high male
1 6541227 low Female
2 3512441 middle Female

虽然在Python中可以通过一定的方法来处理中文, 但鉴于我
们用到的库基本都是外国人开发, 对中文的支持不太好, 所以不建议在程序中直接使用中文进行计算和建模, 除非是基于文本的自然语言和文本挖掘等直接面向中文的主题建模。
第三部分为自定义转换主过程。
步骤1 创建数据框副本。 通过copy() 方法创建一个原始数据库的副本, 用来存储转换后的数据。 该步骤不能省略, 原因是新的副本数据框和原始数据框在下面的步骤都要用到。
步骤2 通过循环获得原始数据框的列索引和列名。 在for循环中使
用enumerate() 方法, 返回可供迭代的列索引和列名。 然后获得每列数据和对应的dtype数据类型, 用来做是否进行标志转换的条件判断。 在if表达式中, 当数据类型为object时进行转换, 转换的核心思路如下:
1) 通过drop() 方法删除复制得到的数据框中要进行转换的列,并将结果赋值给df_new, 这样每次df_new中就会通过循环不断删除要转换的列, 避免数据重复。 drop方法的第一个参数是要删除的列名, 第二个参数是指定要删除的轴, 1表示按列删除。
2) 通过unique() 方法获取分类和顺序变量的唯一值域, 后续的判断主要针对值域列表进行。
3) 通过for循环遍历得到值域中的每个值。 通过“原始列名称+值”的形式新建一个列名, 这样得到的新列名能保留原始列的含义; 由于df_new通过不断循环其本身的索引已经改变, 因此需要使用iloc() 方法获得原始数据框的列; 通过将原始数据列与值域列表中的每个值进行比较, 相同为True, 否则为False, 并将值赋值到df_new结果数据框中。
4) 最后打印输出结果数据框。
上述代码执行后得到的结果如下:

id level_high level_low level_middle sex_male sex_Female
0 3566841 True False False True False
1 6541227 False True False False True
2 3512441 False False True False True

结果数据框中的True和False可以参与后续数据建模和距离计算中,True的值是1而False的值为0。
第四部分为使用klearn.preprocessing中的OneHotEncoder方法进行标志转换。
步骤1 创建模拟数据。 数据为3行3列的数据框。
很多情况下, 原始数据都不会以字符串( 第一种方法中的示例) 的形式存储, 而是将数据转换为数字进行存储, 这些数字可通过维度表匹配出对应的字符串。 当然, 如果是这种数据存储方法, 第一种自定义转换过程也可以实现, 但需要改变对于分类或顺序数据的识别规则, 此时的数据类型就不是object, 需要根据实际情况通过指定列名等方法转换。
步骤2 获得ID列并指定要转换的列。 获得ID列的目的是用于后续
对ID列和转换后的列做拼接, 便于数据格式的还原和对照。 如果不需要做多个方法的对比或对转换后的数据列不作判别应用, 则可以跳过本步骤, 以及步骤4中的拼接过程。
步骤3 建立模型对象并进行转换输出。 该过程中, 主要使用的是OneHotEncoder库中的fit_transform方法直接训练并应用转换, 然后使用toarray方法输出为矩阵。 如果不使用toarray进行转换, 那么输出的数据是一个3行5列的稀疏矩阵。
步骤4 将ID列和转换后的列拼接为完整主体, 用于跟原始数据和
通过方法1得到的数据做比较。

4.不处理

在数据预处理阶段, 对于具有缺失值的数据记录不做任何处理, 也是一种思路。 这种思路主要看后期的数据分析和建模应用, 很多模型对于缺失值有容忍度或灵活的处理方法, 因此在预处理阶段可以不做处理。 常见的能够自动处理缺失值的模型包括: KNN、 决策树和随机森林、 神经网络和朴素贝叶斯、 DBSCAN(基于密度的带有噪声的空间聚类) 等。 这些模型对于缺失值的处理思路是:
·忽略, 缺失值不参与距离计算, 例如KNN。
·将缺失值作为分布的一种状态, 并参与到建模过程, 例如各种决
策树及其变体。
·不基于距离做计算, 因此基于值的距离做计算, 本身的影响就消
除, 例如DBSCAN。

  • 24
    点赞
  • 227
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值