楼层: 首页/ 软件技术/ Python 机器学习与深度学习/ 逻辑回归与分类指标
4

逻辑回归与分类指标

Logistic Regression & Classification Metrics

逻辑回归名字叫"回归",干的却是分类的活。它把线性回归的输出(负无穷到正无穷)用 Sigmoid 压到 0~1 之间,当成"是正例的概率"。二分类的 baseline 之王。

数学原理:Sigmoid + 交叉熵

Sigmoid:σ(z) = 1 / (1 + e-z),把任意实数压到 (0,1)
假设函数:p = σ(θᵀx);预测:p > 0.5 → 正例,否则负例

论为什么不用 MSE

分类用交叉熵损失(Cross Entropy)而不是 MSE——因为 MSE 在 Sigmoid 下是非凸的,梯度下降容易卡局部最优;交叉熵对预测错误的惩罚很大,且梯度形状漂亮。J(θ) = -Σ[y·log(p) + (1-y)·log(1-p)]。

多分类:OvR vs Softmax

方法思路
OvR(One-vs-Rest)有 K 类就训 K 个二分类器,每个判"是不是这一类",选概率最高的。sklearn 的 LogisticRegression 默认。
Softmax(多项逻辑回归)一次输出 K 类的概率,所有概率和为 1。

分类指标全家桶

指标公式 / 含义
混淆矩阵TP / FP / FN / TN 四格表。
准确率 Accuracy(TP+TN) / 全部。类别均衡时用,不均衡会骗人。
精确率 PrecisionTP / (TP+FP)。"预测为正的里面真的正"。
召回率 RecallTP / (TP+FN)。"所有真的正例被找出来多少"。
F12·P·R / (P+R),调和平均,平衡两者。
ROC-AUCROC 曲线下面积,0.5=瞎猜,1=完美,类别不平衡时首选。

论怎么记

看病看重 recall(漏诊代价高,宁可错杀);抓坏人看重 precision(误伤代价高,宁可放过)。

Sigmoid 函数图像与性质

import numpy as np import matplotlib.pyplot as plt z = np.linspace(-10, 10, 100) sigmoid = lambda z: 1 / (1 + np.exp(-z)) plt.plot(z, sigmoid(z), label="Sigmoid") plt.axhline(0.5, color="gray", ls="--") plt.axvline(0, color="gray", ls="--") plt.title("Sigmoid: 把实数压到 (0,1)") plt.grid(True) plt.show() # 性质:z=0 时输出 0.5(决策边界) # z 很大时趋近 1,z 很小时趋近 0 # 导数最大在 z=0 处,两端饱和(导数趋近 0)→ 梯度消失

完整案例:信用卡欺诈检测

import numpy as np from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metrics import (confusion_matrix, classification_report, roc_auc_score, f1_score) # 构造极度不平衡数据:99% 正常,1% 欺诈 X, y = make_classification( n_samples=10000, n_features=20, weights=[0.99], flip_y=0, random_state=42 ) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, stratify=y, random_state=42 ) # stratify=y:保证训练集和测试集类别比例一致 scaler = StandardScaler() X_train_s = scaler.fit_transform(X_train) X_test_s = scaler.transform(X_test) # baseline:不处理不平衡 lr = LogisticRegression(max_iter=1000, random_state=42) lr.fit(X_train_s, y_train) pred = lr.predict(X_test_s) print("准确率:", np.mean(pred == y_test)) # 准确率:0.99(看起来很美) print("F1:", f1_score(y_test, pred)) # F1:0.0(欺诈全没抓到!) # 修复:class_weight="balanced" 自动按类别频率加权 lr_bal = LogisticRegression(max_iter=1000, class_weight="balanced", random_state=42) lr_bal.fit(X_train_s, y_train) pred2 = lr_bal.predict(X_test_s) proba = lr_bal.predict_proba(X_test_s)[:, 1] print("\n=== 平衡后的混淆矩阵 ===") print(confusion_matrix(y_test, pred2)) # [[1850 130] # [ 8 12]] print("\n=== 分类报告 ===") print(classification_report(y_test, pred2, target_names=["正常", "欺诈"])) print("ROC-AUC:", roc_auc_score(y_test, proba)) # ROC-AUC:0.92

本章面试题

面试 · 逻辑回归

Q1. 逻辑回归为什么用交叉熵不用 MSE?

查看答案

Sigmoid + MSE 是非凸损失,梯度下降容易卡局部最优;交叉熵在 Sigmoid 下梯度形状好(误差大梯度大),且是 MLE 推导出来的。

Q2. 类别不平衡怎么办?

查看答案

① class_weight="balanced";② 重采样(SMOTE 过采样 / 欠采样);③ 换指标(F1 / ROC-AUC / PR-AUC);④ 调整分类阈值(不一定要 0.5)。

Q3. precision 和 recall 怎么权衡?

查看答案

移动分类阈值:阈值高 precision 高 recall 低;阈值低 recall 高 precision 低。画 PR 曲线选工作点。

Q4. solver 怎么选?

查看答案

小数据集 liblinear;大且多分类 lbfgs / saga;带 L1 正则用 saga。