CrossValidation交叉验证
1. 分割数据集
为了实现一个良好的机器学习模型,我们需要掌握交叉验证的方法,这是检验一个模型是否为优秀的机器学习模型的关键。
我们从经典数据集————红葡萄酒质量数据集开始。
import pandas as pd
df = pd.read_csv("winequality-red.csv")
# 这个数据集您可以在https://www.kaggle.com/datasets/uciml/red-wine-quality-cortez-et-al-2009?resource=download找到
# 根据红葡萄酒的不同属性值,我们可以预测红葡萄酒的质量,这个问题可以被视为分类问题,或者回归问题。
# 简单起见,作者先把它当做 分类问题处理:
# 观察这个数据集,总共有6种质量值,所以我们将所有质量值映射到0-5之间。
# 为了实现这种映射,我们可以创建一个映射字典:
quality_mapping = {
3:0,
4:1,
5:2,
6:3,
7:4,
8:5
}
# 使用pandas提供的map函数以及任何字典来转换给定列中的值为字典中的值
df.loc[:,"quality"] = df.quality.map(quality_mapping)
# 作者认为,分类不应该一开始就用神经网络。我们从决策树开始,这样更简单,并且我们能够可视化结果:
# 我们可以将数据分为两部分,这个数据集有1599个样本,我们保留1000个样本用于训练,599个样本作为一个单独的集合。
# 用frac = 1的sample方法来打乱dataframe
# 由于打乱后索引会改变,所以我们重置索引
df = df.sample(frac=1).reset_index(drop=True)
# 选取前1000行(pandas的head方法)训练(62.5%)
df_train = df.head(1000)
# 选取最后的599行(pandas的tail方法)作为测试/验证数据(37.5%)
df_test = df.tail(599)
2.训练决策树模型
# 使用scikit-learn训练一个决策树模型
from sklearn import tree
from sklearn import metrics
# 初始化一个决策树分类器,设置最大深度为3
clf = tree.DecisionTreeClassifier(max_depth = 3)
# 选择想要训练模型的列
# 作为模型的特征
cols = ['fixed acidity',
'volatile acidity',
'citric acid',
'residual sugar',
'chlorides',
'free sulfur dioxide',
'total sulfur dioxide',
'density',
'pH',
'sulphates',
'alcohol']
# 训练模型:fit方法接受的参数:Feature(X), Label(Y)
clf.fit(df_train[cols],df_train.quality)
- 固定酸度(fixed acidity)
- 挥发性酸度(volatile acidity)
- 柠檬酸(citric acid)
- 残留糖(residual sugar)
- 氯化物(chlorides)
- 游离⼆氧化硫(free sulfur dioxide)
- ⼆氧化硫总量(total sulfur dioxide)
- 密度(density)
- PH 值(pH)
- 硫酸盐(sulphates)
- 酒精(alcohol)
3. 测试模型准确性
# 训练过后,我们开始测试模型准确性
# 在训练集上生成预测
train_predictions = clf.predict(df_train[cols])
# 在测试集上生成预测
test_predictions = clf.predict(df_test[cols])
# 计算训练数据集上预测的准确性
train_accuracy = metrics.accuracy_score(df_train.quality, train_predictions)
# 计算测试数据集上预测的准确性
test_accuracy = metrics.accuracy_score(df_test.quality, test_predictions)
# accuracy_score函数接受参数:https://scikit-learn.org/stable/modules/generated/sklearn.metrics.accuracy_score.html
# 此处为真实标签和预测标签
print(train_accuracy)
print(test_accuracy)
结果:
0.609
0.5358931552587646
打印出来的训练和测试的准确率是会变的,这与原文有一些出入,但训练和测试的准确率的相差变化不大。
4. 绘图
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
# 导入matplotlib和seaborn用于绘图
matplotlib.rc('xtick',labelsize = 20)
matplotlib.rc('ytick',labelsize = 20)
# 确保图表直接在笔记本内显示
%matplotlib inline
# 初始化用于存储训练和测试准确度的列表
# 从50%的准确度开始
train_accuracies = [0.5]
test_accuracies = [0.5]
# 遍历不同的树的深度值
for depth in range(1,25):
# 初始化模型
clf = tree.DecisionTreeClassifier(max_depth = depth)
cols = [
'fixed acidity', 'volatile acidity', 'citric acid',
'residual sugar',
'chlorides',
'free sulfur dioxide',
'total sulfur dioxide',
'density',
'pH',
'sulphates',
'alcohol']
# 在给定特征上拟合模 型
clf.fit(df_train[cols],df_train.quality)
# 创建训练和测试预测
train_predictions = clf.predict(df_train[cols])
# 计算训练和测试准确度
train_accuracy = metrics.accuracy_score(df_train.quality, train_predictions)
test_accuracy = metrics.accuracy_score(df_test.quality, test_predictions)
# 添加准确度到列表
train_accuracies.append(train_accuracy)
test_accuracies.append(test_accuracy)
plt.figure(figsize=(10,5))
sns.set_style("whitegrid")
plt.plot(train_accuracies, label = "train accuracy")
plt.plot(test_accuracies, label = "test accuracy")
plt.legend(loc = "upper left", prop ={'size':15})
plt.xticks(range(0,26,5))
plt.xlabel("max_depth", size = 20)
plt.ylabel("accuracy", size = 20)
plt.show()
原文为最大深度为14时,测试数据的得分最高,但这里的测试集数据得分变动非常不明显,可能是与方法和参数的更新有关。最大深度增加,决策树模型对训练数据的学习效果越来越好,测试数据的性能并不提高。
此即为过拟合,在训练集上完全拟合,但在测试集上表现不好,意味着模型的泛化能力较差。这种方法虽然在测试集上表现为准确率基本不变,但当不算提高训练损失时,测试损失也在增加,这也符合过拟合,而且这是非常常见的。
每当我们训练一个神经网络时,都必须在训练期间监控训练集和测试集的损失。用非常大的网络来处理一个非常小的数据集(样本数非常少),此时训练集和测试集的损失都会减少。但是,在某个时刻,测试损失会达到最小值;之后,训练损失进一步减少,测试损失也会开始增加。必须在验证损失达 到最小值时停止训练。
这符合奥卡姆剃刀原理。
5. 交叉验证
是时候介绍交叉检验了,它是建立一个良好的机器学习模型的最关键步骤(也许是2017年的说法)。什么是交叉检验?
交叉检验是评估模型性能的常用方法。交叉检验是使用训练数据集来训练模型,然后使用测试数据集来评估模型性能。*一轮交叉验证包括将数据样本划分为互补子集,对一个子集(称为训练集)执行分析,并在另一个子集(称为验证集或测试集)上验证分析结果。为了减少可变性,在大多数方法中,使用不同的分区执行多轮交叉验证,并且在这些回合中验证结果被组合(例如,平均)以估计最终的预测模型。(引自:维基百科)*作者使用了暂留集(hold-out set)这种方法:在一部分上训练模型,然后在另一部分上检查其性能。这也是交叉检验的一种。
选择正确的交叉检验取决于所处理的数据集。在一个数据集上适用的交叉检验并不一定就适合别的数据集。
有几种交叉检验技术最为流行和广泛使用:
- k折交叉检验
- 分层k折交叉检验
- 留一交叉检验
- 分组k折交叉检验
交叉检验是将训练数据分层几个部分,在一部分上训练模型,在其余部分上测试。