Task05:模型搭建和评估

模型搭建和评估

建模

切割训练集和测试集

在进行有监督模型实际模型训练前,需要先将数据划分为训练集和测试集,其中训练集用于训练有监督模型,调整参数,对算法进行其他调整等;测试集用于评估训练出的模型效果,验证模型是否过拟合或欠拟合,决定是否重新训练模型或选择其他算法。

scikit-learn 中切割数据集的方法为 train_test_split

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)

常用参数:

参数 说明
X, y 自变量和因变量
test_size 测试集在数据中的占比,默认 0.25
random_state 随机数种子,设置此参数必须 shuffle
shuffle 切分前是否对数据进行打乱,默认打乱
stratify 设置分层抽样

逻辑回归模型

Logistic Regression 虽然被称为回归,但其实际上是分类模型,并常用于二分类。在 scikit-learn 中,LogisticRegression 用于逻辑回归:

from sklearn.linear_model import LogisticRegression

LogisticRegression 常用的方法:

方法 说明
fit 根据给定的训练数据拟合模型
predict 预测样本的类别标签
predict_proba 获取每个值的概率估计
score 返回平均准确度

Titanic 数据集中使用 fit 训练模型,使用 score 返回平均准确度:

lr1 = LogisticRegression().fit(X_train, y_train)
print(f'训练集得分: {lr1.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr1.score(X_test, y_test):.4f}')

LogisticRegression 模型的参数进行调整:

参数 说明
penalty 指定惩罚规范,默认 ‘L2’
C 正则强度的倒数,越小正则化越强,默认 1
class_weight 设置类别的权重
max_iter 最大迭代次数,默认 100

Titanic 数据集对逻辑回归函数的参数进行调整测试:

# 调小 C 值
lr2 = LogisticRegression(C=0.01).fit(X_train, y_train)
print(f'训练集得分: {lr2.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr2.score(X_test, y_test):.4f}')

# 调大 C 值
lr3 = LogisticRegression(C=1000).fit(X_train, y_train)
print(f'训练集得分: {lr3.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr3.score(X_test, y_test):.4f}')

# 调整类别权重
lr4 = LogisticRegression(class_weight='balanced').fit(X_train, y_train)
print(f'训练集得分: {lr4.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr4.score(X_test, y_test):.4f}')

# 调小最大迭代次数
lr5 = LogisticRegression(max_iter=20).fit(X_train, y_train)
print(f'训练集得分: {lr5.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr5.score(X_test, y_test):.4f}')

# 调大最大迭代次数
lr6 = LogisticRegression(max_iter=500).fit(X_train, y_train)
print(f'训练集得分: {lr6.score(X_train, y_train):.4f}')
print(f'测试集得分: {lr6.score(X_test, y_test):.4f}')

Titanic 数据集逻辑回归模型中各参数对训练得分的影响:

  1. C 调小后正则化变强,模型复杂程度降低,得分下降,模型会出现欠拟合;C 调大后正则化弱,模型复杂程度增加,但得分提升有限;
  2. 设置 class_weight='balanced' 后得分有所下降;
  3. 减少最大迭代次数后,模型复杂程度降低,得分下降,模型会出现欠拟合;增加最大迭代次数,得分没有发生变化,说明模型的迭代次数没有超过默认值 100。

predict()predict_proba() 分别用于获取预测值和预测值的概率:

lr1.predict(X_test), lr1.predict_proba(X_test)

随机森林模型

随机森林模型建立多个决策树,当需要对某个样本进行预测时,统计森林中的每棵树对该样本的预测结果,然后通过投票法从这些预测结果中选出最后的结果。随机体现在两个方面,一个是随机取特征,另一个是随机取样本,让森林中的每棵树既有相似性又有差异性。在 scikit-learn 中,RandomForestClassifier 用于随机森林模型:

from sklearn.ensemble import RandomForestClassifier

Titanic 数据集中使用默认参数的随机森林模型:

rf1 = RandomForestClassifier().fit(X_train, y_train)
print(f'训练集得分: {rf1.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf1.score(X_test, y_test):.4f}')

随机森林模型中几个常用的调整参数:

参数 说明
n_estimators 森林中树木的数量
max_depth 树的最大深度,默认无限制
max_features 构建决策树最优模型时考虑的最大特征数
bootstrap 是否放回抽样
oob_score 是否使用袋外样本来评价模型的好坏

Titanic 数据集对随机森林模型的参数进行调整测试:

# 调小 n_estimators
rf2 = RandomForestClassifier(n_estimators=10).fit(X_train, y_train)
print(f'训练集得分: {rf2.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf2.score(X_test, y_test):.4f}')

# 调大 n_estimators
rf3 = RandomForestClassifier(n_estimators=500).fit(X_train, y_train)
print(f'训练集得分: {rf3.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf3.score(X_test, y_test):.4f}')

# 限制最大深度为 10
rf4 = RandomForestClassifier(max_depth=10).fit(X_train, y_train)
print(f'训练集得分: {rf4.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf4.score(X_test, y_test):.4f}')

# 不放回抽样
rf5 = RandomForestClassifier(bootstrap=False).fit(X_train, y_train)
print(f'训练集得分: {rf5.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf5.score(X_test, y_test):.4f}')

# 使用袋外样本
rf6 = RandomForestClassifier(oob_score=True).fit(X_train, y_train)
print(f'训练集得分: {rf6.score(X_train, y_train):.4f}')
print(f'测试集得分: {rf6.score(X_test, y_test):.4f}')

Titanic 数据集随机森林模型中各参数对训练得分的影响:

  1. n_estimators 变小,则模型复杂度降低,得分降低,模型容易欠拟合;n_estimators 变大,则模型复杂度增加,性能显著下降,得分有所上升,但在该数据集中上升不明显;
  2. 限制最大深度后模型复杂度降低,得分下降,模型容易欠拟合,但性能提升。因为该数据集样本较少,性能要求不高,无需限制最大深度;
  3. 如果不放回抽样,每棵树用的样本完全不同,结果是有偏的,基学习器之间的相似性小,投票结果差,模型偏差大。在该数据集中,是否放回抽样影响不大;
  4. 使用袋外样本来评价模型的好坏可以增加模型的泛化能力。在该数据集中,这一参数的影响不大。

predict()predict_proba() 分别用于获取预测值和预测值的概率,用法和逻辑回归一样:

rf1.predict(X_test), rf1.predict_proba(X_test)

评估

模型评估是对模型的泛化能力进行评估,一方面可以从实验角度进行比较,如交叉验证等;另一方面可以利用具体的性能评价标准,如测试集准确率等。

交叉验证

交叉验证就是重复地使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏。其中,最常用的交叉验证方法是 k 折交叉验证。该方法将数据划分为等量的 k 份,每次 k-1 份用于训练模型,1 份用于测试,重复 k 次。

在 scikit-learn 中,使用 k 折交叉验证的方法为:

from sklearn.model_selection import cross_val_score
cross_val_score()

cross_val_score() 主要参数为:

参数 说明
estimator 训练模型
X, y 自变量和因变量
cv 切分策略,默认 5 折

Titanic 数据集对逻辑回归模型和随机森林模型分别使用 10 折交叉验证法:

from sklearn.model_selection import cross_val_score
lr = LogisticRegression()
rf = RandomForestClassifier()
print(cross_val_score(lr, X, y, cv=10).mean())
print(cross_val_score(rf, X, y, cv=10).mean())

从验证结果来看,Titanic 数据集中,随机森林模型的效果比逻辑回归模型要好。

在 k 折交叉验证法下,一般情况下 k 值越大,验证的效果越好,但计算的开销也会越大。当数据集比较小时,较小的 k 值会导致训练数据较小,因此需要选择较大的 k 值;当数据量很大时,如果 k 值较大,计算的开销则会非常高,需要选择适当的 k 值。

混淆矩阵

混淆矩阵是机器学习中总结分类模型预测结果的情形分析表,以矩阵形式将数据集中的记录按照真实的类别与分类模型预测的类别判断两个标准进行汇总。其中矩阵的行表示真实值,矩阵的列表示预测值。二分类的混淆矩阵可以分为 4 类:

  • TN:True Negative(真阴性):预测值为 0,实际值也是 0;
  • FP:False Positive(假阳性):预测值为 1,实际值是 0;
  • FN:False Negative(假阴性):预测值为 0,实际值是 1;
  • TP:True Positive(真阳性):预测值为 1,实际值也是 1。

根据混淆矩阵,主要有 3 个指标:

  1. 准确率 = (TP+TN) / (TP+TN+FP+FN) = 正确预测 / 总样本
  2. 精确率 = TP / (TP+FP) = 真阳性 / (真阳性+假阳性)
  3. 召回率 = TP / (TP+FN) = 真阳性 / (真阳性+假阴性)

f-分数是精确率和召回率的调和平均数:$F_1 = 2\times\frac{精确率\times召回率}{精确率+召回率}$

scikit-learn 中计算混淆矩阵的方法为 confusion_matrix

from sklearn.metrics import confusion_matrix
confusion_matrix()

主要的参数:

参数 说明
y_true 真实的值
y_pred 预测的目标值
labels 索引矩阵的标签列表
sample_weight 样本权重

计算 Titanic 数据集逻辑回归方法的混淆矩阵:

from sklearn.metrics import confusion_matrix
y_pred = lr1.predict(X_train)
confusion_matrix(y_train, y_pred)

要获取准确性、召回率和 F1 分数,可以使用 scikit-learn 中的 classification_report 方法:

from sklearn.metrics import classification_report
classification_report()

主要参数有:

参数 说明
y_true 真实的值
y_pred 预测的目标值
labels 索引矩阵的标签列表
target_names 与标签匹配的可选显示名称
sample_weight 样本权重

生成上面 Titanic 数据集逻辑回归方法的预测报告:

from sklearn.metrics import classification_report
print(classification_report(y_train, y_pred))

ROC 曲线

ROC 的全名叫做 Receiver Operating Characteristic,中文名字叫“受试者工作特征曲线”,其主要分析工具是一个画在二维平面上的曲线——ROC 曲线。平面的横坐标是false positive rate(FPR),纵坐标是true positive rate(TPR)。ROC 曲线越凸,表示模型越好。

roc_curve 可以用于获取 ROC 曲线对应的值:

from sklearn.metrics import roc_curve
fpr, pr, thresholds = roc_curve()

主要参数:

参数 说明
y_true 真实的值
y_score 置信度值
pos_label 正类的标签
sample_weight 样本权重

计算 Titanic 数据集逻辑回归方法的 ROC 值,并绘制曲线:

from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y_test, lr1.decision_function(X_test))
close_zero = np.argmin(np.abs(thresholds))
plt.plot(fpr, tpr)
plt.plot(fpr[close_zero], tpr[close_zero], 'o')

plot_roc_curve 可以直接绘制 ROC 曲线,而无需获取参数后使用 plt 绘图。注意:sklearn1.2 版弃用了这一方法,从这一版本开始需要使用 RocCurveDisplay.from_estimator() 直接绘制 ROC 曲线。

主要参数:

参数 说明
estimator 分类器
X, y 自变量和因变量
response_method 指定使用predict_proba还是decision_function
name 标记 ROC 曲线的名称
ax 用于多个曲线坐标对齐

用 ROC 曲线对比前面 Titanic 数据集中逻辑回归模型 6 种参数选择下的情况:

lr_display = RocCurveDisplay.from_estimator(lr1, X_test, y_test, name='lrf')
RocCurveDisplay.from_estimator(lr2, X_test, y_test, name='lr2', ax=lr_display.ax_)
RocCurveDisplay.from_estimator(lr3, X_test, y_test, name='lr3', ax=lr_display.ax_)
RocCurveDisplay.from_estimator(lr4, X_test, y_test, name='lr4', ax=lr_display.ax_)
RocCurveDisplay.from_estimator(lr5, X_test, y_test, name='lr5', ax=lr_display.ax_)
RocCurveDisplay.from_estimator(lr6, X_test, y_test, name='lr6', ax=lr_display.ax_)

从曲线来看,lr3、lr4、lr6 比较好。

总结

在进行有监督模型实际模型训练前,需要先将数据划分为训练集和测试集,其中训练集用于训练有监督模型,调整参数,测试集用于验证训练出的模型效果。

对于分类问题,可以是使用逻辑回归模型或随机森林模型进行解决,每个模型各自有许多参数,可以通过调整参数的方式对模型进行调整。

交叉验证就是重复地使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏。其中,最常用的交叉验证方法是 k 折交叉验证。

混淆矩阵是机器学习中总结分类模型预测结果的情形分析表,以矩阵形式将数据集中的记录按照真实的类别与分类模型预测的类别判断两个标准进行汇总,分为:TN(真阴性)、FP(假阳性)、FN(假阴性)和TP(真阳性)4 类。

根据混淆矩阵的结果计算的几个指标

  1. 准确率 = (TP+TN) / (TP+TN+FP+FN) = 正确预测 / 总样本
  2. 精确率 = TP / (TP+FP) = 真阳性 / (真阳性+假阳性)
  3. 召回率 = TP / (TP+FN) = 真阳性 / (真阳性+假阴性)
  4. F1 = 2精确率召回率/(精确率+召回率)

ROC 曲线以图像的方式反映模型的好坏,曲线下的面积越大越好。

浙ICP备19012682号