项目 1: 预测波士顿房价

来源:互联网 发布:信鸽查询软件下载 编辑:程序博客网 时间:2024/04/29 14:32

机器学习工程师纳米学位

模型评价与验证

项目 1: 预测波士顿房价

欢迎来到机器学习工程师纳米学位的第一个项目!在此文件中,有些示例代码已经提供给你,但你还需要实现更多的功能来让项目成功运行。除非有明确要求,你无须修改任何已给出的代码。以编程练习开始的标题表示接下来的内容中有需要你必须实现的功能。每一部分都会有详细的指导,需要实现的部分也会在注释中以TODO标出。请仔细阅读所有的提示!

除了实现代码外,你还必须回答一些与项目和实现有关的问题。每一个需要你回答的问题都会以‘问题 X’为标题。请仔细阅读每个问题,并且在问题后的‘回答’文字框中写出完整的答案。你的项目将会根据你对问题的回答和撰写代码所实现的功能来进行评分。

第一步. 导入数据

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

此项目的数据集来自UCI机器学习知识库(数据集已下线)。波士顿房屋这些数据于1978年开始统计,共506个数据点,涵盖了麻省波士顿不同郊区房屋14种特征的信息。本项目对原始数据集做了以下处理:
- 有16个'MEDV' 值为50.0的数据点被移除。 这很可能是由于这些数据点包含遗失看不到的值
- 有1个数据点的 'RM' 值为8.78. 这是一个异常值,已经被移除。
- 对于本项目,房屋的'RM''LSTAT''PTRATIO'以及'MEDV'特征是必要的,其余不相关特征已经被移除。
- 'MEDV'特征的值已经过必要的数学转换,可以反映35年来市场的通货膨胀效应。

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

# 载入此项目所需要的库import numpy as npimport pandas as pdimport visuals as vs # Supplementary code# 检查你的Python版本from sys import version_infoif 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'的最小值、最大值、均值、中值和标准差;
- 将运算结果储存在相应的变量中。

#TODO 1##numpy的std和var默认计算总体标准差/方差,pandas默认计算样本标准差/方差,可以通过ddof参数更改#目标:计算价值的最小值minimum_price = np.min(prices)#目标:计算价值的最大值maximum_price = np.max(prices)#目标:计算价值的平均值mean_price = np.mean(prices)#目标:计算价值的中值#if prices.size % 2 == 1:#    median_price = sorted(prices)[prices.size / 2 + 1]#else:#    median_price = sum(sorted(prices)[prices.size / 2 -1 : prices.size / 2])/2median_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.00Maximumprice:1,024,800.00 Mean price: 454,342.94Medianprice438,900.00 Standard deviation of prices: $165,171.13

问题 1 - 特征观察

如前文所述,本项目中我们关注的是其中三个值:'RM''LSTAT''PTRATIO',对每一个数据点:
- 'RM' 是该地区中每个房屋的平均房间数量;
- 'LSTAT' 是指该地区有多少百分比的房东属于是低收入阶层(有工作但收入微薄);
- 'PTRATIO' 是该地区的中学和小学里,学生和老师的数目比(学生/老师)。

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

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

### 问题 1 - 回答:1)’RM’越大,’MEDV’越大;基于单个房间的面积差异不大的假设,房屋平均数量等效的描述房屋的总面积,在其他特征相同时,面积越大,总价越高;2)’LSTAT’越高,’MEDV’越小;房东有工作且属于低收入阶层的比例大,可能的原因包括:当地的房价平均价格低、租房市场供大于求等,侧面说明当地经济水平相对较低;3)’PTRATIO’越高,’MEDV’越低;经济发达地区的教育行业越兴旺,教育产业更具有活力和市场,从业人员越多。

第二次审阅:

「’PTRATIO’越高,’MEDV’越低;经济发达地区的教育行业越兴旺,教育产业更具有活力和市场,从业人员越多。」
‘PTRATIO’ 是该地区的中学和小学里,学生和老师的数目比(学生/老师)。所以相对而言,同样数量的老师会负责更多的学生。我们也并不能从比值知道绝对的数量,你可以虑学生和老师的数目比对教学质量和教学资源的影响。

第二次修改:

3)’PTRATIO’越低,’MEDV’越高;‘MEDV’越高,经济越发达,教育行业同样越发达,有资源配置更多的师资力量。

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

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

使用 sklearn.model_selection 中的 train_test_split, 将featuresprices的数据都分成用于训练的数据子集和用于测试的数据子集。
- 分割比例为:80%的数据用于训练,20%用于测试;
- 选定一个数值以设定 train_test_split 中的 random_state ,这会确保结果的一致性;

