波士顿房价预测

96
MrMiaow
0.5 2018.02.01 17:50* 字数 8669

本内容为Udacity课程波士顿房价预测项目,欢迎阅读,有错的地方请留言。仅参考不建议作为其他用途。

优达学城毕业项目Github地址: Kaggle猫狗大战准确率Top 2%webapp部署 如果对你有帮助欢迎 Star 或者 Fork
机器学习深度学习面试题总结:机器学习深度学习面试题总结


第一步. 导入数据

在这个项目中,你将利用马萨诸塞州波士顿郊区的房屋信息数据训练和测试一个模型,并对模型的性能和预测能力进行测试。通过该数据训练后的好的模型可以被用来对房屋做特定预测---尤其是对房屋的价值。对于房地产经纪等人的日常工作来说,这样的预测模型被证明非常有价值。

此项目的数据集来自UCI机器学习知识库(数据集已下线)。波士顿房屋这些数据于1978年开始统计,共506个数据点,涵盖了麻省波士顿不同郊区房屋14种特征的信息。本项目对原始数据集做了以下处理:

  • 有16个'MEDV' 值为50.0的数据点被移除。 这很可能是由于这些数据点包含遗失看不到的值
  • 有1个数据点的 'RM' 值为8.78. 这是一个异常值,已经被移除。
  • 对于本项目,房屋的'RM''LSTAT''PTRATIO'以及'MEDV'特征是必要的,其余不相关特征已经被移除。
  • 'MEDV'特征的值已经过必要的数学转换,可以反映35年来市场的通货膨胀效应。

运行下面区域的代码以载入波士顿房屋数据集,以及一些此项目所需的Python库。如果成功返回数据集的大小,表示数据集已载入成功。

# 载入此项目所需要的库
import numpy as np
import pandas as pd
import visuals as vs # Supplementary code

# 检查你的Python版本
from sys import version_info
if version_info.major != 2 and version_info.minor != 7:
    raise Exception('请使用Python 2.7来完成此项目')
    
# 让结果在notebook中显示
%matplotlib inline
# 载入波士顿房屋的数据集
data = pd.read_csv('housing.csv')
prices = data['MEDV']
features = data.drop('MEDV', axis = 1)
    
# 完成
print "Boston housing dataset has {} data points with {} variables each.".format(*data.shape)
Boston housing dataset has 489 data points with 4 variables each.

第二步. 分析数据

在项目的第一个部分,你会对波士顿房地产数据进行初步的观察并给出你的分析。通过对数据的探索来熟悉数据可以让你更好地理解和解释你的结果。

由于这个项目的最终目标是建立一个预测房屋价值的模型,我们需要将数据集分为特征(features)目标变量(target variable)

  • 特征 'RM''LSTAT',和 'PTRATIO',给我们提供了每个数据点的数量相关的信息。
  • 目标变量'MEDV',是我们希望预测的变量。

他们分别被存在featuresprices两个变量名中。

编程练习 1:基础统计运算

你的第一个编程练习是计算有关波士顿房价的描述统计数据。我们已为你导入了numpy,你需要使用这个库来执行必要的计算。这些统计数据对于分析模型的预测结果非常重要的。
在下面的代码中,你要做的是:

  • 计算prices中的'MEDV'的最小值、最大值、均值、中值和标准差;
  • 将运算结果储存在相应的变量中。

std(标准差)在Numpy与Pandas中的不同

#TODO 1

#目标:计算价值的最小值
minimum_price = np.min(prices)

#目标:计算价值的最大值
maximum_price = np.max(prices)

#目标:计算价值的平均值
mean_price = np.mean(prices)

#目标:计算价值的中值
median_price = np.median(prices)

#目标:计算价值的标准差
std_price = np.std(prices)

#目标:输出计算的结果
print "Statistics for Boston housing dataset:\n"
print "Minimum price: ${:,.2f}".format(minimum_price)
print "Maximum price: ${:,.2f}".format(maximum_price)
print "Mean price: ${:,.2f}".format(mean_price)
print "Median price ${:,.2f}".format(median_price)
print "Standard deviation of prices: ${:,.2f}".format(std_price)
Statistics for Boston housing dataset:

Minimum price: $105,000.00
Maximum price: $1,024,800.00
Mean price: $454,342.94
Median price $438,900.00
Standard deviation of prices: $165,171.13

问题 1 - 特征观察

如前文所述,本项目中我们关注的是其中三个值:'RM''LSTAT''PTRATIO',对每一个数据点:

  • 'RM' 是该地区中每个房屋的平均房间数量;
  • 'LSTAT' 是指该地区有多少百分比的业主属于是低收入阶层(有工作但收入微薄);
  • 'PTRATIO' 是该地区的中学和小学里,学生和老师的数目比(学生/老师)。

凭直觉,上述三个特征中对每一个来说,你认为增大该特征的数值,'MEDV'的值会是增大还是减小呢?每一个答案都需要你给出理由。

提示:你预期一个'RM' 值是6的房屋跟'RM' 值是7的房屋相比,价值更高还是更低呢?

问题 1 - 回答:

# 载入画图所需要的库 matplotlib
import matplotlib.pyplot as plt

# 使输出的图像以更高清的方式显示
%config InlineBackend.figure_format = 'retina'

# 调整图像的宽高
plt.figure(figsize=(16, 4))
for i, key in enumerate(['RM', 'LSTAT', 'PTRATIO']):
    plt.subplot(1, 3, i+1)
    plt.xlabel(key)
    plt.scatter(data[key], data['MEDV'], alpha=0.5)

对以上三个特征预期估计:

  1. 增大 'RM' 值,'MEDV' 的值会增大。一般房间数多的房屋面积要大一些,所以价格会比房间数小的房屋贵

  2. 增大 'LSTAT' 值,'MEDV' 的值会减小。如果低收入阶层比率越大相对购买贵的房屋的能力就可能会下降

  3. 增大 'PTRATIO' 值,'MEDV' 的值会增大。'PTRATIO' 为学生和老师的数目比,如果 'PTRATIO' 增大说明当地对学生教育投入很大,为了孩子教育这样可能会吸引更多的家长在该地区购买房屋,供应量达不到需求量的时候房屋价格上涨是正常的

从上图中我们可以看出,虽然 'PTRATIO' 与 'MEDV' 没有像 'RM'、'LSTAT'那么强的相关性,但是更倾向于 'PTRATIO' 增大 'MEDV' 减小,可能的原因是在美国较好的学校会有低的学生老师比,这也是教育资源和教学质量的保证

编程练习 2: 数据分割与重排

接下来,你需要把波士顿房屋数据集分成训练和测试两个子集。通常在这个过程中,数据也会被重排列,以消除数据集中由于顺序而产生的偏差。
在下面的代码中,你需要

使用 sklearn.model_selection 中的 train_test_split, 将featuresprices的数据都分成用于训练的数据子集和用于测试的数据子集。

  • 分割比例为:80%的数据用于训练,20%用于测试;
  • 选定一个数值以设定 train_test_split 中的 random_state ,这会确保结果的一致性;
# TODO 2

# 提示: 导入train_test_split
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(features, prices, test_size=0.2, random_state=1)

问题 2 - 训练及测试

将数据集按一定比例分为训练用的数据集和测试用的数据集对学习算法有什么好处?

如果用模型已经见过的数据,例如部分训练集数据进行测试,又有什么坏处?

提示: 如果没有数据来对模型进行测试,会出现什么问题?

问题 2 - 回答:

训练集(train set)、 验证集(validation set) 、测试集(test set)

  1. 将数据集按照一定比例分为训练集和测试集的好处是:训练集用来估计模型,测试集检验最终选择最优模型的性能如何

  2. 用部分见过的数据测试不能很好的体现模型的准确性,测试模型目的是为了验证由训练集构建的模型的合理性、表现如何。模型拟合训练使用的是训练集数据,所得到的模型也是依赖训练集数据而构建的,如果再用部分训练集数据进行测试,则结果不具有代表性,不能很好的得到我们预期的结果。

review: 机器学习的核心目的就是构建具有泛化能力的模型,如果没有测试集,或者用模型已经见过的数据来测试,都无法确切知道模型对预测未知数据的表现如何,也就无法衡量模型表现。


第三步. 模型衡量标准

在项目的第三步中,你需要了解必要的工具和技巧来让你的模型进行预测。用这些工具和技巧对每一个模型的表现做精确的衡量可以极大地增强你预测的信心。

编程练习3:定义衡量标准

如果不能对模型的训练和测试的表现进行量化地评估,我们就很难衡量模型的好坏。通常我们会定义一些衡量标准,这些标准可以通过对某些误差或者拟合程度的计算来得到。在这个项目中,你将通过运算决定系数 R2 来量化模型的表现。模型的决定系数是回归分析中十分常用的统计信息,经常被当作衡量模型预测能力好坏的标准。

R2的数值范围从0至1,表示目标变量的预测值和实际值之间的相关程度平方的百分比。一个模型的R2 值为0还不如直接用平均值来预测效果好;而一个R2 值为1的模型则可以对目标变量进行完美的预测。从0至1之间的数值,则表示该模型中目标变量中有百分之多少能够用特征来解释。模型也可能出现负值的R2,这种情况下模型所做预测有时会比直接计算目标变量的平均值差很多。

在下方代码的 performance_metric 函数中,你要实现:

  • 使用 sklearn.metrics 中的 r2_score 来计算 y_truey_predict的R2值,作为对其表现的评判。
  • 将他们的表现评分储存到score变量中。

  • (可选) 不使用任何外部库,参考决定系数的定义进行计算,这也可以帮助你更好的理解决定系数在什么情况下等于0或等于1。
# TODO 3

# 提示: 导入r2_score
from sklearn.metrics import r2_score

def performance_metric(y_true, y_predict):
    """计算并返回预测值相比于预测值的分数"""
    
    score = r2_score(y_true, y_predict)

    return score
# TODO 3 可选

# 不允许导入任何计算决定系数的库

def performance_metric2(y_true, y_predict):
    """计算并返回预测值相比于预测值的分数"""
    y_true = np.array(y_true)
    y_predict = np.array(y_predict)
    
    score = 1 - np.divide(sum([np.square(x[0] - x[1]) for x in zip(y_true, y_predict)]),
                          sum([np.square(x - np.mean(y_true)) for x in y_true]))

    return score

问题 3 - 拟合程度

假设一个数据集有五个数据且一个模型做出下列目标变量的预测:

真实数值 预测数值
3.0 2.5
-0.5 0.0
2.0 2.1
7.0 7.8
4.2 5.3

你觉得这个模型已成功地描述了目标变量的变化吗?如果成功,请解释为什么,如果没有,也请给出原因。

提示:运行下方的代码,使用performance_metric函数来计算模型的决定系数。

# 计算这个模型的预测结果的决定系数
score = performance_metric([3, -0.5, 2, 7, 4.2], [2.5, 0.0, 2.1, 7.8, 5.3])
print "Model has a coefficient of determination, R^2, of {:.3f}.".format(score)
Model has a coefficient of determination, R^2, of 0.923.

问题 3 - 回答:

  1. 从上边的运算结果来看 R^2 值为 0.923 已经很接近 1 ,这个结果可以说是比较成功的描述了目标变量的变化。

review: R^2 是评价模型表现的方法之一,每个机器学习模型的建立都要有相对应的评价指标,后面我们会学到更多的评价指标。不过 R^2 其实也有很多局限性需要注意

可汗学院对此也有很精彩的讲解

skearn 对于常见的模型表现衡量方法也有详细的介绍


第四步. 分析模型的表现

在项目的第四步,我们来看一下不同参数下,模型在训练集和验证集上的表现。这里,我们专注于一个特定的算法(带剪枝的决策树,但这并不是这个项目的重点),和这个算法的一个参数 'max_depth'。用全部训练集训练,选择不同'max_depth' 参数,观察这一参数的变化如何影响模型的表现。画出模型的表现来对于分析过程十分有益,这可以让我们看到一些单看结果看不到的行为。

学习曲线

下方区域内的代码会输出四幅图像,它们是一个决策树模型在不同最大深度下的表现。每一条曲线都直观得显示了随着训练数据量的增加,模型学习曲线的在训练集评分和验证集评分的变化,评分使用决定系数R2。曲线的阴影区域代表的是该曲线的不确定性(用标准差衡量)。

运行下方区域中的代码,并利用输出的图形回答下面的问题。

# 根据不同的训练集大小,和最大深度,生成学习曲线
vs.ModelLearning(X_train, y_train)

问题 4 - 学习曲线

选择上述图像中的其中一个,并给出其最大深度。随着训练数据量的增加,训练集曲线的评分有怎样的变化?验证集曲线呢?如果有更多的训练数据,是否能有效提升模型的表现呢?

提示:学习曲线的评分是否最终会收敛到特定的值?

问题 4 - 回答:

