引言:从回归到分类
线性回归解决了"预测数值"的问题,比如房价能卖多少钱。但现实世界中,还有大量问题需要回答"是或否"、“属于 A 类还是 B 类”:
- 这封邮件是垃圾邮件吗?(是/否)
- 根据肿瘤特征,它是良性还是恶性?(良性/恶性)
- 用户看到广告后会不会点击?(点击/不点击)
这些都是典型的分类问题。线性回归输出范围是 (-inf, +inf),无法直接表示概率,也不适合做类别判断——你总不能说"这个肿瘤的恶性程度是 0.78"吧?我们需要的是一个明确的类别判断。
那么,有没有一种方法,能够巧妙借鉴线性回归的思想,又能优雅地解决分类问题呢?
一、逻辑回归基础
1.1 什么是逻辑回归
逻辑回归(Logistic Regression)是一种用于解决分类问题的统计方法,尤其适用于二分类问题。虽然名字里带"回归",但它主要用于分类任务。
“分类"是逻辑回归的目的和结果,但中间过程依旧是"回归”。
因为通过逻辑回归模型,得到的计算结果是 0~1 之间的连续数字,可以理解为"概率"。例如客户购买某商品的可能性、借款人违约的可能性。然后给这个概率加一个阈值(如 0.5),就成了分类。
伯努利分布:抛一次硬币,只有两个结果——成功或失败,概率分别为 p 和 (1-p)。
1.2 逻辑回归的三大核心特点
| 特点 | 说明 |
|---|---|
| 输出概率值 | 输出 (0, 1) 之间的概率,而非硬分类 |
| 可解释性强 | 能输出每个特征的权重,影响一目了然 |
| 工业界最常用 | 速度快、省资源,大规模应用首选 |
1.3 为什么选择逻辑回归
1)它能给出"概率",而不只是分类结果
- 医疗诊断:不仅告诉你"病人是否患病",还能输出"患病概率为 92%"
- 金融风控:预测违约概率为 75%,银行可对高风险用户提前预警,而非一刀切拒绝
2)速度快、省资源,适合大规模应用
- 实时推荐系统:短视频平台需在毫秒内预测用户是否会点赞
- 嵌入式设备:智能家居传感器内存极小,逻辑回归占用空间少,能在芯片上稳定运行
3)每个特征的影响一目了然
- 银行贷款审批:模型显示"年收入每增加 1 万元,违约概率下降 0.3%",业务员可直接拿着数据向客户解释拒贷原因
1.4 应用场景
适用于二分类任务和需要概率输出的场景:
| 场景 | 输入特征 | 预测目标 |
|---|---|---|
| 欺诈检测 | 交易金额、地点、频率 | 是否欺诈 |
| 垃圾邮件检测 | 邮件文本特征 | 垃圾邮件/正常邮件 |
| 广告点击预测 | 用户画像、广告属性 | 点击/不点击 |
| 医学诊断 | 肿瘤特征指标 | 患病/未患病 |
| 产品质量分类 | 传感器数据 | 合格/不合格 |
二、逻辑回归 API 实操
2.1 信用卡申请案例
用年龄和收入两个特征,预测客户是否会申请信用卡:
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
# 定义数据:每一行 [年龄, 收入, 是否申请]
data = np.array([
[23, 30000, 1], [25, 36000, 1], [28, 42000, 1],
[30, 68000, 1], [32, 65000, 1], [35, 62000, 1],
[38, 58000, 1], [40, 55000, 1], [42, 53000, 0],
[45, 50000, 0], [50, 45000, 0], [55, 40000, 0],
[60, 35000, 0], [65, 30000, 0]
])
# 切分特征与标签
X = data[:, :2] # 年龄、收入
y = data[:, 2] # 是否申请
# 划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=67
)
# 标准化
scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
# 训练模型
model = LogisticRegression()
model.fit(x_train, y_train)
# 预测评估
y_pred = model.predict(x_test)
acc = accuracy_score(y_test, y_pred)
print(f"模型准确率: {acc}")
# 新客户预测
new_customer = scaler.transform(np.array([
[26, 33000], [33, 66000], [41, 54000], [64, 32000]
]))
new_pred = model.predict(new_customer)
for age, pred in zip([26, 33, 41, 64], new_pred):
print(f"{age}岁 -> {'会申请' if pred == 1 else '不会申请'}")
2.2 红酒分类案例
使用 sklearn 内置的葡萄酒数据集,将三分类转为二分类(预测是否为 Class_0):
import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
# 加载数据集
wine = load_wine()
X = wine.data # 178个样本, 13个特征
y = wine.target # 3分类: 0, 1, 2
# 转为二分类: 预测是否为Class_0
y = (y == 0).astype(int)
# 划分数据集
x_train, x_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=45
)
# 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 训练与预测
model = LogisticRegression()
model.fit(x_train, y_train)
pred = model.predict(x_test)
print(f"准确率: {accuracy_score(y_test, pred)}")
运行结果:准确率 1.0
三、逻辑回归原理详解
3.1 Sigmoid 函数:从回归到分类的桥梁
逻辑回归的核心思想:用线性模型计算一个值,再用 Sigmoid 函数将值映射为概率。
Sigmoid 公式:
σ(x)=11+e−x\sigma(x) = \frac{1}{1 + e^{-x}}σ(x)=1+e−x1
导数:
σ′(x)=σ(x)⋅(1−σ(x))\sigma'(x) = \sigma(x) \cdot (1 - \sigma(x))σ′(x)=σ(x)⋅(1−σ(x))
函数特点:
| 属性 | 值 |
|---|---|
| 输入值域 | (-inf, +inf) |
| 输出值域 | (0, 1) |
| 单调性 | 单调递增 |
| 中心对称点 | (0, 0.5) |
| 可导性 | 平滑可导 |
Sigmoid 是一条 S 形曲线,就像阶跃函数的"温和版"——阶跃函数在 0 和 1 之间突然起跳,而 Sigmoid 有平滑的过渡。它将取值范围 (-inf, +inf) 映射到 (0, 1) 之间,非常适合表示概率。
假设函数:
hw(x)=σ(wx+b)=11+e−(wx+b)h_w(x) = \sigma(wx + b) = \frac{1}{1 + e^{-(wx + b)}}hw(x)=σ(wx+b)=1+e−(wx+b)1
3.2 损失函数:对数似然损失
逻辑回归不用 MSE(对分类问题梯度小、训练不稳定),而是使用对数似然损失。
最大似然估计的直观理解:找最可能产生当前数据的模型参数——“什么样的参数,能让我们现在看到的这批数据,发生的概率最大?”
例子:连续抛 10 次硬币出现 7 次正面,如果正面概率为 0.7,出现 7 正 3 反的概率最高,所以 0.7 就是最大似然估计。
单个样本损失:
Loss=−[ylog(y^)+(1−y)log(1−y^)]Loss = -[y \log(\hat{y}) + (1-y) \log(1-\hat{y})]Loss=−[ylog(y^)+(1−y)log(1−y^)]
整体损失函数:
J(w)=−1m∑i=1m[y(i)loghw(x(i))+(1−y(i))log(1−hw(x(i)))]J(w) = -\frac{1}{m} \sum_{i=1}^m \left[y^{(i)} \log h_w(x^{(i)}) + (1-y^{(i)}) \log(1-h_w(x^{(i)}))\right]J(w)=−m1i=1∑m[y(i)loghw(x(i))+(1−y(i))log(1−hw(x(i)))]
目标:最小化 J(w)。
3.3 优化方法:梯度下降
通过梯度下降最小化损失:
wj=wj−η∂J(w)∂wjw_j = w_j - \eta \frac{\partial J(w)}{\partial w_j}wj=wj−η∂wj∂J(w)
梯度推导结果:
∂J(w)∂wj=1m∑i=1m(hw(x(i))−y(i))xj(i)\frac{\partial J(w)}{\partial w_j} = \frac{1}{m} \sum_{i=1}^m (h_w(x^{(i)}) - y^{(i)}) x_j^{(i)}∂wj∂J(w)=m1i=1∑m(hw(x(i))−y(i))xj(i)
四、分类评估指标
4.1 混淆矩阵
混淆矩阵是用来全面评估二分类模型预测对错情况的表格,精确率、召回率全部从它里面算出来。
| 预测为正例 | 预测为反例 | |
|---|---|---|
| 真实为正例 | TP(真正例) | FN(伪反例) |
| 真实为反例 | FP(伪正例) | TN(真反例) |
- 正类 Positive:1(患病、流失、点击、垃圾邮件)
- 负类 Negative:0(健康、留存、不点击、正常邮件)
关系:TP + FN + FP + TN = 总样本数量
4.2 精确率(Precision)
精确率也叫查准率,衡量"预测为正例的样本中,有多少是真的正例"。
Precision=TPTP+FP\text{Precision} = \frac{TP}{TP + FP}Precision=TP+FPTP
4.3 召回率(Recall)
召回率也叫查全率,衡量"所有真实正例中,有多少被正确预测"。
Recall=TPTP+FN\text{Recall} = \frac{TP}{TP + FN}Recall=TP+FNTP
4.4 F1-Score
F1 是精确率和召回率的调和平均,综合衡量模型预测能力:
F1=2×Precision×RecallPrecision+RecallF1 = 2 \times \frac{Precision \times Recall}{Precision + Recall}F1=2×Precision+RecallPrecision×Recall
计算示例:
假设 6 个正样本、4 个负样本,模型预测对了 3 个正样本、4 个负样本:
| 指标 | 计算 | 结果 |
|---|---|---|
| TP | 真正例 | 3 |
| FN | 伪反例 | 3 |
| FP | 伪正例 | 0 |
| TN | 真反例 | 4 |
| 精确率 | 3/(3+0) | 100% |
| 召回率 | 3/(3+3) | 50% |
| F1 | 23/(23+3+0) | 67% |
4.5 分类评估报告
from sklearn.metrics import classification_report
print(classification_report(
y_true, y_pred,
labels=['正', '伪'],
target_names=['正', '伪']
))
输出示例:
precision recall f1-score support
正 1.00 0.50 0.67 6
伪 0.57 1.00 0.73 4
accuracy 0.70 10
macro avg 0.79 0.75 0.70 10
weighted avg 0.83 0.70 0.69 10
- macro avg:各类别指标的算术平均(不考虑样本数量)
- weighted avg:按各类样本数量加权平均
4.6 代码实现:混淆矩阵与评估指标
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score
import pandas as pd
# 真实数据:6个正, 4个伪
y_true = ['正','正','正','正','正','正','伪','伪','伪','伪']
y_pred = ['正','正','正','伪','伪','伪','伪','伪','伪','伪']
labels = ['正','伪']
# 混淆矩阵
result = confusion_matrix(y_true, y_pred, labels=labels)
print(pd.DataFrame(result, index=labels, columns=labels))
# 评估指标
print(f"精确率: {precision_score(y_true, y_pred, pos_label='正')}")
print(f"召回率: {recall_score(y_true, y_pred, pos_label='正')}")
print(f"F1-Score: {f1_score(y_true, y_pred, pos_label='正')}")
五、模型调参与保存
5.1 关键超参数
| 参数 | 说明 | 常用值 |
|---|---|---|
| C | 正则化强度的倒数,越小惩罚越强 | 1.0(默认) |
| class_weight | 处理不平衡数据集 | ‘balanced’ |
| max_iter | 最大迭代次数 | 100~2000 |
| solver | 求解器 | liblinear / lbfgs / saga |
solver 选择指南:
| 数据规模 | 推荐求解器 |
|---|---|
| 小数据集(<10 万) | liblinear(最稳定) |
| 中等数据集 | lbfgs |
| 大数据集 | saga |
class_weight 使用场景:
当标签分布不均衡时(如良性 900 个、恶性 100 个),模型会偏向多数类"躺平"。设置 class_weight='balanced' 可自动给少数类更大权重,医学、金融、风控场景必用。
5.2 迭代次数对准确率的影响
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
wine = load_wine()
X = wine.data
y = (wine.target == 0).astype(int)
x_train, x_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print("===== max_iter 对准确率的影响 =====")
for iters in [1, 2, 3, 5, 10, 50, 200]:
model = LogisticRegression(
max_iter=iters, solver='liblinear',
C=0.01, random_state=55
)
model.fit(x_train, y_train)
y_pred = model.predict(x_test)
print(f"Iterations={iters}: Accuracy={accuracy_score(y_test, y_pred):.2f}")
5.3 模型保存与加载
import joblib
import os
# 保存模型
model_dir = '../model'
model_path = os.path.join(model_dir, 'logic_wine_model.pkl')
if not os.path.exists(model_dir):
os.makedirs(model_dir)
joblib.dump(model, model_path)
print(f"模型已保存: {model_path}")
# 加载模型
model = joblib.load(model_path)
y_pred = model.predict(x_test)
print(f"加载后准确率: {accuracy_score(y_test, y_pred):.2f}")
六、金融信贷实战案例
6.1 数据集背景
使用 Kaggle 经典竞赛 Give Me Some Credit 的信用评分数据集,预测借款人未来 2 年是否会发生严重信用违约。
| 属性 | 说明 |
|---|---|
| 样本量 | 45,063 条 |
| 特征数 | 7 个数值型特征 |
| 标签 | 0=未违约, 1=违约 |
| 标签分布 | 未违约 77.75%, 违约 22.25% |
核心字段:
| 字段 | 中文释义 | 说明 |
|---|---|---|
| SeriousDlqin2yrs | 是否严重违约 | 标签列,1=逾期90天以上 |
| age | 借款人年龄 | 21~107 岁 |
| NumberOfTime30-59DaysPastDueNotWorse | 逾期30-59天次数 | 核心负向特征 |
| DebtRatio | 债务收入比 | 还款压力核心指标 |
| NumberOfTimes90DaysLate | 逾期90天以上次数 | 最严重负向特征 |
| MonthlyIncome | 月收入 | 还款能力正向特征 |
| NumberOfDependents | 家属人数 | 间接影响还款能力 |
6.2 数据预处理
缺失值处理:
| 字段 | 缺失率 | 处理建议 |
|---|---|---|
| MonthlyIncome | 19.18% | 中位数填充或分组填充 |
| NumberOfDependents | 2.48% | 用 0 填充 |
异常值处理:债务收入比和月收入存在极端值,建议用分位数截断。
# 分位数截断
q90_debt = data['DebtRatio'].quantile(0.90)
data['DebtRatio'] = data['DebtRatio'].clip(upper=q90_debt)
6.3 完整建模流程
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import (
accuracy_score, confusion_matrix,
precision_score, recall_score, f1_score,
classification_report, roc_auc_score
)
import warnings
warnings.filterwarnings('ignore')
# 1. 读取数据
data = pd.read_csv('../data/credit_scoring_sample.csv', sep=';')
# 2. 缺失值填充(中位数)
for col in data.columns[data.isnull().any()]:
data[col] = data[col].fillna(data[col].median())
# 3. 划分特征与标签
X = data.drop('SeriousDlqin2yrs', axis=1)
y = data['SeriousDlqin2yrs']
# 4. 划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=88
)
# 5. 标准化
scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
# 6. 训练模型(处理不平衡标签)
model = LogisticRegression(
random_state=5,
class_weight='balanced'
)
model.fit(x_train, y_train)
# 7. 预测与评估
y_pred = model.predict(x_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")
print(f"精确率: {precision_score(y_test, y_pred):.4f}")
print(f"召回率: {recall_score(y_test, y_pred):.4f}")
print(f"F1分数: {f1_score(y_test, y_pred):.4f}")
print("\n混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
print("\n分类报告:")
print(classification_report(y_test, y_pred))
风控场景核心:在信用评分中,召回率比精确率更重要——宁可误伤一些正常客户,也不能漏掉真正的高风险违约客户。
小结
逻辑回归虽然名字里带"回归",却是分类问题的利器:
- 它用 Sigmoid 函数把线性输出映射为概率,巧妙地从回归过渡到分类
- 它的损失函数基于最大似然估计,用对数似然损失代替 MSE,梯度更稳定
- 评估分类模型不能只看准确率,混淆矩阵、精确率、召回率、F1 各有侧重
- 面对不平衡数据,
class_weight='balanced'是风控/医疗场景的必备手段 - 金融信贷实战展示了从数据预处理到模型评估的完整流程
逻辑回归告诉我们:面对"是或否"的问题,最优雅的答案不是一个硬邦邦的 0 或 1,而是一个有温度的概率。
逻辑回归原理与分类评估实战&spm=1001.2101.3001.5002&articleId=163250924&d=1&t=3&u=748497c2937f4701af025a88b7270699)
3111

被折叠的 条评论
为什么被折叠?



