禁止一切形式转载
书接上文
在这个系列的笔记中,我们正在研究一种受监督的回归机器学习问题。 使用真实的纽约市建筑能源数据,我们希望预测建筑物的能源之星得分并确定影响得分的因素。
机器学习的工作的一般流程
1.数据清理和格式化
2.探索性数据分析
3.特征工程和特征选择
4.在性能指标上比较几种机器学习模型
5.对最佳模型执行超参数调整
6.在测试集合中评估最佳模型
7.解释模型结果
8.得出结论
在Part 1 我们进行了1-3,在Part 2 我们 将进行4-6。重申一遍,在本系列笔记中,我们更多地关注实现而不是细节,即机器学习项目的整个流程是什么,对于那些寻求更多机器学习方法背景的人,我推荐 Hands-On Machine Learning with Scikit-Learn and Tensorflow by Aurelien Geron。 这是算法背后的基本理论以及如何在Python中有效使用它们的优秀资源!
读取数据
在Part 1 最后,我们已经将处理好的数据保存到四个.csv文件中:
training_features.csv
testing_features.csv
training_labels.csv
testing_labels.csv
使用如下代码读取数据:
train_features = pd.read_csv('data/training_features.csv')
test_features = pd.read_csv('data/testing_features.csv')
train_labels = pd.read_csv('data/training_labels.csv')
test_labels = pd.read_csv('data/testing_labels.csv')
# Display sizes of data
print('Training Feature Size: ', train_features.shape)
print('Testing Feature Size: ', test_features.shape)
print('Training Labels Size: ', train_labels.shape)
print('Testing Labels Size: ', test_labels.shape)
Training Feature Size: (6622, 64)
Testing Feature Size: (2839, 64)
Training Labels Size: (6622, 1)
Testing Labels Size: (2839, 1)
4. 在性能指标上比较几种机器学习模型
在本节中,我们将为我们的监督回归任务构建,训练和评估几种机器学习方法。 目标是确定哪个模型最有希望进一步开发(例如超参数调整)。
我们使用平均绝对误差比较模型。 猜测得分中值的基线模型平均偏离25分。
4.1 输入缺失值
标准机器学习模型无法处理缺失值,这意味着我们必须找到一种方法来填充这些缺失值或丢弃任何具有缺失值的特征。 由于我们已经删除了第一部分中缺失值超过50%的要素,因此我们将重点关注这些缺失值,即称为插补 (imputation)的过程。 有许多插补方法,但在这里我们将使用相对简单的方法用列的中位数替换缺失值。(Here is a more thorough discussion on imputing missing values)
4.2 特征缩放
在我们构建模型之前要采取的最后一步是特征缩放(scale the features)。这是必要的,因为要素具有不同的单位,我们希望对要素进行标准化,以使单位不影响算法。线性回归和随机森林不需要特征缩放(Linear Regression and Random Forest do not require feature scaling),但其他方法(例如支持向量机和k-最近邻)确实需要它,因为它们考虑了观测之间的欧氏距离。因此,在比较多个算法时,最佳做法是特征缩放。
有两种特征缩放的方法( normalization and standardization.):
- 对于每个值,减去特征的平均值并除以特征的标准偏差。这称为标准化,并且导致每个特征具有0的均值和1的标准偏差。
- 对于每个值,减去要素的最小值并除以最大值减去要素的最小值(范围)。这可以确保要素的所有值都在0到1之间,并称为缩放到范围或标准化。
这是一篇关于规范化和标准化的好文章。
与插补一样,当我们训练缩放对象时,我们只想使用训练集。当我们转换特征时,我们将转换训练集和测试集。
4.3 要评估的模型
我们将使用伟大的Scikit-Learn库比较五种不同的机器学习模型:
- 线性回归
- 支持向量机回归
- 随机森林回归
- Gradient Boosting 回归
- K-Nearest Neighbors回归
同样,在这里,我专注于实现,而不是解释这些是如何工作的。 除了Hands-On Machine Learning之外,另一个用于阅读机器学习模型的优秀资源 An Introduction to Statistical Learning
为了比较模型,我们将主要使用Scikit-Learn默认的模型超参数值。 通常这些将表现得很好,但应该在实际使用模型之前进行优化。 首先,我们只想确定每个模型的baseline性能,然后我们可以选择性能最佳的模型,以便使用超参数调整进行进一步优化。 请记住,默认的超参数将启动并运行模型,但几乎总是应该使用某种搜索来调整以找到问题的最佳设置!
Here is what the Scikit-learn documentation says about the defaults:
__Sensible defaults__: Whenever an operation requires a user-defined parameter,
an appropriate default value is defined by the library. The default value
should cause the operation to be performed in a sensible way (giving a baseline
solution for the task at hand.)
关于scikit-learn的最好的一点是所有模型都以相同的方式实现:一旦你知道如何构建一个模型,你就可以实现一系列极其多样化的模型。 在这里,我们将在几行代码中实现许多模型的整个训练和测试程序。
# Function to calculate mean absolute error
def mae(y_true, y_pred):
return np.mean(abs(y_true - y_pred))
# Takes in a model, trains the model, and evaluates the model on the test set
def fit_and_evaluate(model):
# Train the model
model.fit(X, y)
# Make predictions and evalute
model_pred = model.predict(X_test)
model_mae = mae(y_test, model_pred)
# Return the performance metric
return model_mae
4.3.1 线性回归
lr = LinearRegression()
lr_mae = fit_and_evaluate(lr)
print('Linear Regression Performance on the test set: MAE = %0.4f' % lr_mae)
4.3.2 支持向量机
svm = SVR(C = 1000, gamma = 0.1)
svm_mae = fit_and_evaluate(svm)
print('Support Vector Machine Regression Performance on the test set: MAE = %0.4f' % svm_mae)
4.3.3 随机森林
random_forest = RandomForestRegressor(random_state=60)
random_forest_mae = fit_and_evaluate(random_forest)
print('Random Forest Regression Performance on the test set: MAE = %0.4f' % random_forest_mae)
4.3.4 Gradient Boosting Regression
gradient_boosted = GradientBoostingRegressor(random_state=60)
gradient_boosted_mae = fit_and_evaluate(gradient_boosted)
print('Gradient Boosted Regression Performance on the test set: MAE = %0.4f' % gradient_boosted_mae)
4.3.5 K-Nearest Neighbors Regression
knn = KNeighborsRegressor(n_neighbors=10)
knn_mae = fit_and_evaluate(knn)
print('K-Nearest Neighbors Regression Performance on the test set: MAE = %0.4f' % knn_mae)
4.4 模型比较
plt.style.use('fivethirtyeight')
figsize(8, 6)
# Dataframe to hold the results
model_comparison = pd.DataFrame({'model': ['Linear Regression', 'Support Vector Machine',
'Random Forest', 'Gradient Boosted',
'K-Nearest Neighbors'],
'mae': [lr_mae, svm_mae, random_forest_mae,
gradient_boosted_mae, knn_mae]})
# Horizontal bar chart of test mae
model_comparison.sort_values('mae', ascending = False).plot(x = 'model', y = 'mae', kind = 'barh',
color = 'red', edgecolor = 'black')
# Plot formatting
plt.ylabel(''); plt.yticks(size = 14); plt.xlabel('Mean Absolute Error'); plt.xticks(size = 14)
plt.title('Model Comparison on Test MAE', size = 20);
根据运行情况(每次精确结果略有变化),梯度增强回归量表现最佳,其次是随机森林。 我不得不承认这不是最公平的比较,因为我们主要使用默认的超参数。 特别是对于支持向量回归器,超参数对性能有重要影响。 (随机森林和梯度增强方法非常适合开始,因为性能较少依赖于模型设置)。 尽管如此,从这些结果中,我们可以得出结论: 机器学习是适用的,因为所有模型都明显 优于基线!
从这里开始,我将专注于使用超参数调优来优化最佳模型。 鉴于此处的结果,我将专注于使用GradientBoostingRegressor。 这是Gradient Boosted Trees的Scikit-Learn实现,在过去的几年中赢得了许多Kaggle competitions。 Scikit-Learn版本通常比XGBoost版本慢,但在这里我们将坚持使用Scikit-Learn,因为语法更为熟悉。 这是在XGBoost包中使用实现的指南Here's a guide。
5. 对最佳模型执行超参数调整--Model Optimization
在机器学习中,优化模型意味着为特定问题找到最佳的超参数集
5.1 Hyperparameters
首先,我们需要了解与模型参数相比,模型超参数是如何定义的:
- 模型超参数被认为最好通过机器学习算法来进行设置,在训练之前由数据科学家调整。 例如,随机森林中的树木数量,或者K-Nearest Neighbors Regression中使用的邻居数量。
- 模型参数是模型在训练期间学习的内容,例如线性回归中的权重。
我们作为数据科学家通过选择超参数来控制模型,这些选择会对模型的最终性能产生显着影响(尽管通常不会像获取更多数据或工程特征那样有效)。
调整模型超参数(Tuning the model hyperparameters)可以控制模型中欠拟合与过拟合的平衡。 我们可以尝试通过制作更复杂的模型来校正欠拟合,例如在随机森林中使用更多树或在深度神经网络中使用更多层。 当我们的模型没有足够的容量(自由度)来学习特征和目标之间的关系时,模型会发生欠拟合并且具有高偏差。 我们可以通过限制模型的复杂性和应用正则化来尝试纠正过度拟合。 这可能意味着降低多项式回归的程度,或将衰退层添加到深度神经网络。 过拟合的模型具有高方差并且实际上记住了训练集。 欠拟合和过拟合导致模型在测试集上的泛化性能变差*。
选择超参数的问题在于,没有放之四海而皆准的超参数。 因此,对于每个新数据集,我们必须找到最佳设置。 这可能是一个耗时的过程,但幸运的是,在Scikit-Learn中执行此过程有多种选择。 更好的是,新的libraries,如epistasis实验室的TPOT,旨在为您自动完成此过程! 目前,我们将坚持在Scikit-Learn中手动(有点)这样做,但请继续关注自动模型选择的文章!
5.2 随机搜索和交叉验证的超参数调整
我们可以通过随机搜索和交叉验证为模型选择最佳超参数。
随机搜索是指我们选择超参数来评估的方法:我们定义一系列选项,然后随机选择要尝试的组合。这与网格搜索形成对比,在网格搜索评估,我们指定每个组合。通常,当我们对最佳模型超参数的知识有限时,随机搜索会更好,我们可以使用随机搜索缩小选项范围,然后使用更有限的选项范围进行网格搜索。
交叉验证是用于评估超参数性能的方法。我们使用K-Fold交叉验证,而不是将训练设置拆分为单独的训练和验证集,以减少我们可以使用的训练数据量。这意味着将训练数据划分为K个折叠,然后进行迭代过程,我们首先在折叠的K-1上进行训练,然后评估第K个折叠的性能。我们重复这个过程K次,所以最终我们将测试训练数据中的每个例子,关键是每次迭代我们都在测试我们之前没有训练过的数据。在K-Fold交叉验证结束时,我们将每个K次迭代的平均误差作为最终性能度量,然后立即在所有训练数据上训练模型。然后,我们记录的性能用于比较超参数的不同组合。
A picture of k-fold cross validation using k = 5 is shown below:
在这里,我们将使用交叉验证实现随机搜索,以选择gradient boosting regressor的最佳超参数。 我们首先定义一个网格然后执行迭代过程:从网格中随机抽样一组超参数,使用4倍交叉验证评估超参数,然后选择具有最佳性能的超参数。
Loss function to be optimized
Number of trees used in the boosting process
Maximum depth of each tree
Minimum number of samples per leaf
Minimum number of samples to split a node
Maximum number of features to consider for making splits
我们选择了6个不同的超参数来调整梯度增强回归量。 这些都将以不同的方式影响模型,这些方法很难提前确定,找到特定问题的最佳组合的唯一方法是测试它们! 要了解超参数,我建议您查看(Scikit-Learn documentation)文档。 现在,只要知道我们正在努力寻找超参数的最佳组合,并且因为没有理论告诉我们哪种方法效果最好,我们只需要评估它们,就像运行实验一样!
这部分剩下的内容可以去看jupyter notebook, 上面给出了详细步骤
6. 在测试集合中评估最佳模型
我们将使用超参数调整中的最佳模型来对测试集进行预测。 请记住,我们的模型之前从未见过测试集,所以这个性能应该是模型在现实世界中部署时的表现的一个很好的指标。
最终的模型比基线模型的性能提高了大约10%,但代价是显着增加了运行时间(在我的机器上慢了大约12倍)。 机器学习通常是一个权衡领域:偏差与方差,准确性与可解释性,准确性与运行时间,以及使用哪种模型的最终决定取决于具体情况。 这里,运行时间的增加不是障碍,因为虽然相对差异很大,但训练时间的绝对量值并不显着。 在不同的情况下,平衡可能不一样,因此我们需要考虑我们正在优化的内容以及我们必须使用的限制。
总结
在个笔记中,我们介绍了机器学习流程中的关键概念:
- 输入缺失值
- 评估和比较几种机器学习方法
- 超参数使用随机搜索和交叉验证来调整机器学习模型
- 评估测试集上的最佳模型
结果表明,机器学习适用于我们的问题,最终模型能够将建筑物的能源之星得分预测到9.1分以内。我们还看到,超级参数调整能够改善模型的性能,尽管在投入的时间方面成本相当高。这是一个很好的提醒,正确的特征工程和收集更多数据(如果可能!)比微调模型有更大的回报。我们还观察了运行时与精度之间的权衡,这是我们在设计机器学习模型时必须考虑的众多因素之一。
我们知道我们的模型是准确的,但我们知道为什么它能做出预测?机器学习过程的下一步至关重要:尝试理解模型如何进行预测。实现高精度是很好的,但如果我们能够找出模型能够准确预测的原因,那么我们也可以使用这些信息来更好地理解问题。例如,模型依靠哪些功能来推断能源之星得分?可以使用此模型进行特征选择,并实现更易于解释的更简单模型吗?
在下一个也是最后一个笔记中,我们将尝试回答这些问题并从项目中得出最终结论!