参考文献

  1. max_depth = 1 图:随着训练数据增加,在训练数据低于 50 的时候训练集曲线随数据增加下降的很快,验证集曲线随数据增加迅速上升,训练数据大于 50 的时候训练集曲线和验证集曲线下降和上升缓慢呈现收敛的状态,训练集数据达到 300 的时候训练集 R^2 分数和验证集 R^2 分数比较接近,训练集和验证集的分数收敛但是很低,为高偏差,很可能是欠拟合,此时通过增加数据量是不能有效提升模型表现

  2. max_depth = 10 图:随着训练数据增加,在训练数据低于 50 的时候训练集曲线变化不明显,验证集曲线随数据增加迅速上升,训练集数据大于 50 的时候,训练集曲线变化不明显,验证集曲线呈现缓慢上升。训练数据达到 300 的时候训练集 R^2 分数和验证集 R^2 分数相差太大,为高方差,一般是过拟合。增大训练集数据可以有效的提升模型的表现

  3. max_depth = 3 图:是比较理想的曲线,收敛且 R^2 分数很高

review 批注:在传统机器学习方法中,当模型学习到一定程度以后,增大训练数据是很难有提升的,但是在深度学习中往往是一种有效的方法。

review: 对训练曲线和测试曲线趋势和意义解释的很好。这里随着数据的增多,max_depth 不变的情况下,模型提升的幅度也越来越小。

这里还有更多关于学习曲线的介绍:

https://www.coursera.org/learn/machine-learning/lecture/Kont7/learning-curves

http://scikit-learn.org/stable/auto_examples/model_selection/plot_learning_curve.html

复杂度曲线

下列代码内的区域会输出一幅图像,它展示了一个已经经过训练和验证的决策树模型在不同最大深度条件下的表现。这个图形将包含两条曲线,一个是训练集的变化,一个是验证集的变化。跟学习曲线相似,阴影区域代表该曲线的不确定性,模型训练和测试部分的评分都用的 performance_metric 函数。

运行下方区域中的代码,并利用输出的图形并回答下面的两个问题。

# 根据不同的最大深度参数,生成复杂度曲线
vs.ModelComplexity(X_train, y_train)

问题 5 - 偏差(bias)与方差(variance)之间的权衡取舍

当模型以最大深度 1训练时,模型的预测是出现很大的偏差还是出现了很大的方差?当模型以最大深度10训练时,情形又如何呢?图形中的哪些特征能够支持你的结论?

提示: 你如何得知模型是否出现了偏差很大或者方差很大的问题?

问题 5 - 回答:

  1. 当模型以最大深度 1 训练时,模型的预测出现了很大的偏差,图中训练集 R^2 分数和验证集 R^2 分数在最大深度为 1 时的值可以说明,欠拟合,曲线收敛且分数值很低

  2. 当模型以最大深度 10 训练时,模型的预测出现了很大的方差,图中训练集 R^2 分数和验证集 R^2 分数在最大深度为 1 时的值可以说明,过拟合,曲线间的距离很大

review 批注:高偏差通常是由于模型太简单(即模型欠拟合),不能很好的拟合测试集,训练分数、验证分数、测试分数通常都比较低;高方差通常是由于模型过于复杂(即模型过拟合),模型在训练集上表现得很好,在验证集和测试集上得分确比较低,泛化能力差。

review: 借用西瓜书上的比喻,用机器学习来判断一个物体是不是树叶,underfitting 是以为所有绿色的都是树叶(没学会该学的);overfitting 是以为树叶都要有锯齿(学过头了,不该学的也学了进去)。这两者都不是我们想要的。

维基百科对此也有详细的解释 https://en.wikipedia.org/wiki/Bias%E2%80%93variance_tradeoff

华盛顿大学机器学习的课程详细讲了这个问题,你可以免费观看。 https://www.coursera.org/learn/ml-regression/home/week/3

sklearn 也有对 validation curve的介绍:http://scikit-learn.org/stable/modules/learning_curve.html

问题 6- 最优模型的猜测

结合问题 5 中的图,你认为最大深度是多少的模型能够最好地对未见过的数据进行预测?你得出这个答案的依据是什么?

问题 6 - 回答:

  1. 最大深度大概为 4 时,模型能够很好的对未见过的数据进行预测,因为在最大深度为 4 时,训练集曲线和验证集曲线收敛明显且两曲线对应的 R^2 分数较高

第五步. 选择最优参数

问题 7- 网格搜索(Grid Search)

什么是网格搜索法?如何用它来优化模型?

问题 7 - 回答:

网格搜索算法与K折交叉验证

【scikit-learn】网格搜索来进行高效的参数调优

