欢迎来到机器学习工程师纳米学位的第一个项目!在此文件中,有些示例代码已经提供给你,但你还需要实现更多的功能来让项目成功运行。除非有明确要求,你无须修改任何已给出的代码。以编程练习开始的标题表示接下来的内容中有需要你必须实现的功能。每一部分都会有详细的指导,需要实现的部分也会在注释中以TODO标出。请仔细阅读所有的提示!
除了实现代码外,你还必须回答一些与项目和实现有关的问题。每一个需要你回答的问题都会以'问题 X'为标题。请仔细阅读每个问题,并且在问题后的'回答'文字框中写出完整的答案。你的项目将会根据你对问题的回答和撰写代码所实现的功能来进行评分。
提示:Code 和 Markdown 区域可通过 Shift + Enter 快捷键运行。此外,Markdown可以通过双击进入编辑模式。
在这个项目中,你将利用马萨诸塞州波士顿郊区的房屋信息数据训练和测试一个模型,并对模型的性能和预测能力进行测试。通过该数据训练后的好的模型可以被用来对房屋做特定预测---尤其是对房屋的价值。对于房地产经纪等人的日常工作来说,这样的预测模型被证明非常有价值。
此项目的数据集来自UCI机器学习知识库(数据集已下线)。波士顿房屋这些数据于1978年开始统计,共506个数据点,涵盖了麻省波士顿不同郊区房屋14种特征的信息。本项目对原始数据集做了以下处理:
'MEDV'
值为50.0的数据点被移除。 这很可能是由于这些数据点包含遗失或看不到的值。'RM'
值为8.78. 这是一个异常值,已经被移除。'RM'
, 'LSTAT'
,'PTRATIO'
以及'MEDV'
特征是必要的,其余不相关特征已经被移除。'MEDV'
特征的值已经过必要的数学转换,可以反映35年来市场的通货膨胀效应。运行下面区域的代码以载入波士顿房屋数据集,以及一些此项目所需的Python库。如果成功返回数据集的大小,表示数据集已载入成功。
In [1]:
# 载入此项目所需要的库
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
In [2]:
# 载入波士顿房屋的数据集
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)
In [9]:
#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)
In [3]:
# 载入画图所需要的库 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)
In [7]:
# TODO 2
# 提示: 导入train_test_split
from sklearn.cross_validation import train_test_split
def generate_train_and_test(X, y):
"""打乱并分割数据为训练集和测试集"""
X_train,X_test, y_train, y_test = train_test_split(X,y,test_size=0.2, random_state=0)
return (X_train, X_test, y_train, y_test)
X_train, X_test, y_train, y_test = generate_train_and_test(features, prices)
如果不能对模型的训练和测试的表现进行量化地评估,我们就很难衡量模型的好坏。通常我们会定义一些衡量标准,这些标准可以通过对某些误差或者拟合程度的计算来得到。在这个项目中,你将通过运算决定系数 R2 来量化模型的表现。模型的决定系数是回归分析中十分常用的统计信息,经常被当作衡量模型预测能力好坏的标准。
R2的数值范围从0至1,表示目标变量的预测值和实际值之间的相关程度平方的百分比。一个模型的R2 值为0还不如直接用平均值来预测效果好;而一个R2 值为1的模型则可以对目标变量进行完美的预测。从0至1之间的数值,则表示该模型中目标变量中有百分之多少能够用特征来解释。模型也可能出现负值的R2,这种情况下模型所做预测有时会比直接计算目标变量的平均值差很多。
在下方代码的 performance_metric
函数中,你要实现:
sklearn.metrics
中的 r2_score
来计算 y_true
和 y_predict
的R2值,作为对其表现的评判。score
变量中。或
In [8]:
# 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
In [9]:
# TODO 3 可选
# 不允许导入任何计算决定系数的库
def performance_metric2(y_true, y_predict):
"""计算并返回预测值相比于预测值的分数"""
score = None
return score
In [10]:
# 计算这个模型的预测结果的决定系数
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)
In [18]:
# 根据不同的训练集大小,和最大深度,生成学习曲线
vs.ModelLearning(X_train, y_train)
In [19]:
# 根据不同的最大深度参数,生成复杂度曲线
vs.ModelComplexity(X_train, y_train)
'cv_results_'
属性能告诉我们什么?提示: 在下面 fit_model函数最后加入 print pd.DataFrame(grid.cv_results_)
可以帮你查看更多信息。
数据集分为 训练集 和测试集
训练集用以模型训练
测试集合用以苹果模型最终评分
一般的划分比例是 8:2
`K-fold cross-validation (k-CV)则是Double cross-validation的延伸。
做法是将训练集分成k个子集,选去其中一个作为验证集, 其余k-1个子集作为训练 进行训练,训练完 用验证集进行验证评分
k-CV交叉验证会重复这个步骤k次,每次选择不同的一个子集作为验证集。 如:总共划分了10个子集, 第一次 选取第一个子集作为验证,剩余其他9个参与训练。 第二次 选取第二子集作为验证,剩余其他9个参与训练.... 以此类推。 总共做10次训练和验证。 保证每个子集都做一次验证集。 `
首先列出模型各种可能的参数集合, 如线程模型取 函数的指数项D,决策树模型取 树的深度D
针对每一个可能的参数 进行k次交叉验证取平均值做为模型评分。
在这些评分里面选取一个获得最优评分的参数D
GridSearchCV中的'cvresults'属性能告诉我们什么?
cv_results_ 属性告诉我们 交叉验证的每一次的运算结果和各个指标
网格搜索时如果不使用交叉验证会有什么问题?交叉验证又是如何解决这个问题的?
网络搜索如果不使用交叉验证,仅仅只是在各个区间里面取最优值,可能出现偶然性评分偏高或偏低的问题(欠拟合、过拟合问题)。
交叉验证 避免了数据集划分的偶然性造成的评分偏高或偏低的问题,通过使用不同的训练集和验证集训练然后取K次评分的平均来得到最终成绩来保证评分的客观和准确
在这个练习中,你将需要将所学到的内容整合,使用决策树算法训练一个模型。为了得出的是一个最优模型,你需要使用网格搜索法训练模型,以找到最佳的 'max_depth'
参数。你可以把'max_depth'
参数理解为决策树算法在做出预测前,允许其对数据提出问题的数量。决策树是监督学习算法中的一种。
在下方 fit_model
函数中,你需要做的是:
'cross_validator'
变量: 使用 sklearn.model_selection
中的 KFold
创建一个交叉验证生成器对象;'regressor'
变量: 使用 sklearn.tree
中的 DecisionTreeRegressor
创建一个决策树的回归函数;'params'
变量: 为 'max_depth'
参数创造一个字典,它的值是从1至10的数组;'scoring_fnc'
变量: 使用 sklearn.metrics
中的 make_scorer
创建一个评分函数;
将 ‘performance_metric’
作为参数传至这个函数中;'grid'
变量: 使用 sklearn.model_selection
中的 GridSearchCV
创建一个网格搜索对象;将变量'regressor'
, 'params'
, 'scoring_fnc'
和 'cross_validator'
作为参数传至这个对象构造函数中;如果你对python函数的默认参数定义和传递不熟悉,可以参考这个MIT课程的视频。
In [12]:
# 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=2, random_state=None, shuffle=False)
regressor = DecisionTreeRegressor()
params = {"max_depth": [1,2,3,4,5,6,7,8,9,10]}
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_
In [56]:
# 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
In [13]:
# 基于熟练数据,获得最优模型
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'])
In [14]:
# 生成三个客户的数据
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)
从统计的结果可以看出
所以
客户1 预测价格 $391,183.33,房间数5 RM数量中 ,穷人数中等, LSTAT一般,教育资源一般,15个学生对1位老师, PTRATIO中等
客户2 预测价格 $189,123.53,房间数4 RM数量低,穷人数偏多 LSTAT低,教育资源稀缺,22位学生对1位老师, PTRATIO高。
客户3 预测价格 $942,666.67,房间书8 RN数量高 ,穷人占比少 LSTAT高 ,教育资源较为优秀,12位学生对应1位老师, PTRATIO高
预测价格比较合理。
In [18]:
#TODO 5
# 提示:你可能需要用到 X_test, y_test, optimal_reg, performance_metric
# 提示:你可能需要参考问题10的代码进行预测
# 提示:你可能需要参考问题3的代码来计算R^2的值
y_pre = optimal_reg.predict(X_test)
r2 = r2_score(y_test,y_pre)
print "Optimal model has R^2 score {:,.2f} on test data".format(r2)
In [17]:
# 请先注释掉 fit_model 函数里的所有 print 语句
vs.PredictTrials(features, prices, fit_model, client_data)
(本题结果不影响项目是否通过)通过上面的实践,相信你对机器学习的一些常用概念有了很好的领悟和掌握。但利用70年代的波士顿房价数据进行建模的确对我们来说意义不是太大。现在你可以把你上面所学应用到北京房价数据集中 bj_housing.csv
。
免责声明:考虑到北京房价受到宏观经济、政策调整等众多因素的直接影响,预测结果仅供参考。
这个数据集的特征有:
目标变量:
你可以参考上面学到的内容,拿这个数据集来练习数据分割与重排、定义衡量标准、训练模型、评价模型表现、使用网格搜索配合交叉验证对参数进行调优并选出最佳参数,比较两者的差别,最终得出最佳模型对验证集的预测分数。
In [77]:
# TODO 6
# 导入数据
# 载入此项目所需要的库
import numpy as np
import pandas as pd
import visuals as vs # Supplementary code
# 让结果在notebook中显示
%matplotlib inline
# 1.导入数据
data = pd.read_csv('bj_housing.csv')
area = data['Area']
Room = data['Room']
living = data['Living']
school = data['School']
year = data['Year']
Floor = data['Floor']
prices = data['Value']
features = data.drop('Value', axis = 1)
# 完成
print "BJ housing dataset has {} data points with {} variables each.".format(*data.shape)
# 2. 分析数据
minimum_price = prices.min()
maximum_price = prices.max()
mean_price = prices.mean()
median_price = prices.median()
std_price = prices.std()
#目标:输出计算的结果
print "Statistics for BJ 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)
X_train, X_test, y_train, y_test = generate_train_and_test(features, prices)
# 学习曲线
vs.ModelLearning(X_train, y_train)
# 根据不同的最大深度参数,生成复杂度曲线
vs.ModelComplexity(X_train, y_train)
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'])
# 模型评价
y_pre = optimal_reg.predict(X_test)
r2 = r2_score(y_test,y_pre)
print "Optimal model has R^2 score {:,.2f} on test data".format(r2)
In [ ]: