圣人曾说过:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
再好的模型,如果没有好的数据和特征质量,那训练出来的效果也不会有所提高。数据质量对于数据分析而言是至关重要的,有时候它的意义会在某种程度上会胜过模型算法。
https://blog.csdn.net/SeafyLiang/article/details/115671683
首先我们应该知道:**数据为什么缺失?**数据的缺失是我们无法避免的,可能的原因有很多种,博主总结有以下三大类:
在对缺失数据进行处理前,了解数据缺失的机制和形式是十分必要的。将数据集中不含缺失值的变量称为完全变量,数据集中含有缺失值的变量称为不完全变量。而从缺失的分布来将缺失可以分为完全随机缺失,随机缺失和完全非随机缺失。
直接去除含有缺失值的记录,这种处理方式是简单粗暴的,适用于数据量较大(记录较多)且缺失比较较小的情形,去掉后对总体影响不大。一般不建议这样做,因为很可能会造成数据丢失、数据偏移。
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)
在进行缺失值填充之前,我们要先对缺失的变量进行业务上的了解,即变量的含义、获取方式、计算逻辑,以便知道该变量为什么会出现缺失值、缺失值代表什么含义。比如,‘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 Imputer
imr = Imputer(missing_values='NaN', strategy='mean', axis=0)
imputed_data =pd.DataFrame(imr.fit_transform(df.values),columns=df.columns)
imputed_data
采用某种插入模式进行填充,比如取缺失值前后值的均值进行填充:
# interpolate()插值法,缺失值前后数值的均值,但是若缺失值前后也存在缺失,则不进行计算插补。
df['c'] = df['c'].interpolate()
# 用前面的值替换, 当第一行有缺失值时,该行利用向前替换无值可取,仍缺失
df.fillna(method='pad')
# 用后面的值替换,当最后一行有缺失值时,该行利用向后替换无值可取,仍缺失
df.fillna(method='backfill')#用后面的值替换
下述2个方式需要先处理数据
# 需要先对a列数据做插值填充,后续作为训练数据
df['a'] = df['a'].interpolate()
# 拆分空数据和非空数据
df_notnull = df[df.is_fill==0] # 非空数据
df_null = df[df.is_fill==1] # 空数据
x_train = df_notnull[['b', 'a']] # 训练数据x, a,b列
y_train = df_notnull['c'] # 训练数据y, c列(目标)
test = df_null[['b', 'a']] # 预测数据x, a,b列
利用knn算法填充,其实是把目标列当做目标标量,利用非缺失的数据进行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.astype('int'))
return test.index, knn.predict(test)
index,predict = knn_filled_func(x_train, y_train, test, 3, True)
随机森林算法填充的思想和knn填充是类似的,即利用已有数据拟合模型,对缺失变量进行预测。
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
def RandomForest_filled_func(x_train, y_train, test, dispersed = True):
# params: x_train 为目标列不含缺失值的数据(不包括目标列)
# params: y_train 为不含缺失值的目标列
# params: test 为目标列为缺失值的数据(不包括目标列)
if dispersed:
rf= RandomForestRegressor()
else:
rf= RandomForestClassifier()
rf.fit(x_train, y_train.astype('int'))
return test.index, rf.predict(test)
index,predict = RandomForest_filled_func(x_train, y_train, test, True)
预测完成后处理操作
# 填充预测值
df_null['c'] = predict
# 回填到原始数据中
df['c'] = df['c'].fillna(df_null[['c']].c)
df.info()
红色为填充数据,绿色为原始数据 上图为随机森林填充 下图为插值填充