首先,我们先训练一个线性回归模型:
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(housing_prepared, housing_labels)
LinearRegression()
现在你有一个可以工作的线性回归模型了,让我们用几个训练集的实例试试:
some_data = housing[:5] # 获取前5行数据
some_labels = housing_labels.iloc[:5] # 获取前5行标签,用于验证模型结果
some_data_prepared = full_pipeline.transform(some_data) # 流水线处理数据
print("Predictions:", lin_reg.predict(some_data_prepared)) # 模型预测数据
print("Labels:", list(some_labels)) # 真实结果
Predictions: [210644.60459286 317768.80697211 210956.43331178 59218.98886849 189747.55849879]
Labels: [286600.0, 340600.0, 196900.0, 46300.0, 254500.0]
可以工作了,虽然预测还不是很准确(实际上。。。一点都不准。。。)。我们可以使用Scikit-Learn
的mean_squared_error()
函数来测量整个训练集上回归模型的RMSE
(均方根误差):
RMSE
MAE
SD
from sklearn.metrics import mean_squared_error
housing_predictions = lin_reg.predict(housing_prepared) # 使用模型获取训练集全部预测数据
lin_mse = mean_squared_error(housing_labels, housing_predictions) # 真实数据 与 模型预测数据 的 均方根误差
lin_rmse = np.sqrt(lin_mse) # 平方根,预测误差值
lin_rmse
68628.19819848922
median_housing_values
分布在 120000~265000 美元之间,所以典型的预测误差达到 68628 美元只能说明差强人意。
这就是一个典型的模型对训练数据欠拟合的案例
。这种情况发生时,通常意味着这些:
想要修正欠拟合,可以通过:
我们这个模型不是一个正则化的模型,所以可以排除最后一个选项。你可以尝试添加更多的特征(比如,人口数量的日志),但首选,让我们尝试一个更复杂的模型
,看看它到底是怎样工作的。
我们来训练一个DecisionTreeRegressor
。这是一个非常强大的模型,它能够从数据中找到复杂的非线性关系(决策树)。使用方法与上面的线性回归模型相同:
from sklearn.tree import DecisionTreeRegressor
tree_reg = DecisionTreeRegressor()
tree_reg.fit(housing_prepared, housing_labels)
DecisionTreeRegressor()
训练集评估结果
housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squared_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)
print(tree_rmse)
0.0
结果是0
,没有预测误差,这个模型真的可以做到绝对完美么
?当然,更可能是这个模型对数据严重过拟合
了。我们应该怎么确认?前面提到过,在你有信心启动模型之前,都不要触碰测试集。
所有这里,你需要那训练集中的一部分用于训练,另一部分用于模型验证。
评估决策树模型的一种方法是使用train_test_split
函数将训练集分为较小的训练集和验证集,然后根据这些较小的训练集来训练模型,并对其进行评估。这虽然有一些工作量,但是也不会太难,并且非常有效。
另一个不错的选择市使用Scikit-Learn
的K-折交叉验证
功能。以下是执行K-折交叉验证
的代码:
def display_scores(scores):
print("分 数:", scores)
print("平均值:", scores.mean())
print("标准差:", scores.std())
from sklearn.model_selection import cross_val_score
# neg_mean_squared_error: 负均方误差
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)
display_scores(tree_rmse_scores)
分 数: [70062.5222628 66736.98017719 70439.6047592 70474.78239772 71238.21621992
74620.75350778 71398.18416741 70620.80936843 77492.84330946 71004.28109473]
平均值: 71408.89772646272
标准差: 2712.8600596563356
Scikit-Learn
的K-折交叉验证
功能更倾向于使用效用函数
(越大越好)而不是成本函数
(越小越好),所以计算分数的函数实际上负的MSE
(一个负值)函数,这就是为什么上面的代码在计算平方根之前会先计算出-scores
。
这次的决策树模型好像不如之前的表现得好,事实上,它看起来简直比线性回归模型还要糟糕。请注意,交叉验证不仅可以得到一个模型性能的评估值,还可以衡量该评估的精准度(即其标准差)。这里该决策树得到的评分约为71407
,上下浮动±2439
。如果你只使用了一个验证集,就收不到这样的结果信息。交叉验证的代价就是要多次训练模型,因此也不是永远都行得通。
保险起见,让我们也计算一下线性回归模型的评分:
lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
lin_rmse_scores = np.sqrt(-lin_scores)
display_scores(lin_rmse_scores)
分 数: [66782.73843989 66960.118071 70347.95244419 74739.57052552 68031.13388938
71193.84183426 64969.63056405 68281.61137997 71552.91566558 67665.10082067]
平均值: 69052.46136345083
标准差: 2731.674001798347
没错,决策树模型的确严重过拟合了,以至于表现得比线性回归模型还要糟糕。
我们再来试试最后一个模型RndomForestRegressor
。随机森林的工作原理
:通过对特征的随机子集进行许多个决策树的训练,然后对其预测取平均。在多个模型的基础之上建立模型,称之为集成学习
,这是进一步推动机器学习算法的好方法。这里我们将跳过大部分代码,因为与其他模型基本相同:
from sklearn.ensemble import RandomForestRegressor
forest_reg = RandomForestRegressor()
forest_reg.fit(housing_prepared, housing_labels)
RandomForestRegressor()
housing_predictions = forest_reg.predict(housing_prepared)
forest_mse = mean_squared_error(housing_labels, housing_predictions)
forest_rmse = np.sqrt(forest_mse)
print(forest_rmse)
18725.06655956781
forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
forest_rmse_scores = np.sqrt(-forest_scores)
display_scores(forest_rmse_scores)
分 数: [49809.66295035 47362.11725625 50097.32716715 51971.44001152 49498.75378409
53481.17484005 49051.91408781 48402.93749135 52812.15210493 50385.42811085]
平均值: 50287.290780434654
标准差: 1842.3191312235808
当前数据看起来是目前对好的。但是,请注意,训练集上的分数(18725)仍然远低于验证集(50287),这意味着该模型仍然对训练集过拟合
。过拟合的可能解决方案包括:
不过在深入探索随机森林之前,你应该先尝试一遍各种机器学习算法的其他模型(几种具有不同内核的支持向量机,比如神经网络模型等),但记住,别花太多时间去调整超参数,我们的目的是筛选出几个(2~5个)有效的模型。
每一个尝试过的模型都应该妥善的保存,以便将来可以轻松回顾。通过
Python
的pickle
模块或joblib
库,你可以轻松保存Scikit-Learn
模型,这样可以更有效地将大型NumPy
数组序列号。