Kaggle-Intermediate Machine Learning(3)
Cross-validation
机器学习是一个反复的过程。
您将面临选择使用哪些预测变量,使用哪种类型的模型,向这些模型提供哪些参数的选择。到目前为止,您已经通过数据验证和评估模型质量以数据驱动的方式做出了这些选择(或保持)。
但是这种方法有一些缺点。要看到这一点,假设您有一个包含5000行的数据集。通常,您将保留约20%的数据作为验证数据集或1000行。但这在确定模型分数方面留下了一些随机的机会。也就是说,即使在不同的1000行上模型都不准确,模型也可能在一组1000行上表现良好。
在极端情况下,您可以想象验证集中只有1行数据。如果您比较其他模型,那么在单个数据点上做出最佳预测的模型将很幸运!
通常,验证集越大,我们的模型质量度量中的随机性(即“噪声”)就越少,并且可靠性也就越高。不幸的是,我们只能通过从训练数据中删除行来获得较大的验证集,而较小的训练数据集则意味着模型更差!
什么是交叉验证?
在交叉验证中,我们对数据的不同子集运行建模过程,以获取模型质量的多种度量。
例如,我们可以将数据分为5个部分,每个部分占整个数据集的20%。 在这种情况下,我们说我们已经将数据分为5个“折叠”。
然后,我们对每一折进行一个实验:
1.在实验1中,我们将第一折用作验证(或保留)集,并将其他所有内容用作训练数据。 这为我们提供了基于20%保留集的模型质量度量。
2.在实验2中,我们从第二次折叠中保留数据(并使用第二次折叠以外的所有数据来训练模型)。 然后使用保留集来获得模型质量的第二个估计值。
3.我们重复此过程,每折叠一次作为保留集。 放在一起,在某些时候将100%的数据用作保留,并且我们最终得出的模型质量度量是基于数据集中的所有行(即使我们不同时使用所有行)
什么时候应该使用交叉验证?
交叉验证可以更准确地衡量模型质量,这在您做出大量建模决策时尤其重要。 但是,它可能需要更长的时间才能运行,因为它会估计多个模型(每折一个)。
因此,考虑到这些折衷,您应何时使用每种方法?
对于较小的数据集,不需要太多的计算负担,则应运行交叉验证。
对于较大的数据集,单个验证集就足够了。 您的代码将运行得更快,并且您可能拥有足够的数据,因此几乎不需要将其中的一些数据重新用于保留。
对于组成大型数据集还是小型数据集没有简单的阈值。 但是,如果您的模型需要花费几分钟或更短的时间来运行,则可能值得切换到交叉验证。
另外,您可以运行交叉验证,看看每个实验的分数是否接近。 如果每个实验产生相同的结果,则单个验证集可能就足够了。
Example
我们将使用与上一教程中相同的数据。 我们将输入数据加载到X中,将输出数据加载到y中。然后,我们定义一个管道,该管道使用imputer填写缺失值,并使用随机森林模型进行预测。尽管无需管道就可以进行交叉验证,但这非常困难! 使用管道会使代码非常简单。
from sklearn.ensemble import RandomForestRegressor from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer my_pipeline = Pipeline(steps=[('preprocessor', SimpleImputer()), ('model', RandomForestRegressor(n_estimators=50, random_state=0)) ])
我们使用scikit-learn中的cross_val_score()函数获得交叉验证分数。 我们使用cv参数设置折数(k)。
from sklearn.model_selection import cross_val_score # Multiply by -1 since sklearn calculates *negative* MAE scores = -1 * cross_val_score(my_pipeline, X, y, cv=5, scoring='neg_mean_absolute_error') print("MAE scores:\n", scores)
MAE scores:
[301628.7893587 303164.4782723 287298.331666 236061.84754543
260383.45111427]
评分参数选择要报告的模型质量的量度:在这种情况下,我们选择负平均绝对误差(MAE)。 scikit-learn的文档显示了选项列表。
我们指定负MAE有点令人惊讶。 Scikit-learn有一个约定,其中定义了所有指标,因此数量越多越好。 在这里使用负值可以使它们与该约定保持一致,尽管负MAE在其他地方几乎闻所未闻。
我们通常希望对模型质量进行单一衡量,以比较其他模型。 因此,我们将整个实验取平均值。
print("Average MAE score (across experiments):") print(scores.mean())
Output:
Average MAE score (across experiments):
277707.3795913405
使用交叉验证可更好地衡量模型质量,并具有清理代码的额外好处:请注意,我们不再需要跟踪单独的训练和验证集。 因此,尤其对于小型数据集,这是一个很好的改进!
练习
到目前为止,您已经学习了如何使用scikit-learn构建管道。 例如,在使用RandomForestRegressor()训练随机森林模型进行预测之前,下面的管道将使用SimpleImputer()替换数据中的缺失值。 我们使用n_estimators参数设置随机森林模型中的树数,并设置random_state确保可重复性。
from sklearn.ensemble import RandomForestRegressor from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer my_pipeline = Pipeline(steps=[ ('preprocessor', SimpleImputer()), ('model', RandomForestRegressor(n_estimators=50, random_state=0)) ])
您还学习了如何在交叉验证中使用管道。 下面的代码使用cross_val_score()函数来获取平均绝对误差(MAE),该误差在五个不同的折叠中平均。 回想一下,我们使用cv参数设置了折数。
from sklearn.model_selection import cross_val_score # Multiply by -1 since sklearn calculates *negative* MAE scores = -1 * cross_val_score(my_pipeline, X, y, cv=5, scoring='neg_mean_absolute_error') print("Average MAE score:", scores.mean())
Step 1: Write a useful function
在本练习中,您将使用交叉验证为机器学习模型选择参数。
首先编写一个函数get_score(),该函数报告使用以下内容的机器学习管道的平均(三个交叉验证折叠)MAE:
X和y中的数据以创建折叠,
SimpleImputer()(保留所有默认参数)以替换缺少的值,以及
RandomForestRegressor()(其中random_state = 0)适合随机森林模型。
设置随机森林模型中的树数时,将使用提供给get_score()的n_estimators参数。
def get_score(n_estimators): """Return the average MAE over 3 CV folds of random forest model. Keyword argument: n_estimators -- the number of trees in the forest """ # Replace this body with your own code # pass my_pipeline = Pipeline(steps=[ ('preprocessor', SimpleImputer()), ('model', RandomForestRegressor(n_estimators, random_state=0))]) scores = -1 * cross_val_score(my_pipeline, X, y, cv=3, scoring='neg_mean_absolute_error') print(scores) return scores.mean() # Check your answer step_1.check()
Step 2: Test different parameter values
现在,您将使用在步骤1中定义的函数来评估与随机森林中的树数的八个不同值相对应的模型性能:50、100、150,...,300、350、400。
将结果存储在Python字典结果中,其中results [i]是get_score(i)返回的平均MAE。
results = {} # Your code here for i in range(50,401,50): results[i]=get_score(i) # Check your answer step_2.check()
Output:
[18414.4198768 17950.8061191 18696.29205761] [18431.44531143 17816.34640657 18937.85378601] [18243.49104266 17661.60951403 18961.08950617] [18245.33884668 17671.76715606 18827.93166667] [18282.77936756 17578.16626694 18904.86203292] [18251.90511294 17600.66503765 18973.15561728] [18245.98694241 17586.13852156 18978.75003527] [18245.06112423 17553.22719713 19012.30560185]
Step 3: Find the best parameter value
使用下一个单元格来可视化步骤2的结果。运行代码而无需进行任何更改
根据结果,对于随机森林模型,n_estimators的哪个值似乎最合适? 使用您的答案来设置n_estimators_best的值。
import matplotlib.pyplot as plt %matplotlib inline plt.plot(list(results.keys()), list(results.values())) plt.show()
明显是n_estimators树的数目为200时MAE最小,
n_estimators_best = 200 # Check your answer step_3.check()
在本练习中,您探索了一种在机器学习模型中选择适当参数的方法。
如果您想了解有关超参数优化的更多信息,建议您从网格搜索开始,这是一种确定机器学习模型的最佳参数组合的直接方法。 幸运的是,scikit-learn还包含一个内置函数GridSearchCV(),可以使您的网格搜索代码非常高效在本练习中,您探索了一种在机器学习模型中选择适当参数的方法。