网格搜索法是指定参数值的一种穷举搜索方法,通过将估计函数的参数通过交叉验证的方法进行优化来得到最优的学习算法。 即,将各个参数可能的取值进行排列组合,列出所有可能的组合结果生成“网格”。然后将各组合用于 SVM 训练,并使用交叉验证对表现进行评估。在拟合函数尝试了所有的参数组合后,返回一个合适的分类器,自动调整至最佳参数组合,可以通过 clf.best_params_ 获得参数值

网格搜索是根据给定的模型自动进行交叉验证,通过调节每一个参数来跟踪评分结果。

如果使用决策树训练模型,通常选择参数是决策树的最大深度,在定义最大深度的值时要尽可能的包含最优最大深度。

可以通过字典来提供分类器或回归器的类型对象。字典的键我们将要调整的参数,而字典的值就是需要尝试的参数值的相应列表。

以决策树为例:每个最大深度决策树验证分数使用交叉验证评估得到,然后对所有最大深度的决策树最终验证分数进行比较,分数最高的哪一个就是最优最大深度。

review: GridSearch就是把给定超参数下所有可能的组合都试一遍,通过指定的评价函数找出最优。

同时还要注意,这里的最优也是我们给定超参数范围,给定 Kfold(如果使用)的K下的最优。超参数空间变化和K取值的变化都会引起结果不同,所以即使是GridSearch,也无法保证是绝对最优。

问题 8 - 交叉验证

  • 什么是K折交叉验证法(k-fold cross-validation)?
  • GridSearchCV是如何结合交叉验证来完成对最佳参数组合的选择的?
  • GridSearchCV中的'cv_results_'属性能告诉我们什么?
  • 网格搜索时如果不使用交叉验证会有什么问题?交叉验证又是如何解决这个问题的?

提示: 在下面 fit_model函数最后加入 print pd.DataFrame(grid.cv_results_) 可以帮你查看更多信息。

问题 8 - 回答:

  • K 折交叉验证是将训练集的所有数据分为 K 份(通常选择 K = 10),取第 K 份作为验证集,验证集的作用是:确定网络结构或者控制模型复杂度的参数,剩下的 K-1 份作为交叉验证的训练集

  • GridSearchCV 对每一个参数组合进行一次 K 折交叉验证,得到对应的平均分数;最后选择平均分数最高的参数组合作为模型的最优参数组合,可通过 best_params_ 属性获得该参数组合

  • cv_results 属性返回一个字典,记录了每一组网格参数每一次训练/验证( K 折对应 K 次)对应的训练结果,包括训练/验证时间、训练/验证评估分数以及相关时间和评分的统计信息

  • 网格搜索不使用交叉验证,可以使训练速度更快,但可能难以得到最优的模型参数;交叉验证对每一个参数组合得出的评分更为准确和鲁棒,可以提高评估的稳定性

review: 对于网格搜索来说,使用交叉验证的评估结果更准确,因为不使用交叉验证,训练数据可以按一定比例分为训练集和验证集。我们可以用这个训练集训练不同(参数)的模型,在验证集上跑分。选出最佳参数组合。但这样只是这一次划分验证集上表现最好的参数,如果验证集不具代表性。就会影响模型在未知数据上的表现。而交叉验证很大程度上避免因样本划分不合理导致选择了错误的参数。

编程练习 4:训练最优模型

在这个练习中,你将需要将所学到的内容整合,使用决策树算法训练一个模型。为了得出的是一个最优模型,你需要使用网格搜索法训练模型,以找到最佳的 'max_depth' 参数。你可以把'max_depth' 参数理解为决策树算法在做出预测前,允许其对数据提出问题的数量。决策树是监督学习算法中的一种。

在下方 fit_model 函数中,你需要做的是:

  1. 定义 'cross_validator' 变量: 使用 sklearn.model_selection 中的 KFold 创建一个交叉验证生成器对象;
  2. 定义 'regressor' 变量: 使用 sklearn.tree 中的 DecisionTreeRegressor 创建一个决策树的回归函数;
  3. 定义 'params' 变量: 为 'max_depth' 参数创造一个字典,它的值是从1至10的数组;
  4. 定义 'scoring_fnc' 变量: 使用 sklearn.metrics 中的 make_scorer 创建一个评分函数;
    ‘performance_metric’ 作为参数传至这个函数中;
  5. 定义 'grid' 变量: 使用 sklearn.model_selection 中的 GridSearchCV 创建一个网格搜索对象;将变量'regressor', 'params', 'scoring_fnc''cross_validator' 作为参数传至这个对象构造函数中;

