评估决策树模型的一种方法是使用train_test_split函数可以将训练集划分成一个更小的训练集和验证集,然后会用这个较小的训练集来训练我们的模型,然后视同验证集来验证我们的模型。这只是一点小小的工作,而且也不难,还会使得工作的更好。
一个很好的选择是使用Scikit-Learn的交叉验证特性。下面的代码执行k-折交叉验证(K-fold cross-validation);它随机将训练集分成10个不同的子集,称为折叠(fold),然后对决策树模型进行10次训练和评估,每次都选择不同的折叠项进行评估,并用其他的9个折叠项来训练。结果是一个包含10个评价分数的数组:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
rmse_scores = np.sqrt(-scores)
Scikit-Learn交叉验证特性需要的是一个效用函数(值越大越好)而不是成本函数(值越低越好),所以得分函数实际上与MSE相反(比如是一个负数),这就是为什么前面的代码在计算平方根之前先计算-scores。
让我们看看结果:
>>> def display_scores(scores):
... print("Scores:", scores)
... print("Mean:", scores.mean())
... print("Standard deviation:", scores.std())
...
>>> display_scores(tree_rmse_scores)
Scores: [ 74678.4916885 64766.2398337 69632.86942005 69166.67693232
71486.76507766 73321.65695983 71860.04741226 71086.32691692
76934.2726093 69060.93319262]
Mean: 71199.4280043
Standard deviation: 3202.70522793
现在决策树看起来不像之前那么好了。事实上,它似乎比线性回归模型更糟糕!请注意,交叉验证不仅可以获得模型性能的估计,还可以度量这个估计值的精确程度(即其标准偏差)。决策树大约71200分,一般±3200浮动。如果您只使用了一个验证集,您就不会得到这些信息。但是交叉验证以队模型进行多次训练为代价,因此不总是可能的。
为安全起见,让我们来计算线性回归模型的评分:
>>> 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)
Scores: [ 70423.5893262 65804.84913139 66620.84314068 72510.11362141
66414.74423281 71958.89083606 67624.90198297 67825.36117664
72512.36533141 68028.11688067]
Mean: 68972.377566
Standard deviation: 2493.98819069
这是正确的:决策树模型过于复杂,以致于它的性能比线性回归模型还要差。
现在让我们尝试最后一个模型:RandomForestRegressor。正如我们在第7章中所看到的,随机森林的是通过使用特征的随机子集来训练多个决策树,然后对它们的预测进行平均。在许多其他模型之上构建一个模型被称为Ensemble Learning(集成学习),这通常是进一步推进ML算法的一个好方法。我们将跳过大部分代码,因为它本质上与其他模型相同:
>>> from sklearn.ensemble import RandomForestRegressor
>>> forest_reg = RandomForestRegressor()
>>> forest_reg.fit(housing_prepared, housing_labels)
>>> [...]
>>> forest_rmse
22542.396440343684
>>> display_scores(forest_rmse_scores)
Scores: [ 53789.2879722 50256.19806622 52521.55342602 53237.44937943
52428.82176158 55854.61222549 52158.02291609 50093.66125649
53240.80406125 52761.50852822]
Mean: 52634.1919593
Standard deviation: 1576.20472269
哇,这好得多:随机森林看起来很有前途。但是,请注意,训练集上的分数仍然比验证集的分数要低很多,这意味着模型仍然对于训练集过拟合。对于过拟合的可能解决方案是简化模型,约束它(即:调整它),或者得到更多的训练数据。然而,在您深入研究随机森林之前,你应该试着从各种机器学习算法中(几种不同内核的支持向量机,也可能是神经网络,等等。)来尝试许多其他的模型。
您应该保存您试验的每个模型,这样您就可以轻松地回退到任何您想要的模型。确保您既保存了超参数,又保存了经过训练的参数,以及交叉验证的分数,也可能是实际的预测。这将允许您轻松地比较不同模型类型的分数,并比较它们所犯的错误类型。您可以通过使用Python的pickle模块轻松地保存Scikit-Learn学习模型,或者也可以使用sklearn.externals.joblib,它在序列化大型NumPy数组时更有效:
from sklearn.externals import joblib joblib.dump(my_model, "my_model.pkl") # and later... my_model_loaded = joblib.load("my_model.pkl")