# TODO 2# 提示: 导入train_test_splitfrom sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(features, prices, test_size=0.2, random_state=42)

问题 2 - 训练及测试

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

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

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

问题 2 - 回答:

原答案:1)将数据集按一定比例分为训练集和测试集,一方面可以用独立于训练集的样本评估学习算法的性能;另一方面可避免学习算法过拟合;
2)由于机器学习算法的拟合能力一般远高于问题复杂度,即采用复杂的算法总能在训练集上得到非常高的准确率;因此,如果没有数据来对模型进行测试,或利用部分训练集进行测试,都难以准确评估学习算法的泛化性能。

第一次审阅:

「可避免学习算法过拟合」这并不能避免过拟合,但是模型出现过拟合我们能够发现过拟合。

测试集确实可以帮助评价模型表现,测试集不能避免模型过拟合。模型出现过拟合通常是因为模型相对数据而言过于复杂,这里就是决策树的最大深度太深;而欠拟合就是模型不够复杂,在这里就是决策树的最大深度太浅。所以模型是过拟合和欠拟合与用训练集还是测试集测试本身没有关系。我们只能够通过比较模型在数据集上的测试分数和训练分数来判断模型是否有过拟合或者欠拟合的问题。

反馈:

原答案中“分割数据集可避免学习算法过拟合”可能表达得不清楚,我的本意是:通过对比训练集和测试集的评估分数,可以判断模型是否有过拟合的现象,如果有,就可以通过调整模型参数,重新训练得到新的模型,从而避免过拟合。不知道这样理解是否正确或符合常识。

第二次审阅:

「如果有,就可以通过调整模型参数,重新训练得到新的模型,从而避免过拟合」
这里的关系过于间接了,测试集直接的功能就是评估模型在未知数据的泛化能力。

此外,调整模型使用的是验证集,它与测试集是两个不同的概念。标准来讲,测试集只会在最终模型确定训练好之后使用一次。验证集用于模型调优。

反馈:

好的。训练数据包含训练集和验证集,用于模型训练和参数调优;测试数据包含测试集,用于评估模型的泛化能力。


第三步. 模型衡量标准

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

编程练习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_scorefrom sklearn.metrics import r2_scoredef performance_metric(y_true, y_predict):    """计算并返回预测值相比于预测值的分数"""    score = r2_score(y_true, y_predict)    return score

第一次提交答案:

计算公式同题目中第一个链接:http://stattrek.com/statistics/dictionary.aspx?definition=coefficient_of_determination

# TODO 3 可选# 不允许导入任何计算决定系数的库def performance_metric2(y_true, y_predict):    """计算并返回预测值相比于预测值的分数"""    y_true = np.array(y_true)    y_predict = np.array(y_predict)    N = y_true.size    sigmaTrue = y_true.std()    #meanTrue = y_true.mean()    meanTrue = np.average(y_true)    sigmaPred = y_predict.std()    #meanPred = y_predict.mean()    meanPred = np.average(y_predict)    score = (1.0 / N * sum(np.multiply(y_true - meanTrue, y_predict - meanPred)) /sigmaPred / sigmaTrue) ** 2    return score

第一次修改答案:

计算公式同题目中第三个链接:https://en.wikipedia.org/wiki/Coefficient_of_determination
,sklearn采用该定义。在该定义中,R2可以取负值,且不具有对称性。

def performance_metric2(y_true, y_predict):    """计算并返回预测值相比于预测值的分数"""    y_true = np.array(y_true)    y_predict = np.array(y_predict)    N = y_true.size    yBar = y_true.sum()/ N    SSR = ((y_true - y_predict) ** 2).sum()    SST = ((y_true - yBar) ** 2).sum()    score = 1 - SSR / SST    return score
score2 = performance_metric2([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(score2)
Model has a coefficient of determination, R^2, of 0.923.

问题 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 - 回答:

决定系数为0.923,说明目标变量的92.3%可以用特征来解释,模型较好的描述了目标变量的变化


第四步. 分析模型的表现

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

学习曲线

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

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

# 根据不同的训练集大小,和最大深度,生成学习曲线vs.ModelLearning(X_train, y_train)
![这里写图片描述](http://img.blog.csdn.net/20170919235850227?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmlnbGV0aHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

问题 4 - 学习曲线

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

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

问题 4 - 回答:

1)在上面四个模型中,max_depth=3的模型表现较好。max_depth=3的学习曲线随着训练集增加而降低、最终趋于平稳,而验证曲线随着训练集增加而升高并最终趋于平稳,说明当模型学习足够多的样本之后,基本学习到了训练集的基本模式;max_depth=6和10的学习曲线始终保持较高的评分,而在训练集上的表现相对max_depth=3较差,且方差较大,出现了过拟合现象。
2)随着训练集样本数量增多,模型基本拟合出了训练集的所有模式,而遇到‘特殊情况’的概率降低,学习曲线最终会收敛。

第一次审阅:

最大深度为3时,如果有更多的训练数据(大于300后继续增加),是否能有效提升模型的表现呢?

反馈:

在样本数增加到200以后,学习曲线趋于平稳,即模型基本拟合出了数据集的所有模式,且较难采用当前模型进一步提高评估分数;如果加入的训练数据和已有数据的分布规律基本相同,则不会明显提升模型的表现。

复杂度曲线

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

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

# 根据不同的最大深度参数,生成复杂度曲线vs.ModelComplexity(X_train, y_train)
![这里写图片描述](http://img.blog.csdn.net/20170919235926400?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmlnbGV0aHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

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

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

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

问题 5 - 回答:

1)当模型的最大深度为1时,模型训练和预测的决定系数都较小,偏差较大;当模型最大深度为10时,模型训练的决定系数极大,而预测的决定系数随着模型复杂度提高而有所下降,预测的方差较大
2)判断偏差和方差大小主要根据模型在训练集和测试集上的表现判断:训练和测试的准确率都较低说明模型的拟合能力较弱,预测准确率低,即偏差较大;而训练的准确率高、测试集准确率低,说明模型拟合了误差,在未见过的数据上表现不好,方差较大。

问题 6- 最优模型的猜测

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

问题 6 - 回答:

max_depth=3的模型较好,当max_depth=3和4时,模型在训练集上的表现基本一致;参考奥卡姆剃刀法则,对两个准确率相当的模型,选择简单的模型。


第五步. 选择最优参数

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

问题 7 - 回答:

网格搜索通过遍历给定的参数组合,分别用于训练,选取其中性能较好的组合作为模型参数,从而优化模型。

问题 8 - 交叉验证

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

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

问题 8 - 回答:

1)K折交叉验证法是将数据集分为K个规模相似的互斥子集,每次训练都采用其中K-1个子集作为训练集,而将剩余的子集作为测试集,最终返回K次测试结果的均值。
2)GridSearchCV对每一个参数组合进行一次K折交叉验证,得到对应的平均分数;最后选择平均分数最高的参数组合作为模型的最优参数组合,可通过best_params_属性获得该参数组合;
3)’cv_results_’属性返回一个字典,包含了各个参数及取值
4)网格搜索不使用交叉验证,使训练速度更快,但可能难以得到最优的模型参数;交叉验证对每一个参数组合得出的评分更为准确和鲁棒,提高评估的稳定性。

第一次审阅:

使用K折交叉验证法时是将训练集分成了K份还是整个数据集呢?
「而将剩余的子集作为测试集」K折交叉验证中的用于验证评分的部分我们称为验证集不是测试集,测试集不参与K折交叉验证过程。测试集和验证集是两个不同的概念,测试集用于评估模型的最终效果,而验证集用于模型调优。
更具体地说明GridSearchCV中的’cv_results_’属性能告诉我们什么,比如举例。尝试输出cv_results_或者阅读文档查看。

反馈:

1)模型训练是将数据集分为训练数据和测试数据(测试集),K折交叉验证是将训练数据分为K个规模相似的互斥子集,每次训练都采用其中K-1个子集作为训练集,剩余子集作为验证集,最终返回K次验证集评分结果的平均值作为评估分数。
2)’cv_results_’属性返回一个字典,记录了每一组网格参数每一次训练/验证(K折对应K次)对应的训练结果,包括训练/验证时间、训练/验证评估分数以及相关时间和评分的统计信息。

编程练习 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,GridSearchCVfrom sklearn.tree import DecisionTreeRegressorfrom sklearn.metrics import make_scorerdef fit_model(X, y):    """ 基于输入数据 [X,y],利于网格搜索找到最优的决策树模型"""    cross_validator = KFold(n_splits=10)    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_

