在机器学习模型中,输入数据的质量对模型性能有着至关重要的影响。数据缺失是数据预处理中常见的问题,需要妥善处理。本文将探讨从基础到高级的不同数据缺失处理技术,并提供Python代码示例。
数据集中的数据缺失可能由多种原因造成,例如数据不可用、数据录入错误等。这些缺失的数据可能包含关键信息,对模型性能有影响,因此不能忽视。
首先探讨几种处理数据缺失的策略,包括不作任何改变、删除含有缺失值的行、以及在探索性数据分析(EDA)阶段可视化缺失数据的百分比。
某些基于树的模型,如Light GBM和XGBoost,能够处理NA值。可以尝试使用包含缺失数据的基线模型,并检查性能指标。
# 假设train和test是两个DataFrame
# 删除train和test中包含缺失值的行
train = train.dropna()
test = test.dropna()
如果含有缺失值的记录在整个数据集中占比较少,删除这些记录是可行的。否则,删除大量信息并不合理。
import pandas as pd
import matplotlib.pyplot as plt
# 计算train和test中每列的缺失值比例
ncounts = pd.DataFrame([train.isna().mean(), test.isna().mean()]).T
ncounts = ncounts.rename(columns={0: "train_missing", 1: "test_missing"})
ncounts.query("train_missing > 0").plot(kind="barh", figsize=(8, 5), title="缺失值百分比")
plt.show()
通过可视化,可以直观地看到哪些特征的缺失值较多,从而决定是否删除这些特征。
# 计算每条记录缺失特征的数量
tt["n_missing"] = tt[nacols].isna().sum(axis=1)
train["n_missing"] = train[nacols].isna().sum(axis=1)
test["n_missing"] = test[nacols].isna().sum(axis=1)
tt["n_missing"].value_counts().plot(kind="bar", title="每条记录缺失特征的数量")
通过分析每条记录缺失特征的数量,可以决定使用哪种插补技术,或者是否不使用任何插补。
可以用一个常数值替换缺失数据,例如,如果竞赛正在进行的年份是2022年,那么可以用2022年替换年份建造特征的缺失值。
# 用2022年替换年份建造特征的缺失值
train['year_built'] = train['year_built'].fillna(2022)
test['year_built'] = test['year_built'].fillna(2022)
另一种方法是用非空记录的特征均值替换缺失值。由于均值可能受到异常值的影响,也可以使用中位数或众数作为替换策略。
# 用均值、中位数替换缺失值
test['energy_star_rating'] = test['energy_star_rating'].fillna(test['energy_star_rating'].mean())
test['energy_star_rating'] = test['energy_star_rating'].fillna(test['energy_star_rating'].median())
还可以根据另一个特征的值来插补缺失值。例如,可以根据建筑类别来填充最大风速的缺失值。
Sklearn提供了一个简单的插补器,可以按照之前讨论的策略,用常数或平均值来插补缺失值。
from sklearn.impute import SimpleImputer
# 创建SimpleImputer对象
imptr = SimpleImputer(strategy="mean")
# 对训练集和测试集进行插补
tr_imp = imptr.fit_transform(train[FEATURES])
test_imp = imptr.transform(test[FEATURES])
根据用例,可以将策略替换为mean、mode、median或constant。
本文将探讨以下高级插补技术:
迭代插补器通过将每个特征建模为其他元素的函数来插补缺失值。
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# 创建迭代插补器对象
it_imputer = IterativeImputer(max_iter=10)
# 对数据进行插补
train_iterimp = it_imputer.fit_transform(X[FEATURES])
test_iterimp = it_imputer.transform(X_test[FEATURES])
迭代插补器使用贝叶斯岭算法。
KNN插补器基于K最近邻无监督聚类算法的原理,使用KNN来插补缺失值。
from sklearn.impute import KNNImputer
# 创建KNN插补器对象
imputer = KNNImputer(n_neighbors=2)
# 对数据进行插补
imputer.fit_transform(X)
n_neighbors参数指定用于插补的邻居数量。
# 克隆LGBM插补器的代码库
!git clone https://github.com/analokmaus/kuma_utils.git
import sys
sys.path.append("kuma_utils/")
from kuma_utils.preprocessing.imputer import LGBMImputer
# 创建LGBM插补器对象
lgbm_imtr = LGBMImputer(n_iter=100, verbose=True)
# 对训练集和测试集进行插补
train_lgbmimp = lgbm_imtr.fit_transform(train[FEATURES])
test_lgbmimp = lgbm_imtr.transform(test[FEATURES])