如果你对python函数的默认参数定义和传递不熟悉,可以参考这个MIT课程的视频

# TODO 4

#提示: 导入 'KFold' 'DecisionTreeRegressor' 'make_scorer' 'GridSearchCV' 
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV

def fit_model(X, y):
    """ 基于输入数据 [X,y],利于网格搜索找到最优的决策树模型"""
    
    cross_validator = KFold(n_splits=10, random_state=1, shuffle=True)
    
    regressor = DecisionTreeRegressor()

    params = { 'max_depth': range(1,11) }

    scoring_fnc = make_scorer(performance_metric)

    grid = GridSearchCV(regressor, params, scoring=scoring_fnc, cv=cross_validator)

    # 基于输入数据 [X,y],进行网格搜索
    grid = grid.fit(X, y)
    
    #print pd.DataFrame(grid.cv_results_)

    # 返回网格搜索后的最优模型
    return grid.best_estimator_

编程练习 4:训练最优模型 (可选)

在这个练习中,你将需要将所学到的内容整合,使用决策树算法训练一个模型。为了得出的是一个最优模型,你需要使用网格搜索法训练模型,以找到最佳的 'max_depth' 参数。你可以把'max_depth' 参数理解为决策树算法在做出预测前,允许其对数据提出问题的数量。决策树是监督学习算法中的一种。

在下方 fit_model 函数中,你需要做的是:

  • 遍历参数‘max_depth’的可选值 1~10,构造对应模型
  • 计算当前模型的交叉验证分数
  • 返回最优交叉验证分数对应的模型
# TODO 4 可选

'''
不允许使用 DecisionTreeRegressor 以外的任何 sklearn 库

提示: 你可能需要实现下面的 cross_val_score 函数

def cross_val_score(estimator, X, y, scoring = performance_metric, cv=3):
    """ 返回每组交叉验证的模型分数的数组 """
    scores = [0,0,0]
    return scores
'''

def fit_model2(X, y):
    """ 基于输入数据 [X,y],利于网格搜索找到最优的决策树模型"""
    
    #最优交叉验证分数对应的最优模型
    best_estimator = None
    
    return best_estimator

问题 9 - 最优模型

最优模型的最大深度(maximum depth)是多少?此答案与你在问题 6所做的猜测是否相同?

运行下方区域内的代码,将决策树回归函数代入训练数据的集合,以得到最优化的模型。

# 基于训练数据,获得最优模型
optimal_reg = fit_model(X_train, y_train)

# 输出最优模型的 'max_depth' 参数
print "Parameter 'max_depth' is {} for the optimal model.".format(optimal_reg.get_params()['max_depth'])
Parameter 'max_depth' is 4 for the optimal model.

问题 9 - 回答:

  1. 最优模型的最大深度为 4,与问题 6 中猜测相同

review: 这里返回的最佳参数的值,会随着 random_state 在 train_test_split, Kfold (如果设置shuffle=True) 和 DecisionTreeRegressor 中的取值变化而变化。要得到一致结果,每个随机数都需要设定。

第六步. 做出预测

当我们用数据训练出一个模型,它现在就可用于对新的数据进行预测。在决策树回归函数中,模型已经学会对新输入的数据提问,并返回对目标变量的预测值。你可以用这个预测来获取数据未知目标变量的信息,这些数据必须是不包含在训练数据之内的。

问题 10 - 预测销售价格

想像你是一个在波士顿地区的房屋经纪人,并期待使用此模型以帮助你的客户评估他们想出售的房屋。你已经从你的三个客户收集到以下的资讯:

特征 客戶 1 客戶 2 客戶 3
房屋内房间总数 5 间房间 4 间房间 8 间房间
社区贫困指数(%被认为是贫困阶层) 17% 32% 3%
邻近学校的学生-老师比例 15:1 22:1 12:1

你会建议每位客户的房屋销售的价格为多少?从房屋特征的数值判断,这样的价格合理吗?为什么?

提示:用你在分析数据部分计算出来的统计信息来帮助你证明你的答案。

运行下列的代码区域,使用你优化的模型来为每位客户的房屋价值做出预测。

# 生成三个客户的数据
client_data = [[5, 17, 15], # 客户 1
               [4, 32, 22], # 客户 2
               [8, 3, 12]]  # 客户 3

# 进行预测
predicted_price = optimal_reg.predict(client_data)
for i, price in enumerate(predicted_price):
    print "Predicted selling price for Client {}'s home: ${:,.2f}".format(i+1, price)