问题 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'])
mean_fit_time mean_score_time mean_test_score mean_train_score \ 0 0.0036 0.0029 0.299259 0.460178 1 0.0036 0.0009 0.562190 0.725521 2 0.0040 0.0008 0.735255 0.823905 3 0.0036 0.0007 0.759906 0.868586 4 0.0034 0.0008 0.727736 0.899422 5 0.0038 0.0006 0.718151 0.926507 6 0.0039 0.0006 0.718811 0.945358 7 0.0041 0.0003 0.687320 0.961365 8 0.0042 0.0006 0.689245 0.975325 9 0.0043 0.0003 0.675072 0.984078 param_max_depth params rank_test_score split0_test_score \ 0 1 {u’max_depth’: 1} 10 0.487886 1 2 {u’max_depth’: 2} 9 0.732110 2 3 {u’max_depth’: 3} 2 0.804755 3 4 {u’max_depth’: 4} 1 0.821353 4 5 {u’max_depth’: 5} 3 0.803654 5 6 {u’max_depth’: 6} 5 0.833292 6 7 {u’max_depth’: 7} 4 0.834483 7 8 {u’max_depth’: 8} 7 0.808882 8 9 {u’max_depth’: 9} 6 0.845443 9 10 {u’max_depth’: 10} 8 0.792025 split0_train_score split1_test_score … split7_test_score \ 0 0.451907 0.393276 … 0.371648 1 0.716888 0.541372 … 0.538882 2 0.825096 0.717467 … 0.715567 3 0.869006 0.754296 … 0.781867 4 0.898087 0.776892 … 0.743699 5 0.932973 0.710594 … 0.738055 6 0.953398 0.741916 … 0.778344 7 0.968435 0.727839 … 0.739262 8 0.979686 0.711539 … 0.725697 9 0.987785 0.739619 … 0.716655 split7_train_score split8_test_score split8_train_score \ 0 0.452255 0.032192 0.464305 1 0.724182 0.353745 0.734585 2 0.815483 0.715218 0.823006 3 0.856730 0.700104 0.874314 4 0.893582 0.632705 0.900806 5 0.915605 0.679555 0.921076 6 0.937424 0.676224 0.937046 7 0.957279 0.545675 0.951616 8 0.970245 0.632594 0.974567 9 0.979021 0.593986 0.985794 split9_test_score split9_train_score std_fit_time std_score_time \ 0 0.335204 0.469736 0.000663 0.006730 1 0.660249 0.725304 0.000800 0.000831 2 0.784659 0.827042 0.000447 0.000600 3 0.850445 0.870769 0.000490 0.000458 4 0.806423 0.898087 0.000490 0.000400 5 0.780809 0.929003 0.000400 0.000490 6 0.794412 0.945589 0.000539 0.000490 7 0.761910 0.960843 0.000538 0.000458 8 0.793099 0.974387 0.000400 0.000490 9 0.780686 0.983332 0.000458 0.000458 std_test_score std_train_score 0 0.150506 0.006533 1 0.113488 0.008590 2 0.071758 0.006626 3 0.074458 0.006250 4 0.070410 0.005571 5 0.065497 0.006456 6 0.065473 0.006173 7 0.075656 0.005726 8 0.077587 0.003967 9 0.080890 0.003120 [10 rows x 31 columns] Parameter ‘max_depth’ is 4 for the optimal model.

问题 9 - 回答:

最大深度为4,与问题6的回答略微不同。

第六步. 做出预测

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

问题 10 - 预测销售价格

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

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

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

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

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

dData=pd.DataFrame(data)dData.describe()
RM LSTAT PTRATIO MEDV count 489.000000 489.000000 489.000000 4.890000e+02 mean 6.240288 12.939632 18.516564 4.543429e+05 std 0.643650 7.081990 2.111268 1.653403e+05 min 3.561000 1.980000 12.600000 1.050000e+05 25% 5.880000 7.370000 17.400000 3.507000e+05 50% 6.185000 11.690000 19.100000 4.389000e+05 75% 6.575000 17.120000 20.200000 5.187000e+05 max 8.398000 37.970000 22.000000 1.024800e+06
# 生成三个客户的数据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: $403,025.00Predicted selling price for Client 2's home: $237,478.72Predicted selling price for Client 3's home: $931,636.36

问题 10 - 回答:

1)三位客户的建议售价分别为: $403,025.00、$237,478.72和$931,636.36。
2)对客户1,其特征参数RM在训练集中处于min和Q1之间;LSTAT与训练集的Q3相当;PTRATIO处于min和Q1之间。根据问题1中的直觉判断,客户1的房屋总价应略低于训练集中的Q1即3.5e+5,预测值4.03e+5相对偏高。
3)对客户2,其三个特征参数分别处于训练集的min和Q1之间、Q3与max之间、与max值相当位置,因此,其房屋总价应在训练集房价的Q1:3.5e+5和最小值:1.05e+5之间,预测值2.37e+5较为合理;
4)对客户4,其三个特征参数分别处于训练集的接近max、接近min、接近min位置,因此,其房屋总价应接近于训练集中房价的max:1.03e+6,预测值9.31e+5较为合理。

