机器学习中级课程 2.缺失值

机器学习中级教程

缺失值的发生,为现实数据集中的这一常见挑战做好准备。

在本教程中,您将学习三种处理缺失值的方法。然后,您将在真实数据集上比较这些方法的有效性。

正文

介绍

有许多方法可以导致数据丢失值。例如,

  • 两间卧室的房子不包括第三间卧室的价值
  • 被调查者可选择不分享其收入

大多数机器学习库(包括scikit-learn)在试图使用缺失值的数据构建模型时都会出错。因此,你需要选择以下策略之一。

三种方法

1) 一个简单的选项:删除缺少值的列

最简单的选项是删除缺少值的列。
删除
除非删除列中的大多数值都丢失了,否则使用这种方法,模型将失去对大量(可能有用的!)信息。作为一个极端的例子,考虑一个有10,000行的数据集,其中一个重要的列缺少一个条目。这种方法将完全删除该列!

2) 更好的选择:插补

插补用一些数字填充缺失的值。例如,我们可以填写每列的平均值。
插补
在大多数情况下,估算值并不完全正确,但它通常会得到比完全删除列更准确的模型。

3) 插补的扩展

插补是标准方法,通常效果良好。然而,估算值可能系统地高于或低于实际值(数据集中未收集到实际值)。或者,缺少值的行在其他方面可能是唯一的。在这种情况下,您的模型可以通过考虑最初缺少的值来做出更好的预测。
extend
在这种方法中,我们像以前一样对缺失的值进行插补。此外,对于原始数据集中缺少条目的每一列,我们添加一个新列,显示插补条目的位置。
在某些情况下,这将有意义地改善结果。在其他情况下,这根本没有帮助。

举个例子

在本例中,我们将使用墨尔本住房数据集。我们的模型将使用房间数量和土地面积等信息来预测房价。
我们将不关注数据加载步骤。相反,相反,可以想象您已经拥有训练集和验证集(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)
方法1的得分(删除缺少值的列)

因为我们同时使用训练集和验证集,所以我们会小心地在两个数据帧中删除相同的列。

# 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

方法2的得分(插补)

接下来,我们使用 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

我们看到,方法2的MAE低于方法1,因此方法2在该数据集上表现更好。

方法3的得分(插补的扩展)

接下来,我们对缺失的值进行插补,同时跟踪插补的值。

# 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

我们可以看到,方法3的表现比方法2稍差。

那么,为什么插补比删除列表现更好呢?

训练数据有10864行和12列,其中三列包含缺少的数据。对于每一列,缺少的条目不到一半。因此,删除列会删除很多有用的信息,因此插补的效果会更好。