Predicted selling price for Client 1's home: $411,417.39
Predicted selling price for Client 2's home: $230,828.57
Predicted selling price for Client 3's home: $937,230.00

问题 10 - 回答:

  1. 建议客户 1 的房屋销售价格为:$411,417.39

  2. 建议客户 2 的房屋销售价格为:$230,828.57

  3. 建议客户 3 的房屋销售价格为:$937,230.00

  4. 根据三位客户的房屋特征来分析:

    客户 3 的房间数为 8,房间最多,且社区的贫困指数在三位客户中最低,说明购买房屋的能力高,学生老师的比例小,可以说明当地对教育的投入较大。所以价格高于其他两位客户是正常的。根据问题 1 中的预测可以说明符合预期预测

    客户 2 的房屋特征与其他两位客户房屋特征相比,房间数最少,且社区贫困指数最大,学生老师的比例最大,所以房屋价低于其他两位客户是正常的。

    客户 1 的房屋特征介于客户 2 和客户 3 之间,所以房屋价格介于客户2 房屋价格和客户 3 房屋价格之间是正常的

review: 这里我们可以根据房子的特征来做横向比较;也可以与数据集中特征相近的房子做纵向比较。最终还可以跟统计数据中的最大值,最小值,均值等做比较。

编程练习 5

你刚刚预测了三个客户的房子的售价。在这个练习中,你将用你的最优模型在整个测试数据上进行预测, 并计算相对于目标变量的决定系数 R2的值**。

#TODO 5

# 提示:你可能需要用到 X_test, y_test, optimal_reg, performance_metric
# 提示:你可能需要参考问题10的代码进行预测
# 提示:你可能需要参考问题3的代码来计算R^2的值

predicted_price = optimal_reg.predict(X_test)

r2 = performance_metric(y_test, predicted_price)

print "Optimal model has R^2 score {:,.2f} on test data".format(r2)
Optimal model has R^2 score 0.78 on test data

问题11 - 分析决定系数

你刚刚计算了最优模型在测试集上的决定系数,你会如何评价这个结果?

问题11 - 回答

决定系数

  1. 此模型计算相对于目标变量的决定系数 R^2 的是为:0.78。这个值说明模型有一定的参考性,在实际中可能会有些偏差。

模型健壮性

一个最优的模型不一定是一个健壮模型。有的时候模型会过于复杂或者过于简单,以致于难以泛化新增添的数据;有的时候模型采用的学习算法并不适用于特定的数据结构;有的时候样本本身可能有太多噪点或样本过少,使得模型无法准确地预测目标变量。这些情况下我们会说模型是欠拟合的。

问题 12 - 模型健壮性

模型是否足够健壮来保证预测的一致性?

提示: 执行下方区域中的代码,采用不同的训练和测试集执行 fit_model 函数10次。注意观察对一个特定的客户来说,预测是如何随训练数据的变化而变化的。

# 请先注释掉 fit_model 函数里的所有 print 语句
vs.PredictTrials(features, prices, fit_model, client_data)
Trial 1: $391,183.33
Trial 2: $411,417.39
Trial 3: $415,800.00
Trial 4: $420,622.22
Trial 5: $418,377.27
Trial 6: $411,931.58
Trial 7: $399,663.16
Trial 8: $407,232.00
Trial 9: $402,531.82
Trial 10: $413,700.00

Range in prices: $29,438.89

问题 12 - 回答:

  1. 对于模型来说以上 10 次训练数据的变化价格差值范围大概为 $29,438.89 左右,这个范围有些大,说明模型的健壮性不是很好。

review: 关于敏感性分析更多的知识可以参考 https://en.wikipedia.org/wiki/Sensitivity_analysis

问题 13 - 实用性探讨

简单地讨论一下你建构的模型能否在现实世界中使用?

提示:回答以下几个问题,并给出相应结论的理由:

  • 1978年所采集的数据,在已考虑通货膨胀的前提下,在今天是否仍然适用?
  • 数据中呈现的特征是否足够描述一个房屋?
  • 在波士顿这样的大都市采集的数据,能否应用在其它乡镇地区?
  • 你觉得仅仅凭房屋所在社区的环境来判断房屋价值合理吗?

问题 13 - 回答:

以上构建的模型不能在现实世界中使用,理由如下:

review 提示:'MEDV'特征的值已经过必要的数学转换,可以反映35年来市场的通货膨胀效应。

  • 1978年到现今时间跨度太大,消费水平的差异、购房侧重点的不同、经济条件的差异等等诸多的原因影响,所以训练出的模型已经无法预测如今市场房屋价值

  • 数据中呈现的特征不能足够的描述一个房屋,如今购房要求比较高,关注的更多的是房屋的地理位置,周边环境,如学校、医院、交通等

  • 在波士顿这样的大都市采集的数据不能应用于其他乡镇地区,如今消费观、经济条件、购房的侧重点、以及其他情况不同区域的人都有不同的侧重点

  • 仅仅凭房屋所在社区的环境来判断房屋价值不合理,房屋的价值不仅仅与房屋所在社区的环境有关,其他的一些因素:如房屋在社区的位置、房屋的楼层高低、房屋的建造成本、空间大小等都会影响房屋价值

可选问题 - 预测北京房价

(本题结果不影响项目是否通过)通过上面的实践,相信你对机器学习的一些常用概念有了很好的领悟和掌握。但利用70年代的波士顿房价数据进行建模的确对我们来说意义不是太大。现在你可以把你上面所学应用到北京房价数据集中 bj_housing.csv

免责声明:考虑到北京房价受到宏观经济、政策调整等众多因素的直接影响,预测结果仅供参考。

这个数据集的特征有:

  • Area:房屋面积,平方米
  • Room:房间数,间
  • Living: 厅数,间
  • School: 是否为学区房,0或1
  • Year: 房屋建造时间,年
  • Floor: 房屋所处楼层,层

目标变量:

  • Value: 房屋人民币售价,万

你可以参考上面学到的内容,拿这个数据集来练习数据分割与重排、定义衡量标准、训练模型、评价模型表现、使用网格搜索配合交叉验证对参数进行调优并选出最佳参数,比较两者的差别,最终得出最佳模型对验证集的预测分数。

# TODO 6

# 你的代码

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV

%matplotlib inline
# 载入北京房屋的数据集
data = pd.read_csv('bj_housing.csv')
prices = data['Value']
features = data.drop('Value', axis = 1)

print "Beijing housing dataset has {} data points with {} variables each.".format(*data.shape)
Beijing housing dataset has 9999 data points with 7 variables each.
# 数据分割与重排
X_train, X_test, y_train, y_test = train_test_split(features, prices, test_size=0.2, random_state=30)
# 决定系数计算
def performance_metric(y_true, y_predict):
    score = r2_score(y_true, y_predict)
    return score
# 训练最优模型
def fit_model(X, y):
    cross_validator = KFold(n_splits=10, random_state=1, shuffle=True)
    
    regressor = DecisionTreeRegressor()
    
    params = { 'max_depth': range(1,11) }

    scoring_fnc = make_scorer(performance_metric)

    grid = GridSearchCV(regressor, params, scoring=scoring_fnc, cv=cross_validator)

    # 基于输入数据 [X,y],进行网格搜索
    grid = grid.fit(X, y)

    # 返回网格搜索后的最优模型
    return grid.best_estimator_
# 基于训练数据,获得最优模型
optimal_reg = fit_model(X_train, y_train)

# 输出最优模型的 'max_depth' 参数
print "Parameter 'max_depth' is {} for the optimal model.".format(optimal_reg.get_params()['max_depth'])
Parameter 'max_depth' is 4 for the optimal model.
# 计算相对于目标变量的决定系数 R2的值
predicted_price = optimal_reg.predict(X_test)

r2 = performance_metric(y_test, predicted_price)

print "Optimal model has R^2 score {:,.2f} on test data".format(r2)
Optimal model has R^2 score 0.75 on test data

问题14 - 北京房价预测

你成功的用新的数据集构建了模型了吗?他能对测试数据进行验证吗?它的表现是否符合你的预期?交叉验证是否有助于提升你模型的表现?

提示:如果你是从零开始构建机器学习的代码会让你一时觉得无从下手。这时不要着急,你要做的只是查看之前写的代码,把每一行都看明白,然后逐步构建你的模型。当中遇到什么问题也可以在我们论坛寻找答案。也许你会发现你所构建的模型的表现并没有达到你的预期,这说明机器学习并非是一项简单的任务,构建一个表现良好的模型需要长时间的研究和测试。这也是我们接下来的课程中会逐渐学到的。

问题14 - 回答

使用北京房屋数据集成功构建了模型,并成功对测试数据集进行了验证,模型大体符合预期,交叉验证可以提升模型的表现。

机器学习