编程练习 5

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

#TODO 5# 提示:你可能需要用到 X_test, y_test, optimal_reg, performance_metric# 提示:你可能需要参考问题10的代码进行预测# 提示:你可能需要参考问题3的代码来计算R^2的值from sklearn.metrics import r2_scorer2 = r2_score(y_test, optimal_reg.predict(X_test))print "Optimal model has R^2 score {:,.2f} on test data".format(r2)
Optimal model has R^2 score 0.84 on test data

问题11 - 分析决定系数

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

问题11 - 回答:

最优模型的决定系数R2为0.84,说明模型基本准确的拟合了数据集的基本模式,能够较好的进行房价预测。

模型健壮性

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

问题 12 - 模型健壮性

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

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

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

问题 12 - 回答:

预测值的最大变化范围约为总价的5%,模型预测的一致性较好。

问题 13 - 实用性探讨

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

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

问题 13 - 回答:

1)在不同的时代,类似特征与房价的相关性一般也类似,但对房价的影响程度会发生较大的变化,可以参考学区房在不同时代对于房价的意义。尽管已考虑通货膨胀,但1978年的数据仍然不适合用于现在的房价预测,但可以作为影响趋势的参考。
2)不足够。考虑对房价的影响,房屋自身的重要属性还包括房龄、户型、社区档次等等;其他影响房价的因素还包括附近交通状况、生活配套设施是否齐全、当时政策是否对房价利好等等。
3)不适宜用于其他乡镇地区。在不同地区,类似特征与房价的相关性类似,但影响程度不同,以线性回归为例,回归模型中的斜率不同;另外不同地区的整体房价水平不同,对应于线性回归模型中的截距也不同。
4)不完全合理,社会的环境特征不足以准确描述房价的规律。

可选问题 - 预测北京房价

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

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

这个数据集的特征有:
- Area:房屋面积,平方米
- Room:房间数,间
- Living: 厅数,间
- School: 是否为学区房,0或1
- Year: 房屋建造时间,年
- Floor: 房屋所处楼层,层

目标变量:
- Value: 房屋人民币售价,万

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

# TODO 6#读入北京房价数据bj_data = pd.read_csv('bj_housing.csv')bj_prices = bj_data['Value']bj_features = bj_data.drop('Value', axis = 1)#分割训练集和测试集fea_train, fea_test, val_train, val_test = train_test_split(bj_features, bj_prices, test_size=0.25, random_state=42)#利用交叉验证和网格搜索选择最优模型bj_optimal_reg = fit_model(fea_train, val_train)print "Parameter 'max_depth' is {} for the optimal model.".format(bj_optimal_reg.get_params()['max_depth'])#模型评分bj_r2 = r2_score(val_test, bj_optimal_reg.predict(fea_test))print "Optimal model has R^2 score {:,.2f} on test data".format(bj_r2)
Parameter 'max_depth' is 5 for the optimal model.Optimal model has R^2 score 0.55 on test data
from sklearn.model_selection import KFold,GridSearchCVfrom sklearn.svm import SVRfrom sklearn.metrics import make_scorerdef fit_model2(X, y):    """ 基于输入数据 [X,y],利于网格搜索找到最优的决策树模型"""    cross_validator = KFold(n_splits=3)    regressor = SVR()    params = {"C": [1e0, 1e1, 1e2, 1e3],"gamma": np.logspace(-2, 2, 5)}    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_
bj_optimal_reg = fit_model2(fea_train, val_train)print "Parameter 'C' is {} for the optimal model.".format(bj_optimal_reg.get_params()['C'])print "Parameter 'gamma' is {} for the optimal model.".format(bj_optimal_reg.get_params()['gamma'])#模型评分bj_r2 = r2_score(val_test, bj_optimal_reg.predict(fea_test))print "Optimal model has R^2 score {:,.2f} on test data".format(bj_r2)
Parameter 'C' is 1000.0 for the optimal model.Parameter 'gamma' is 0.01 for the optimal model.Optimal model has R^2 score 0.54 on test data

问题14 - 北京房价预测

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

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

问题14 - 回答:

1)利用前面定义的函数构建了模型;
2)可以对测试数据进行验证;
3)决定系数在0.55~0.57左右,预测性能一般;
4)改变K值,对模型评分结果影响较小。采用svm模块中的SVR方法,并对参数‘gamma’和‘C’采用交叉验证(训练时间较长,取K=3)和网格搜索寻优,最优模型的决定系数约为0.54。

阅读全文
0 0
原创粉丝点击