# 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
'''

结论

与我们简单地删除缺失值的列(在方法1中)相比,通常情况下,填充缺失值(在方法2和方法3中)会产生更好的结果。

轮到你了

在本练习中,自己比较这些方法来处理缺失的价值观!


练习部分

现在轮到你测试关于缺失值处理的新知识了。你可能会发现这有很大的不同。

设置

下面的问题将为你的工作提供反馈。运行以下单元格设置反馈系统。

# Set up code checking
import os
if not os.path.exists("../input/train.csv"):
    os.symlink("../input/home-data-for-ml-course/train.csv", "../input/train.csv")  
    os.symlink("../input/home-data-for-ml-course/test.csv", "../input/test.csv") 
from learntools.core import binder
binder.bind(globals())
from learntools.ml_intermediate.ex2 import *
print("Setup Complete")

Setup Complete

在本练习中,您将使用 Housing Prices Competition for Kaggle Learn Users 案例.

banner

在不做任何更改的情况下运行以下代码单元,以加载X_train、X_valid、y_train和y_valid中的训练集和验证集。测试集在X_test中加载。

import pandas as pd
from sklearn.model_selection import train_test_split

# 读取数据
X_full = pd.read_csv('../input/train.csv', index_col='Id')
X_test_full = pd.read_csv('../input/test.csv', index_col='Id')

# 删除目标值缺失的行,从预测中分享目标
# Remove rows with missing target, separate target from predictors
X_full.dropna(axis=0, subset=['SalePrice'], inplace=True)
y = X_full.SalePrice
X_full.drop(['SalePrice'], axis=1, inplace=True)

# 为简单,只保留数值型变量
X = X_full.select_dtypes(exclude=['object'])
X_test = X_test_full.select_dtypes(exclude=['object'])

# 从培训集中分离出验证数据
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2,
                                                      random_state=0)

使用以下代码打印数据的前五行。查看数据各列的情况

X_train.head()

缺失值
您已经可以在前几行中看到一些缺失的值。在下一步中,您将更全面地了解数据集中缺少的值。

第1步:初步调查

运行下面的代码格,不做任何更改。

# 查看训练集结构,即(行,列) Shape of training data (num_rows, num_columns)
print(X_train.shape)

# 查看训练集各列中缺失值数量
missing_val_count_by_column = (X_train.isnull().sum())
print(missing_val_count_by_column[missing_val_count_by_column > 0])

(1168, 36)
LotFrontage 212
MasVnrArea 6
GarageYrBlt 58
dtype: int64

A 部分

以上输出回答以下问题。

# 填写以下行:培训数据中有多少行有缺失值?
num_rows = ____

#填写以下行:训练集中有多少列
num_cols_with_missing = ____

#填写以下行:所有的训练数据表格中包含多少缺失条目?
tot_missing = ____

# Check your answers
step_1.a.check()
B 部分

考虑到你以上的答案,你认为处理缺失值的最佳方法是什么?

由于数据中缺少的条目相对较少(缺失值百分比最大的列缺少的条目不到其条目的20%),我们可以预期删除列不太可能产生好的结果。这是因为我们会扔掉很多有价值的数据,因此插补可能会表现得更好。

为了比较处理缺失值的不同方法,您将使用教程中相同的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=100, random_state=0)
    model.fit(X_train, y_train)
    preds = model.predict(X_valid)
    return mean_absolute_error(y_valid, preds)

第2步:删除缺失值的列

在这一步中,您将预处理X_train和X_valid中的数据,以删除缺失值的列。将预处理的数据集分别设置为 reduced_X_train和reduced_X_valid。

#填写以下行:获取缺失值的列的名称
____ #你的代码在这里

# 填写以下行:在训练和验证数据中删除列
# Fill in the lines below: drop columns in training and validation data
reduced_X_train = ____
reduced_X_valid = ____

# Check your answers
step_2.check()

在不做任何更改的情况下运行以下代码,以获取此方法的MAE。

print("MAE (Drop columns with missing values):")
print(score_dataset(reduced_X_train, reduced_X_valid, y_train, y_valid))

MAE (Drop columns with missing values):
17837.82570776256

第3步:插补

A 部分

使用下一个代码单元格,用每列的平均值填充缺失值。将预处理的数据帧设置为 imputed_X_train和imputed_X_valid。确保列名与X_train和X_valid中的列名匹配。

from sklearn.impute import SimpleImputer

# 在以下行填写:插补 Fill in the lines below: imputation
____ # 你的代码
imputed_X_train = ____
imputed_X_valid = ____

# Fill in the lines below: imputation removed column names; put them back
imputed_X_train.columns = ____
imputed_X_valid.columns = ____

# Check your answers
step_3.a.check()

检查:当您更新启动程序代码时,Check() 会告诉您代码是否正确。您需要更新创建变量imputed_X_train,imputed_X_valid的代码
在不做任何更改的情况下运行下一个代码单元,以获取此方法的MAE。

print("MAE (Imputation):")
print(score_dataset(imputed_X_train, imputed_X_valid, y_train, y_valid))

MAE (Imputation):
18062.894611872147

B 部分

比较每种方法的MAE。结果有什么让你惊讶的吗?为什么你认为一种方法比另一种更好?

第四步:生成测试预测

在最后一步中,您将使用您选择的任何方法来处理缺少的值。在预处理了训练和验证功能之后,您将训练和评估一个随机森林模型。然后,在生成可提交给竞赛的预测之前,您将对测试数据进行预处理!

A 部分

使用以下代码单元预处理训练和验证数据。将预处理的数据集命名为final_X_train和final_X_valid。你可以在这里选择任何方法! 要将这些步骤标记为正确,只需确保以下情况:

  • 预处理的数据集具有相同的列数
  • 预处理的数据集没有缺失值,
  • 最终的X_train和y_train具有相同的行数,并且 final_X_valid和y_valid的行数也相同。

总之一句话,训练集和验证集的数据没有缺失值,并具有相同的结构,即有相同的列(特征)。

# 预处理 训练集和验证集的特征
final_X_train = ____
final_X_valid = ____

# Check your answers
step_4.a.check()

运行以下代码单元来训练和评估随机森林模型。(请注意,我们不使用上面的 score_dataset() 函数,因为我们很快就会使用经过训练的模型来生成测试预测!)

# Define and fit model
# 定义和拟合模型
model = RandomForestRegressor(n_estimators=100, random_state=0)
model.fit(final_X_train, y_train)

# Get validation predictions and MAE
# 获得验证数据的预测值和 MAE
preds_valid = model.predict(final_X_valid)
print("MAE (Your approach):")
print(mean_absolute_error(y_valid, preds_valid))

MAE (Your approach):
17791.59899543379

B 部分

使用下一个代码单元预处理测试数据。确保使用的方法与预处理培训和验证数据的方式一致,并将预处理的测试功能命名为final_X_test。
然后,使用预处理的测试特征和经训练后的模型在 preds_test中生成测试预测值。
为了将此步骤能正常运行,您只需确保:

  • 预处理的测试数据帧没有缺失值,并且
  • final_X_test 的行数与X_test的行数相同。

需要测试的数据也相同的处理,得到与 A 部分 相同的列(特征),相同不改变原来测试集的行数。

# Fill in the line below: preprocess test data
# 填写以下行:处理测试集数据
final_X_test = ____

# Fill in the line below: get test predictions
# 填写以下行:获得测试集的预测值
preds_test = ____

# Check your answers
step_4.b.check()

运行下一个代码单元,不做任何更改,将结果保存到CSV文件中,该文件可以直接提交给竞赛。

提交你的结果

一旦成功完成第4步后,您就可以将结果提交到排行榜了!(在上一个练习中,您还学习了如何执行此操作。如果您需要如何执行此操作的提示,请使用以下说明。)
首先,如果你还没有参加比赛,你需要参加。所以点击这个链接打开一个新窗口。然后点击“加入竞争”按钮。
题目

接下来,按照以下说明操作:

  • 首先单击窗口右上角的“保存版本”按钮。这将生成一个弹出窗口。
  • 确保选择了“全部保存并运行”选项,然后单击“保存”按钮。
  • 这将在笔记本的左下角生成一个窗口。完成运行后,单击“保存版本”按钮右侧的数字。这会在屏幕右侧显示一个版本列表。点击省略号(…)在最新版本的右侧,选择“在查看器中打开”。这将使您进入同一页面的查看模式。您需要向下滚动才能返回这些说明。
  • 单击屏幕右侧的“输出”选项卡。然后,点击你想提交的文件,点击提交按钮,将结果提交到排行榜。

您现在已成功提交竞赛!

如果您想继续工作以提高性能,请选择屏幕右上角的编辑按钮。然后您可以更改代码并重复该过程。还有很大的改进空间,你将在工作中登上排行榜。

答案

### step 1
# How many rows are in the training data?
num_rows = 1168

# How many columns in the training data have missing values?
num_cols_with_missing = 3

# How many missing entries are contained in all of the training data?
tot_missing = 212 + 6 + 58


# step 2
# 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)

# step 3
# 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

# step 4
# Imputation
final_imputer = SimpleImputer(strategy='median')
final_X_train = pd.DataFrame(final_imputer.fit_transform(X_train))
final_X_valid = pd.DataFrame(final_imputer.transform(X_valid))

# Imputation removed column names; put them back
final_X_train.columns = X_train.columns
final_X_valid.columns = X_valid.columns
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值