丢失值——中级机器学习 2/7
简介
有很多数据会产生丢失值,比如:
- 有两个卧室的房子就不会保留第三个卧室的数据。
- 问卷的调查对象可能选择不分享他的收入
大多数的机器学习库(包括scikit-learn)在使用含有丢失值的数据集训练模型时会报错。所以你需要使用下面的策略之一。
三大法宝
-
一个简单的选择:将含有丢失值的列删掉
-
更好的选择:填补
-
填补扩展
案例
- 案例中我们继续使用墨尔本房价数据集,我们的模型将使用诸如房间数、占地面积等信息来预测房价。
- 我们就跳过数据载入阶段了,代码前面都有。我们还是将数据集分为训练集和验证集:
X_train
X_valid
y_train
y_valid
。
定义一个函数来衡量通过每个手段训练的模型质量
- 我们将定义一个函数
score_dataset()
来评价不同处理手段。这个函数返回随机森林的平均绝对误差(MAE)。
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
# Function for comparing different approaches
def score_dataset(X_train, X_valid, y_train, y_valid):
model = RandomForestRegressor(n_estimators=10, random_state=0)
model.fit(X_train, y_train)
preds = model.predict(X_valid)
return mean_absolute_error(y_valid, preds)
方法一的得分(删掉含有丢失数据的列)
- 既然我们使用的是训练集和验证集,那就要注意将两个数据框架中的相同列删去。
# Get names of columns with missing values
cols_with_missing = [col for col in X_train.columns
if X_train[col].isnull().any()]
# Drop columns in training and validation data
reduced_X_train = X_train.drop(cols_with_missing, axis=1)
reduced_X_valid = X_valid.drop(cols_with_missing, axis=1)
print("MAE from Approach 1 (Drop columns with missing values):")
print(score_dataset(reduced_X_train, reduced_X_valid, y_train, y_valid))
MAE from Approach 1 (Drop columns with missing values):
183550.22137772635
方法二的得分:(填补)
- 下面,我们用
SimpleImputer
将各自列的平均值填入丢失值中 - 虽然看似简单,但是填入平均总体上效果比较好(但这个也是因数据集而异)。虽然统计学家使用更复杂的方法来填值(如回归填补法),但是这些复杂的策略往往在将结果输入复杂的机器学习模型时不会产生什么效益。
from sklearn.impute import SimpleImputer
# Imputation
my_imputer = SimpleImputer()
imputed_X_train = pd.DataFrame(my_imputer.fit_transform(X_train))
imputed_X_valid = pd.DataFrame(my_imputer.transform(X_valid))
# Imputation removed column names; put them back
imputed_X_train.columns = X_train.columns
imputed_X_valid.columns = X_valid.columns
print("MAE from Approach 2 (Imputation):")
print(score_dataset(imputed_X_train, imputed_X_valid, y_train, y_valid))
MAE from Approach 2 (Imputation):
178166.46269899711
- 我们可以看到方法二的MAE要比方法一的低,说明方法二的效果要好些。
方法三的得分(扩展填补) - 下面,我们既要填数据,还要记录填在哪里
# Make copy to avoid changing original data (when imputing)
X_train_plus = X_train.copy()
X_valid_plus = X_valid.copy()
# Make new columns indicating what will be imputed
for col in cols_with_missing:
X_train_plus[col + '_was_missing'] = X_train_plus[col].isnull()
X_valid_plus[col + '_was_missing'] = X_valid_plus[col].isnull()
# Imputation
my_imputer = SimpleImputer()
imputed_X_train_plus = pd.DataFrame(my_imputer.fit_transform(X_train_plus))
imputed_X_valid_plus = pd.DataFrame(my_imputer.transform(X_valid_plus))
# Imputation removed column names; put them back
imputed_X_train_plus.columns = X_train_plus.columns
imputed_X_valid_plus.columns = X_valid_plus.columns
print("MAE from Approach 3 (An Extension to Imputation):")
print(score_dataset(imputed_X_train_plus, imputed_X_valid_plus, y_train, y_valid))
MAE from Approach 3 (An Extension to Imputation):
178927.503183954
- 我们可以看到,方法三要比方法二表现稍差一些。
那么为什么填补法要比丢弃法表现好呢?
- 训练数据集有10864行,12列,其中有3列含有丢失值。每个列含有的丢失值都没超过数据行的一半。所以丢弃法要损失更多的有用信息,所以填补法表现好。
# Shape of training data (num_rows, num_columns)
print(X_train.shape)
# Number of missing values in each column of training data
missing_val_count_by_column = (X_train.isnull().sum())
print(missing_val_count_by_column[missing_val_count_by_column > 0])
(10864, 12)
Car 49
BuildingArea 5156
YearBuilt 4307
dtype: int64
结论
总的来说,填补丢失值(方法二、方法三)要比丢弃列的方法(方法一)获得更好的结果。