Aller au contenu principal

机器学习 3 — 分类

:::tip Kaggle 笔记本 本章的完整可执行代码在 Kaggle 上:打开 →

法语和英语版本可在首页查看。 :::

继回归之后,我们攻克分类:预测一个类别而不是一个数值。Titanic 生存、医疗诊断、企鹅物种——许多输出离散的问题。

为什么要学这一章?

您将发现:

  • Naive Bayes 分类器和经验概率
  • 混淆矩阵和分类专属的指标(精确率、召回率、F1);
  • 决策阈值的作用以及 ROC精确率-召回率曲线;
  • 带 Gini 指数的决策树
  • 集成方法:随机森林和梯度提升。

Naive Bayes

Naive Bayes 分类器基于贝叶斯定理预测类别:

P(Y=yX)P(Y=y)P(XY=y)P(Y = y \mid X) \propto P(Y = y) \cdot P(X \mid Y = y)

"naive"(朴素)一词来自一个强假设:解释变量在给定类别下条件独立

P(X1,,XdY)=j=1dP(XjY)P(X_1, \dots, X_d \mid Y) = \prod_{j=1}^d P(X_j \mid Y)

实际上这是错的,但近似值的效果出奇地好,模型也非常快。

from sklearn.naive_bayes import BernoulliNB

model = BernoulliNB(alpha=1.0)
model.fit(X_train, y_train)
y_hat = model.predict(X_test)

混淆矩阵

准确率(正确分类率)很直观但具有误导性。设想一个总是说"非垃圾邮件"的垃圾邮件检测器:如果 99% 的邮件是合法的,它的准确率是 99%……但毫无用处。

为了理解模型在哪里出错,我们使用混淆矩阵

& \text{预测 } 0 & \text{预测 } 1 \\ \hline \text{实际 } 0 & TN & FP \\ \text{实际 } 1 & FN & TP \end{array}$$ - **TP**(真阳性):说是,确实是。 - **FP**(假阳性):误报。 - **FN**(假阴性):漏检。 - **TN**(真阴性):正确排除。 ## 精确率、召回率、F1 从矩阵推导出三个核心指标: $$\mathrm{Precision} = \frac{TP}{TP + FP}, \quad \mathrm{Recall} = \frac{TP}{TP + FN}$$ $$F_1 = 2 \cdot \frac{\mathrm{Precision} \cdot \mathrm{Recall}}{\mathrm{Precision} + \mathrm{Recall}}$$ - **高精确率** = 误报少(FP 代价高时有用)。 - **高召回率** = 漏检少(FN 危险时有用)。 - **F1** = 两者之间的妥协。 ```python from sklearn.metrics import classification_report, confusion_matrix print(classification_report(y_test, y_hat)) print(confusion_matrix(y_test, y_hat)) ``` ## 概率和决策阈值 大多数分类器预测一个**概率** $\hat{p} = P(Y=1 \mid X)$。然后通过与**阈值** $t$(默认为 0.5)的比较决定类别。 $$\hat{y} = \begin{cases} 1 & \text{如果 } \hat{p} \geq t \\ 0 & \text{否则} \end{cases}$$ ```python probas = model.predict_proba(X_test) y_score = probas[:, 1] y_hat = (y_score >= 0.7).astype(int) # 阈值 0.7 ``` 提高阈值 → 预测的阳性更少,**FP 更少,FN 更多**。降低阈值 → 预测的阳性更多,**FP 更多,FN 更少**。 ## ROC 曲线和 AUC **ROC 曲线**绘制真阳性率 $\mathrm{TPR}(t)$ 关于假阳性率 $\mathrm{FPR}(t)$ 的图,针对所有可能的阈值 $t$。 $$\mathrm{TPR} = \frac{TP}{TP + FN}, \quad \mathrm{FPR} = \frac{FP}{FP + TN}$$ **AUC**(*曲线下面积*)将曲线总结为 0 到 1 之间的单一数字。 | AUC | 质量 | |---|---| | 0.5 | 随机 | | 0.7-0.8 | 不错 | | 0.8-0.9 | 好 | | > 0.9 | 非常好 | ```python from sklearn.metrics import roc_auc_score, roc_curve y_score = model.predict_proba(X_test)[:, 1] auc = roc_auc_score(y_test, y_score) fpr, tpr, _ = roc_curve(y_test, y_score) ``` ## 精确率-召回率曲线 ROC 在**类别不平衡**时可能具有误导性:即使模型错过许多阳性,FPR 仍然很小。**精确率-召回率曲线**在这种情况下更诚实。 ```python from sklearn.metrics import precision_recall_curve, average_precision_score precisions, recalls, thresholds = precision_recall_curve(y_test, y_score) ap = average_precision_score(y_test, y_score) ``` 只要阳性类别稀少(欺诈、疾病等),就使用它。 ## 决策树 **决策树**通过对变量提出一系列简单问题来分类。 ### Gini 指数 为了衡量节点的纯度(多数类的比例),我们使用 **Gini 指数**: $$G = 2 \, p \, (1 - p)$$ 其中 $p$ 是阳性类别的比例。如果节点纯净,$G = 0$;如果是 50/50,$G = 0.5$。 算法选择**最小化加权杂质**的两个子组的分裂。 ```python from sklearn.tree import DecisionTreeClassifier model = DecisionTreeClassifier(max_depth=3) model.fit(X_train, y_train) ``` 关键超参数: - `max_depth`:最大深度。小 = 简单;大 = 过拟合风险。 - `min_samples_leaf`:每个叶子的最小样本数。 ## 随机森林 单棵树不稳定。**随机森林**在引导样本(bootstrap)上训练许多树,每次分裂都使用变量的随机子集,然后**平均**它们的预测。 ```python from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier(n_estimators=200, max_depth=5) ``` 稳健,需要很少调整,还提供**特征重要性**(`model.feature_importances_`)。 ## 梯度提升(Gradient Boosting) 与森林相反的哲学:**顺序**训练树,每棵新树都纠正前面树的错误。 ```python from sklearn.ensemble import GradientBoostingClassifier model = GradientBoostingClassifier( n_estimators=200, learning_rate=0.05, max_depth=3 ) ``` `learning_rate` 控制每次校正的强度。小(0.05)= 稳定收敛,大(0.3)= 过拟合风险。 | 随机森林 | 梯度提升 | |---|---| | 独立的树 | 顺序的树 | | 平均 / 投票 | 累积修正 | | 稳健 | 性能更好但对调参敏感 | 更高效的现代库:**XGBoost**、**LightGBM**、**CatBoost**(下一章介绍)。 --- [**Kaggle 上的完整笔记本(可分叉)→**](https://www.kaggle.com/code/pyim59/zh-machine-learning-3-classification-v3-1)