import pandas as pddf = pd . read_csv ( "winequality-red.csv" )
quality_mapping = {
3: 0,
4: 1,
5: 2,
6: 3,
7: 4,
8: 5
}
df.loc[:, "quality"] = df.quality.map(quality_mapping)
df = df.sample(frac=1).reset_index(drop=True)
df_train = df.head(1000)
df_test = df.tail(599)
现在,我们将在训练集上使⽤scikit-learn训练⼀个决策树模型。
from sklearn import tree
from sklearn import metrics
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']
clf.fit(df_train[cols], df_train.quality)
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
)
from sklearn import tree
from sklearn import metrics
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
# 设置 matplotlib 字体大小
matplotlib.rc('xtick', labelsize=20)
matplotlib.rc('ytick', labelsize=20)
# 用于在 Jupyter Notebook 中显示图形
%matplotlib inline
# 初始化训练集和测试集的准确率列表
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])
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)
# 将准确率添加到列表中
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()
这将⽣成如图 2 所⽰的曲线图。
import pandas as pd
from sklearn import model_selection
if __name__ == "__main__":
# 读取训练数据集
df = pd.read_csv("train.csv")
# 创建一个新列 "kfold" 并初始化为 -1
df["kfold"] = -1
# 随机打乱数据集
df = df.sample(frac=1).reset_index(drop=True)
# 初始化 KFold 分割器,将数据集分成 5 折
kf = model_selection.KFold(n_splits=5)
# 遍历每一折并为相应的样本分配折叠索引
for fold, (trn_, val_) in enumerate(kf.split(X=df)):
df.loc[val_, 'kfold'] = fold
# 将带有折叠索引的数据集保存为 CSV 文件
df.to_csv("train_folds.csv", index=False)
import pandas as pd
from sklearn import model_selection
if __name__ == "__main__":
# 读取训练数据集
df = pd.read_csv("train.csv")
# 创建一个新列 "kfold" 并初始化为 -1
df["kfold"] = -1
# 随机打乱数据集
df = df.sample(frac=1).reset_index(drop=True)
# 提取目标变量列
y = df.target.values
# 初始化 StratifiedKFold 分割器,将数据集分成 5 折,并保持目标变量的分布相同
kf = model_selection.StratifiedKFold(n_splits=5)
# 遍历每一折并为相应的样本分配折叠索引
for fold, (train_idx, val_idx) in enumerate(kf.split(X=df, y=y)):
df.loc[val_idx, 'kfold'] = fold
# 将带有折叠索引的数据集保存为 CSV 文件
df.to_csv("train_folds.csv", index=False)
对于葡萄酒数据集,我们来看看标签的分布情况。
b = sns . countplot ( x = 'quality' , data = df )b . set_xlabel ( "quality" , fontsize = 20 )b . set_ylabel ( "count" , fontsize = 20 )
请注意,我们继续上⾯的代码。因此,我们已经转换了⽬标值。从图 6 中我们可以看出,质量偏差很⼤。有些类别有很多样本,有些则没有那么多。如果我们进⾏简单的k折交叉检验,那么每个折叠中的⽬标值分布都不会相同。因此,在这种情况下,我们选择分层 k 折交叉检验。
规则很简单,如果是标准分类问题,就盲⽬选择分层k折交叉检验。
但如果数据量很⼤,该怎么办呢?假设我们有 100万个样本。5倍交叉检验意味着在 800k 个样本 上进⾏训练,在 200k 个样本上进⾏验证。根据我们选择的算法,对于这样规模的数据集来说, 训练甚⾄验证都可能⾮常昂贵。在这种情况下,我们可以选择暂留交叉检验。
创建保持结果的过程与分层 k 折交叉检验相同。对于拥有 100 万个样本的数据集,我们可以创建 10 个折叠⽽不是 5 个,并保留其中⼀个折叠作为保留样本。这意味着,我们将有 10 万个样本被 保留下来,我们将始终在这个样本集上计算损失、准确率和其他指标,并在 90 万个样本上进训练。
在处理时间序列数据时,暂留交叉检验也⾮常常⽤。假设我们要解决的问题是预测⼀家商店 2020 年的销售额,⽽我们得到的是 2015-2019 年的所有数据。在这种情况下,你可以选择 2019 年的 所有数据作为保留数据,然后在 2015年⾄ 2018 年的所有数据上训练你的模型。
其中 是数据集中的样本数。该函数如图8所⽰。
import numpy as np
import pandas as pd
from sklearn import datasets
from sklearn import model_selection
def create_folds(data):
# 初始化新列 "kfold" 并将其全部赋值为 -1
data["kfold"] = -1
# 随机打乱数据集
data = data.sample(frac=1).reset_index(drop=True)
# 计算分箱数量
num_bins = int(np.floor(1 + np.log2(len(data))))
# 将目标变量分到对应的分箱中
data.loc[:, "bins"] = pd.cut(
data["target"], bins=num_bins, labels=False
)
# 初始化 StratifiedKFold 分割器,保持分箱后的分布相同
kf = model_selection.StratifiedKFold(n_splits=5)
# 遍历每一折并为相应的样本分配折叠索引
for fold, (train_idx, val_idx) in enumerate(kf.split(X=data, y=data.bins.values)):
data.loc[val_idx, 'kfold'] = fold
# 删除创建的分箱列
data = data.drop("bins", axis=1)
return data
if __name__ == "__main__":
# 生成模拟数据
X, y = datasets.make_regression(
n_samples=15000, n_features=100, n_targets=1
)
# 将模拟数据转换为 DataFrame 格式
df = pd.DataFrame(
X,
columns=[f"f_{i}" for i in range(X.shape[1])]
)
# 将目标变量添加到 DataFrame 中
df.loc[:, "target"] = y
# 使用 create_folds 函数创建带有折叠索引的数据集
df = create_folds(df)