机器学习基础:缺失值的处理技巧(附Python代码)
在数据分析和建模中,经常会遇到变量值缺失的情况,这是非常常见的。为了保证数据指标的完整性以及可利用性,通常我们会采取特殊的方式对其进行处理。
1、缺失查看
首先,需要查看缺失值的缺失数量以及比例(#数据使用的kaggle平台上预测房价的数据)
import pandas as pd
# 统计缺失值数量missing=data.isnull().sum().reset_index().rename(columns={0:'missNum'})# 计算缺失比例missing['missRate']=missing['missNum']/data.shape[0]# 按照缺失率排序显示miss_analy=missing[missing.missRate>0].sort_values(by='missRate',ascending=False)# miss_analy 存储的是每个变量缺失情况的数据框
柱形图可视化
import matplotlib.pyplot as pltimport pylab as pl
fig = plt.figure(figsize=(18,6))plt.bar(np.arange(miss_analy.shape[0]), list(miss_analy.missRate.values), align = 'center',color=['red','green','yellow','steelblue'])
plt.title('Histogram of missing value of variables')plt.xlabel('variables names')plt.ylabel('missing rate')# 添加x轴标签,并旋转90度plt.xticks(np.arange(miss_analy.shape[0]),list(miss_analy['index']))pl.xticks(rotation=90)# 添加数值显示for x,y in enumerate(list(miss_analy.missRate.values)): plt.text(x,y+0.12,'{:.2%}'.format(y),ha='center',rotation=90) plt.ylim([0,1.2])
plt.show()
这样的统计计算以及可视化基本已经看出哪些变量缺失,以及缺失比例情况,对数据即有个缺失概况。下面将对缺失变量进行相应处理。
2、缺失处理
方式1:删除
直接去除含有缺失值的记录,这种处理方式是简单粗暴的,适用于数据量较大(记录较多)且缺失比较较小的情形,去掉后对总体影响不大。一般不建议这样做,因为很可能会造成数据丢失、数据偏移。
func: df.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
# 1、删除‘age’列df.drop('age', axis=1, inplace=True)
# 2、删除数据表中含有空值的行df.dropna()
# 3、丢弃某几列有缺失值的行df.dropna(axis=0, subset=['a','b'], inplace=True)
直接去除缺失变量,基于第一步我们已经知道每个变量的缺失比例,如果一个变量的缺失比例过高,基本也就失去了预测意义,这样的变量我们可以尝试把它直接去掉。
# 去掉缺失比例大于80%以上的变量data=data.dropna(thresh=len(data)*0.2, axis=1)
方式2:常量填充
在进行缺失值填充之前,我们要先对缺失的变量进行业务上的了解,即变量的含义、获取方式、计算逻辑,以便知道该变量为什么会出现缺失值、缺失值代表什么含义。比如,‘age’ 年龄缺失,每个人均有年龄,缺失应该为随机的缺失,‘loanNum’贷款笔数,缺失可能代表无贷款,是有实在意义的缺失。
全局常量填充:可以用0,均值、中位数、众数等填充。
平均值适用于近似正态分布数据,观测值较为均匀散布均值周围;中位数适用于偏态分布或者有离群点数据,中位数是更好地代表数据中心趋势;众数一般用于类别变量,无大小、先后顺序之分。
# 均值填充data['col'] = data['col'].fillna(data['col'].means())# 中位数填充data['col'] = data['col'].fillna(data['col'].median())# 众数填充data['col'] = data['col'].fillna(stats.mode(data['col'])[0][0])
也可以借助Imputer类处理缺失:
from sklearn.preprocessing import Imputerimr = Imputer(missing_values='NaN', strategy='mean', axis=0)imputed_data =pd.DataFrame(imr.fit_transform(df.values),columns=df.columns)imputed_data
方式3:插值填充
采用某种插入模式进行填充,比如取缺失值前后值的均值进行填充:
# interpolate()插值法,缺失值前后数值的均值,但是若缺失值前后也存在缺失,则不进行计算插补。df['a'] = df['a'].interpolate()
# 用前面的值替换, 当第一行有缺失值时,该行利用向前替换无值可取,仍缺失df.fillna(method='pad')
# 用后面的值替换,当最后一行有缺失值时,该行利用向后替换无值可取,仍缺失df.fillna(method='backfill')#用后面的值替换
方式4:KNN填充
利用knn算法填充,其实是把目标列当做目标标量,利用非缺失的数据进行knn算法拟合,最后对目标列缺失进行预测。(对于连续特征一般是加权平均,对于离散特征一般是加权投票)
fancyimpute 类
from fancyimpute import KNNfill_knn = KNN(k=3).fit_transform(data)data = pd.DataFrame(fill_knn)
sklearn类
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
def knn_filled_func(x_train, y_train, test, k = 3, dispersed = True): # params: x_train 为目标列不含缺失值的数据(不包括目标列) # params: y_train 为不含缺失值的目标列 # params: test 为目标列为缺失值的数据(不包括目标列) if dispersed: knn= KNeighborsClassifier(n_neighbors = k, weights = "distance") else: knn= KNeighborsRegressor(n_neighbors = k, weights = "distance")
knn.fit(x_train, y_train) return test.index, knn.predict(test)
方式5:随机森林填充
随机森林算法填充的思想和knn填充是类似的,即利用已有数据拟合模型,对缺失变量进行预测。
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
def knn_filled_func(x_train, y_train, test, k = 3, dispersed = True): # params: x_train 为目标列不含缺失值的数据(不包括目标列) # params: y_train 为不含缺失值的目标列 # params: test 为目标列为缺失值的数据(不包括目标列) if dispersed: rf= RandomForestRegressor() else: rf= RandomForestClassifier()
rf.fit(x_train, y_train) return test.index, rf.predict(test)
3、缺失衍生
有时候,可以根据某个字段是否缺失,进行新变量的衍生,比如,"信用卡数量",若该字段缺失,代表'无信用卡',则可以根据"信用卡数量"是否缺失衍生'有无信用卡'字段,这种衍生很可能是很有效果的。
4、总结
总之,处理缺失值是需要研究数据规律与缺失情况来进行处理的,复杂的算法不一定有好的效果,因此,还要具体问题具体分析,尤其是要搞明白字段含义以及缺失意义,这往往容易被忽略。个人经验,数据处理需要去探索,没有一成不变的万全之策。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- CSP
- Saltstack_使用指南07_远程执行-执行模块
- 学习从拥有一支好笔开始
- Saltstack_使用指南08_远程执行-返回程序
- 人生苦短,何不用vim装13
- Saltstack_使用指南09_远程执行-编写执行模块
- 如何安装FreeIPA
- 编译及使用hive-testbench生成Hive基准测试数据
- 树酱的前端知识体系构建(下)
- Babel配置傻傻看不懂?
- Saltstack_使用指南10_配置管理-状态模块
- Saltstack_使用指南11_配置管理-状态之间依赖关系 4.1. 部署架构4.2. Apache和PHP的SLS【正向依赖】4.3. mariadb 的 SLS
- 前端工程化之CICD那点破事
- Saltstack_使用指南12_配置管理-jinja模板 4.1. 部署架构4.2. 本章涉及的 pillar 的信息4.3. 配置文件 httpd.conf 修改
- Saltstack_使用指南13_runner的job和manage与execution的saltutil 5.1. master执行5.2. 查看当前活动的jobs