【交叉验证代码教程】
一、交叉验证的概念
交叉验证是一种在机器学习中广泛应用的评估技术,主要用于评估模型的泛化能力和性能。 交叉验证(Cross-validation)是一种将数据集分割成多个小部分,然后多次对模型进行训练和验证的过程。通过多次进行这个过程,可以评估模型的泛化性能和稳定性。
注:上面所说的"模型的泛化能力"、"模型的稳定性"可能对一些读者来说比较难理解。
(1)"模型的泛化能力":机器学习的“泛化”能力是指机器学习算法对"新鲜样本"的适应能力。这种能力使得机器学习模型在面对新数据时,能够更好地适应并做出准确的预测。
(2)"模型的稳定性":是指模型对于输入数据的变化的响应程度。如果模型对于不同的输入数据变化能够产生相对一致的输出结果,那么这个模型就被认为是稳定的。
如果对"泛化"和"稳定性"这两个概念还不太了解,也没有关系,其实不影响对下面内容的阅读和理解
二、交叉验证的实现方法
下面介绍2种常见的交叉验证方法:
(1)留出交叉验证(Leave-one-out cross-validation): 每次选择一个样本作为测试集,剩下的样本作为训练集,然后进行模型训练和测试。在所有样本都被选作测试集之后,可以计算出模型的平均性能指标。
(2)k折交叉验证(k-fold cross-validation): 将数据集分成k个子集,每次选择k-1个子集作为训练集,剩下的一个子集作为验证集。这种方法的好处是可以在较短的时间内完成验证,适用于大规模数据集。
三、案例分析
下面将以一个简单的例子讲解上面这三种交叉验证的方法。
我们的数据来源于英雄联盟S12。result指的是比赛的胜负,FAC1指的是队伍在比赛中的技战术指标。我们要用这6个FAC1来预测比赛的胜负result。
样本一共有10个,样本的序号我们设为0-1-2-3-4-5-6-7-8-9
3.1 进行留出交叉验证法
用上面的10个样本数据做机器学习的模型。在这种情况下,要进行10次的模型训练和测试。 下面的数字代表的样本序号(0-9)。
第01次: 训练集为0-1-2-3-4-5-6-7-8 测试集为9
第02次: 训练集为1-2-3-4-5-6-7-8-9 测试集为0
第03次: 训练集为2-3-4-5-6-7-8-9-0 测试集为1
第04次: 训练集为3-4-5-6-7-8-9-0-1 测试集为2
第05次: 训练集为4-5-6-7-8-9-0-1-2 测试集为3
第06次: 训练集为5-6-7-8-9-0-1-2-3 测试集为4
第07次: 训练集为6-7-8-9-0-1-2-3-4 测试集为5
第08次: 训练集为7-8-9-0-1-2-3-4-5 测试集为6
第09次: 训练集为8-9-0-1-2-3-4-5-6 测试集为7
第10次: 训练集为9-0-1-2-3-4-5-6-7 测试集为8
3.2 k折交叉验证法(shuffle=False)
用上面的10个样本数据做机器学习的模型。在这种情况下,要进行k次的模型训练和测试。而k是我们自己设定的,在这里我们设定为5(即下面代码的n_splits=5)。
kf = KFold(n_splits=5, shuffle=False) -- 这是一段进行k折交叉验证中的python代码
shuffle=False即"数据分成5份"时是不是随机分的,而是按照原有的样本序号分的; "shuffle"的英文意思是"洗牌; 洗(牌); 拖着脚走; 坐立不安; 把(纸张等)变换位置,打乱次序"
k折交叉验证法(shuffle=False)实现的效果如下:
第01次: 训练集为0-1-2-3-4-5-6-7 测试集为8-9
第02次: 训练集为2-3-4-5-6-7-8-9 测试集为0-1
第03次: 训练集为4-5-6-7-8-9-0-1 测试集为2-3
第04次: 训练集为6-7-8-9-0-1-2-3 测试集为4-5
第05次: 训练集为8-9-0-1-2-3-4-5 测试集为6-7
注:上面的数字代表的样本序号(0-9)。
3.3 k折交叉验证法(shuffle=True)
用上面的10个样本数据做机器学习的模型。在这种情况下,要进行k次的模型训练和测试。而k是我们自己设定的,在这里我们设定为5(即下面代码的n_splits=5)。
kf = KFold(n_splits=5, shuffle=True) -- 这是一段进行k折交叉验证中的python代码
shuffle=True即"数据分成5份"时是随机分的; "shuffle"的英文意思是"洗牌; 洗(牌); 拖着脚走; 坐立不安; 把(纸张等)变换位置,打乱次序"
k折交叉验证法(shuffle=True)实现的效果如下:
第01次: 训练集为0-1-3-4-5-6-7-8 测试集为2-9
第02次: 训练集为1-2-3-5-6-7-8-9 测试集为0-4
第03次: 训练集为0-1-2-4-6-7-8-9 测试集为3-5
第04次: 训练集为0-2-3-4-5-7-8-9 测试集为1-6
第05次: 训练集为0-1-2-3-4-5-6-9 测试集为7-8
注:上面的数字代表的样本序号(0-9)。
四、"k折"交叉验证具体代码实现
01 导入库
>引入库函数
import pandas as pd
import numpy as np
>导入进行模型训练与测试前的进行数据处理的库
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
>导入逻辑回归模型的库(linear_model字面理解是线性模型的意思)
from sklearn.linear_model import LogisticRegression
>导入“集成学习”的库(集成学习(ensemble learning),并不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器(基学习器,Base learner)来完成学习任务。)
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
>导入含机器学习评价函数的库
from sklearn import metrics
>导入含混淆矩阵的库
from sklearn.metrics import confusion_matrix
>导入机器学习的评价指标准确率、精确率、召回率、F1值
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
>导入做ROC曲线的库
from sklearn.metrics import roc_curve, auc, roc_auc_score
from sklearn.metrics import mean_squared_error
>导入作图的库
import matplotlib.pyplot as plt
02 获取数据源并整理数据
(数据集可在此获取:机器学习交叉验证教程 - 飞桨AI Studio星河社区 (baidu.com))
data = pd.read_excel('/home/mw/input/data2157/data.xlsx')
data_np = np.array(data)
data_np[np.array([0,1,2,3])]
运行结果:
>查看前几行数据
data.head()
数据解释:result是胜负结果;FAC1_1等是通过主成分分析后得到的技战术指标
>使用loc函数进行数据获取
data.loc[0:1,"FAC1_1":"FAC1_2"]
运行结果:
>使用iloc函数进行数据获取
03 对数据集进行7次“训练”和“测试”
> 使用KFold设定交叉验证的参数
(n_splits=7即把数据分成7份,也是要进行7次的"训练"和"测试"; shuffle=True即"数据分成7份"时是随机分的;random=40,按正常的理解,应该是"random_state=40指定随机数生成器的种子")
kf = KFold(n_splits=7, shuffle=True, random_state=40)
>创建一个全是1的7×5的矩阵
evaluate_matrix = np.ones([7,5])
>用i来表明是第几次的交叉验证;从0开始计数
i = 0
>使用kf.split( )这个函数进行数据的划分
(在每一次循环的"train_index"、"test_index"都是不一样的 ; "train_index"指的是第i次训练和测试时的训练集数据的行索引; "train_index"指的是第i次训练和测试时的测试集数据的行索引)
for train_index, test_index in kf.split(data):
# 逻辑回归实现部分
# 根据"train_index"、"test_index"获取每一次的训练和测试时的训练集数据和测试集数据
# 此处是用data_np(numpy的array数据类型)来获取训练集和测试集,不是用data(pandas的DataFrame数据类型)
train_data_LR = data_np[train_index]
test_data_LR = data_np[test_index]
# 如果用data_np(pandas的DataFrame数据类型)来获取训练集和测试集的话,会报错,所以要用data_np(numpy的array数据类型)来获取训练集和测试集
# train_data = data[train_index]
# test_data = data[test_index]
# 每次都要重新创建一个逻辑回归模型的"空盒子",里面没有设定参数
lr=LogisticRegression()
# 使用lr的对象函数fit()进行训练
lr.fit(train_data_LR[:, 1:], train_data_LR[:,0])
# 使用使用lr的对象函数predict()进行比赛结果的预测(要么是预测成1(获胜),要么预测成0(失败))
predictions = lr.predict(test_data_LR[:, 1:])
# 使用使用lr的对象函数predict_proba获取预测成1的概率(如果该概率大于等于0.5则预测成1(获胜),反之则预测成0(失败))
predictions_proba = lr.predict_proba(test_data_LR[:, 1:])
# 查看每一次的训练与测试时的模型系数
print("变量前的系数是:{0}".format(lr.coef_))
print("常系数是:{0}".format(lr.intercept_))
# 使用accuracy_score、precision_score、recall_score、f1_score来获取每一次训练和测试中的准确率、精确率、召回率、F1值
print('逻辑回归分类 Accuracy:{0}'.format(accuracy_score(test_data_LR[:,0], predictions)))
print('逻辑回归分类 Precision:{0}'.format(precision_score(test_data_LR[:,0], predictions)))
print('逻辑回归分类 Recall_rate:{0}'.format(recall_score(test_data_LR[:,0], predictions)))
print('逻辑回归分类 F1_Value:{0}'.format(f1_score(test_data_LR[:,0], predictions)))
# fpr的取名逻辑可以理解成"false positive rate", tpr的取名逻辑可以理解成"true positive rate"
fpr, tpr, thresholds = metrics.roc_curve(test_data_LR[:,0], predictions_proba[:,1], pos_label=1)
# 根据fpr,tpr可以算出一个auc的模型评价指标,即auc_roc_LR
auc_roc_LR = metrics.auc(fpr,tpr)
print('逻辑回归分类 ROC_AUC:{0}'.format(auc_roc_LR))
#关于ROC曲线,AUC,"false positive rate","true positive rate"的概念,在这里暂不解释,有兴趣的可以自行找资料进行学习#
# 评价指标的收集
evaluate_matrix[i][0] = accuracy_score(test_data_LR[:,0], predictions)
evaluate_matrix[i][1] = precision_score(test_data_LR[:,0], predictions)
evaluate_matrix[i][2] = recall_score(test_data_LR[:,0], predictions)
evaluate_matrix[i][3] = f1_score(test_data_LR[:,0], predictions)
evaluate_matrix[i][4] = auc_roc_LR
# 画出ROC曲线
plt.figure()
lw = 2
# plot函数中的lw参数的英文逻辑是line width,指的是线的粗度
plt.plot(fpr, tpr, color="darkorange", lw=lw, label="ROC curve (area = %0.2f)" % auc_roc_LR,)
plt.plot([0, 1], [0, 1], color="navy", lw=lw, linestyle="--")
# 设置x轴和y轴的最大取值范围,lim指的就是limit
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
# 给x轴和y轴取名
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve for {0} ".format(i+1))
# 数值图标显示的位置,这里把图标设置成右下角,即"lower right"
plt.legend(loc="lower right")
# 把图形显示出来
plt.show()
# 对
i+=1
# 查看这7次的训练和测试中每一次的评价指标数值
print(evaluate_matrix)
运行结果:
- 第1次:
- 第2次:
- 第3次:
- 第4次:
- 第5次:
- 第6次:
- 第7次: