Logistic回归学习笔记
作为大数据领域学习者,Logistic回归是我入门分类算法的难点------它虽名"回归",实则用于二分类,多数书籍要么堆砌公式要么空谈理论,直到品读吕欣等著的《数据挖掘》,我才读懂这一算法精髓。
Logistic回归是监督学习基础算法,广泛应用于多领域,核心是将线性回归输出映射到(0,1)区间,实现概率预测与因素分析。该书立足读者视角,避开晦涩理论,结合案例拆解其核心逻辑,清晰区分与线性回归的差异,阐释其应用方法。
书中对Logistic回归的讲解兼顾理论严谨与实操性,无深厚统计基础也能掌握。对于大数据领域学习者、从业者,它是贴心入门指南,能帮助攻克学习难点、挖掘数据分类规律,适配学习与工作需求,值得品读。
书籍开源学习代码: https://github.com/XL-lab-bigdata/DataMining
1. Logistic回归是什么
1.1 基本思想
(1) "从连续到离散的桥梁"
Logistic回归(Logistic Regression)是一种广泛应用于分类问题 的统计学习方法。尽管名字中带有"回归"二字,但它实际上是一种分类算法。其核心思想是:通过Sigmoid函数将线性回归的输出映射到(0,1)区间,从而表示样本属于某一类别的概率。
注意:Logistic回归的本质是在线性回归的基础上套用一个Sigmoid函数,将连续值转换为概率值,再通过设定阈值(通常为0.5)进行分类决策。
(2) "软分类"的优势
与硬分类器(如感知机)直接输出类别不同,Logistic回归输出的是概率值,这使得我们可以:
- 了解模型对预测结果的置信度
- 根据业务需求灵活调整分类阈值
- 为后续的集成学习提供概率输入
1.2 Sigmoid函数
Sigmoid函数(又称Logistic函数)是Logistic回归的核心,其数学表达式为:
σ(z)=11+e−z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
Sigmoid函数的性质:
| 性质 | 数学表达 | 意义 |
|---|---|---|
| 值域 | (0,1)(0, 1)(0,1) | 输出可解释为概率 |
| 单调性 | 单调递增 | 输入越大,概率越高 |
| 对称性 | σ(−z)=1−σ(z)\sigma(-z) = 1 - \sigma(z)σ(−z)=1−σ(z) | 关于点(0,0.5)(0, 0.5)(0,0.5)中心对称 |
| 导数 | σ′(z)=σ(z)(1−σ(z))\sigma'(z) = \sigma(z)(1-\sigma(z))σ′(z)=σ(z)(1−σ(z)) | 便于梯度计算 |
提示:Sigmoid函数的导数形式非常优雅,这使得在反向传播时计算梯度变得简单高效。
1.3 Logistic回归与线性回归的关系
| 对比维度 | 线性回归 | Logistic回归 |
|---|---|---|
| 任务类型 | 回归(连续值预测) | 分类(离散值预测) |
| 输出范围 | (−∞,+∞)(-\infty, +\infty)(−∞,+∞) | (0,1)(0, 1)(0,1) |
| 假设函数 | h(x)=wTx+bh(x) = w^Tx + bh(x)=wTx+b | h(x)=σ(wTx+b)h(x) = \sigma(w^Tx + b)h(x)=σ(wTx+b) |
| 损失函数 | 均方误差(MSE) | 交叉熵损失 |
| 优化目标 | 最小化预测误差 | 最大化似然函数 |
2. Logistic回归原理
2.1 模型假设
对于二分类问题,设输入特征为 x∈Rnx \in \mathbb{R}^nx∈Rn,类别标签 y∈{0,1}y \in \{0, 1\}y∈{0,1}。
Logistic回归假设样本属于类别1的概率为:
P(y=1∣x)=σ(wTx+b)=11+e−(wTx+b) P(y=1|x) = \sigma(w^Tx + b) = \frac{1}{1 + e^{-(w^Tx + b)}} P(y=1∣x)=σ(wTx+b)=1+e−(wTx+b)1
相应地,属于类别0的概率为:
P(y=0∣x)=1−P(y=1∣x)=11+ewTx+b P(y=0|x) = 1 - P(y=1|x) = \frac{1}{1 + e^{w^Tx + b}} P(y=0∣x)=1−P(y=1∣x)=1+ewTx+b1
2.2 几率与对数几率
几率(Odds) 定义为事件发生与不发生的概率之比:
odds=P(y=1∣x)P(y=0∣x)=P(y=1∣x)1−P(y=1∣x) \text{odds} = \frac{P(y=1|x)}{P(y=0|x)} = \frac{P(y=1|x)}{1 - P(y=1|x)} odds=P(y=0∣x)P(y=1∣x)=1−P(y=1∣x)P(y=1∣x)
对数几率(Log Odds / Logit):
logit(P)=lnP1−P=wTx+b \text{logit}(P) = \ln\frac{P}{1-P} = w^Tx + b logit(P)=ln1−PP=wTx+b
我的理解:
- Logistic回归实际上是在用线性函数拟合对数几率
- 这解释了为什么它叫"Logistic回归"------回归的是对数几率,而非直接回归概率
- 对数几率的范围是(−∞,+∞)(-\infty, +\infty)(−∞,+∞),恰好与线性函数的值域匹配
2.3 损失函数:交叉熵损失
为什么不能用MSE?
如果使用均方误差作为损失函数:
LMSE=12(y−σ(z))2 L_{MSE} = \frac{1}{2}(y - \sigma(z))^2 LMSE=21(y−σ(z))2
由于Sigmoid函数的特性,该损失函数是非凸的,存在多个局部极小值,梯度下降难以找到全局最优解。
交叉熵损失函数
对于单个样本,交叉熵损失定义为:
L(y,y^)=−[ylog(y^)+(1−y)log(1−y^)] L(y, \hat{y}) = -[y\log(\hat{y}) + (1-y)\log(1-\hat{y})] L(y,y^)=−[ylog(y^)+(1−y)log(1−y^)]
其中 y^=σ(wTx+b)\hat{y} = \sigma(w^Tx + b)y^=σ(wTx+b)。
对于整个数据集(mmm个样本),总损失为:
J(w,b)=−1m∑i=1m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))] J(w, b) = -\frac{1}{m}\sum_{i=1}^{m}[y^{(i)}\log(\hat{y}^{(i)}) + (1-y^{(i)})\log(1-\hat{y}^{(i)})] J(w,b)=−m1i=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]
交叉熵损失的直观理解:
- 当 y=1y=1y=1 时,损失为 −log(y^)-\log(\hat{y})−log(y^),y^\hat{y}y^ 越接近1,损失越小
- 当 y=0y=0y=0 时,损失为 −log(1−y^)-\log(1-\hat{y})−log(1−y^),y^\hat{y}y^ 越接近0,损失越小
- 错误预测会受到严重惩罚(损失趋向无穷大)
2.4 最大似然估计推导
交叉熵损失可以从最大似然估计的角度推导得出。
似然函数:
L(w,b)=∏i=1mP(y(i)∣x(i))=∏i=1m(y^(i))y(i)(1−y^(i))1−y(i) L(w, b) = \prod_{i=1}^{m} P(y^{(i)}|x^{(i)}) = \prod_{i=1}^{m} (\hat{y}^{(i)})^{y^{(i)}} (1-\hat{y}^{(i)})^{1-y^{(i)}} L(w,b)=i=1∏mP(y(i)∣x(i))=i=1∏m(y^(i))y(i)(1−y^(i))1−y(i)
对数似然函数:
ℓ(w,b)=∑i=1m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))] \ell(w, b) = \sum_{i=1}^{m} [y^{(i)}\log(\hat{y}^{(i)}) + (1-y^{(i)})\log(1-\hat{y}^{(i)})] ℓ(w,b)=i=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]
最大化对数似然 ⇔\Leftrightarrow⇔ 最小化负对数似然 ⇔\Leftrightarrow⇔ 最小化交叉熵损失
2.5 梯度计算
对损失函数求梯度:
∂J∂wj=1m∑i=1m(y^(i)−y(i))xj(i) \frac{\partial J}{\partial w_j} = \frac{1}{m}\sum_{i=1}^{m}(\hat{y}^{(i)} - y^{(i)})x_j^{(i)} ∂wj∂J=m1i=1∑m(y^(i)−y(i))xj(i)
∂J∂b=1m∑i=1m(y^(i)−y(i)) \frac{\partial J}{\partial b} = \frac{1}{m}\sum_{i=1}^{m}(\hat{y}^{(i)} - y^{(i)}) ∂b∂J=m1i=1∑m(y^(i)−y(i))
梯度形式的优雅之处:
- 梯度正比于预测误差 (y^−y)(\hat{y} - y)(y^−y)
- 与线性回归的梯度形式完全一致
- Sigmoid函数的导数在推导过程中被巧妙地消去
3. Logistic回归算法步骤
3.1 算法流程
输入:
- 训练数据集 D={(x(1),y(1)),(x(2),y(2)),...,(x(m),y(m))}D = \{(x^{(1)}, y^{(1)}), (x^{(2)}, y^{(2)}), ..., (x^{(m)}, y^{(m)})\}D={(x(1),y(1)),(x(2),y(2)),...,(x(m),y(m))}
- 学习率 α\alphaα
- 迭代次数 TTT 或收敛阈值 ϵ\epsilonϵ
算法过程:
-
初始化参数 :w=0w = 0w=0,b=0b = 0b=0(或随机初始化)
-
迭代优化(重复直到收敛):
-
前向传播 :计算预测概率
y^(i)=σ(wTx(i)+b)\hat{y}^{(i)} = \sigma(w^Tx^{(i)} + b)y^(i)=σ(wTx(i)+b) -
计算损失 :
J=−1m∑i=1m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]J = -\frac{1}{m}\sum_{i=1}^{m}[y^{(i)}\log(\hat{y}^{(i)}) + (1-y^{(i)})\log(1-\hat{y}^{(i)})]J=−m1i=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))] -
计算梯度 :
∂J∂w=1mXT(Y^−Y)\frac{\partial J}{\partial w} = \frac{1}{m}X^T(\hat{Y} - Y)∂w∂J=m1XT(Y^−Y)
∂J∂b=1m∑i=1m(y^(i)−y(i))\frac{\partial J}{\partial b} = \frac{1}{m}\sum_{i=1}^{m}(\hat{y}^{(i)} - y^{(i)})∂b∂J=m1i=1∑m(y^(i)−y(i)) -
更新参数 :
w:=w−α∂J∂ww := w - \alpha \frac{\partial J}{\partial w}w:=w−α∂w∂J
b:=b−α∂J∂bb := b - \alpha \frac{\partial J}{\partial b}b:=b−α∂b∂J
-
-
输出 :训练好的参数 www, bbb
预测阶段:
y^={1,if σ(wTx+b)≥0.50,otherwise \hat{y} = \begin{cases} 1, & \text{if } \sigma(w^Tx + b) \geq 0.5 \\ 0, & \text{otherwise} \end{cases} y^={1,0,if σ(wTx+b)≥0.5otherwise
3.2 具体例子
假设有一个简单的二分类数据集:
| 样本 | 特征 xxx | 真实标签 yyy |
|---|---|---|
| 1 | 1.0 | 0 |
| 2 | 2.0 | 0 |
| 3 | 3.0 | 1 |
| 4 | 4.0 | 1 |
第一轮迭代 (假设 w=0,b=0,α=0.1w=0, b=0, \alpha=0.1w=0,b=0,α=0.1):
Step 1: 计算预测值
y^(1)=σ(0×1+0)=σ(0)=0.5\hat{y}^{(1)} = \sigma(0 \times 1 + 0) = \sigma(0) = 0.5y^(1)=σ(0×1+0)=σ(0)=0.5
y^(2)=σ(0)=0.5\hat{y}^{(2)} = \sigma(0) = 0.5y^(2)=σ(0)=0.5
y^(3)=σ(0)=0.5\hat{y}^{(3)} = \sigma(0) = 0.5y^(3)=σ(0)=0.5
y^(4)=σ(0)=0.5\hat{y}^{(4)} = \sigma(0) = 0.5y^(4)=σ(0)=0.5
Step 2: 计算梯度
∂J∂w=14[(0.5−0)×1+(0.5−0)×2+(0.5−1)×3+(0.5−1)×4]\frac{\partial J}{\partial w} = \frac{1}{4}[(0.5-0) \times 1 + (0.5-0) \times 2 + (0.5-1) \times 3 + (0.5-1) \times 4]∂w∂J=41[(0.5−0)×1+(0.5−0)×2+(0.5−1)×3+(0.5−1)×4]
=14[0.5+1.0−1.5−2.0]=−24=−0.5= \frac{1}{4}[0.5 + 1.0 - 1.5 - 2.0] = \frac{-2}{4} = -0.5=41[0.5+1.0−1.5−2.0]=4−2=−0.5
∂J∂b=14[(0.5−0)+(0.5−0)+(0.5−1)+(0.5−1)]=0\frac{\partial J}{\partial b} = \frac{1}{4}[(0.5-0) + (0.5-0) + (0.5-1) + (0.5-1)] = 0∂b∂J=41[(0.5−0)+(0.5−0)+(0.5−1)+(0.5−1)]=0
Step 3: 更新参数
w:=0−0.1×(−0.5)=0.05w := 0 - 0.1 \times (-0.5) = 0.05w:=0−0.1×(−0.5)=0.05
b:=0−0.1×0=0b := 0 - 0.1 \times 0 = 0b:=0−0.1×0=0
继续迭代,参数会逐渐收敛,使得小的 xxx 值预测为0,大的 xxx 值预测为1。
4. 正则化
4.1 为什么需要正则化
当特征维度较高或数据量较少时,Logistic回归容易发生过拟合。正则化通过在损失函数中添加惩罚项来限制模型复杂度。
4.2 正则化方法
| 正则化类型 | 惩罚项 | 特点 | 适用场景 |
|---|---|---|---|
| L1正则化(Lasso) | λ∑j∣wj∣\lambda\sum_{j}|w_j|λ∑j∣wj∣ | 产生稀疏解,特征选择 | 高维稀疏数据 |
| L2正则化(Ridge) | λ2∑jwj2\frac{\lambda}{2}\sum_{j}w_j^22λ∑jwj2 | 权重衰减,防止权重过大 | 一般场景 |
| 弹性网络 | λ1∣w∣1+λ2∣w∣22\lambda_1|w|_1 + \lambda_2|w|_2^2λ1∣w∣1+λ2∣w∣22 | 结合L1和L2优点 | 特征相关性高 |
L2正则化后的损失函数:
J(w,b)=−1m∑i=1m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]+λ2m∑j=1nwj2 J(w, b) = -\frac{1}{m}\sum_{i=1}^{m}[y^{(i)}\log(\hat{y}^{(i)}) + (1-y^{(i)})\log(1-\hat{y}^{(i)})] + \frac{\lambda}{2m}\sum_{j=1}^{n}w_j^2 J(w,b)=−m1i=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]+2mλj=1∑nwj2
梯度更新(带L2正则化):
wj:=wj(1−αλm)−α∂J0∂wj w_j := w_j(1 - \alpha\frac{\lambda}{m}) - \alpha\frac{\partial J_0}{\partial w_j} wj:=wj(1−αmλ)−α∂wj∂J0
我的思考:
- L2正则化相当于在每次更新时对权重进行衰减(乘以一个小于1的系数)
- 正则化强度 λ\lambdaλ 需要通过交叉验证来选择
- 在sklearn中,参数
C= 1/λ1/\lambda1/λ,C越小正则化越强
5. 算法参数详解
5.1 sklearn中LogisticRegression核心参数
| 参数 | 默认值 | 作用说明 | 典型取值范围 |
|---|---|---|---|
penalty |
'l2' | 正则化类型 | 'l1', 'l2', 'elasticnet', 'none' |
C |
1.0 | 正则化强度倒数 | 0.001 - 1000 |
solver |
'lbfgs' | 优化算法 | 见下表 |
max_iter |
100 | 最大迭代次数 | 100 - 10000 |
tol |
1e-4 | 收敛阈值 | 1e-6 - 1e-3 |
class_weight |
None | 类别权重 | 'balanced' 或字典 |
multi_class |
'auto' | 多分类策略 | 'ovr', 'multinomial' |
5.2 优化器选择
| solver | 支持的正则化 | 适用场景 | 特点 |
|---|---|---|---|
| liblinear | L1, L2 | 小数据集 | 坐标下降法 |
| lbfgs | L2, None | 中等数据集 | 拟牛顿法(默认) |
| newton-cg | L2, None | 中等数据集 | 牛顿法 |
| sag | L2, None | 大数据集 | 随机平均梯度下降 |
| saga | L1, L2, Elastic | 大数据集 | 改进的SAG |
6. 多分类扩展
6.1 One-vs-Rest(OvR)
对于K类分类问题,训练K个二分类器:
- 第k个分类器:将第k类作为正类,其余所有类作为负类
- 预测时选择概率最大的类别
6.2 Softmax回归(Multinomial)
将Sigmoid函数扩展为Softmax函数:
P(y=k∣x)=ewkTx+bk∑j=1KewjTx+bj P(y=k|x) = \frac{e^{w_k^Tx + b_k}}{\sum_{j=1}^{K}e^{w_j^Tx + b_j}} P(y=k∣x)=∑j=1KewjTx+bjewkTx+bk
损失函数变为多类交叉熵:
J=−1m∑i=1m∑k=1KI(y(i)=k)logP(y(i)=k∣x(i)) J = -\frac{1}{m}\sum_{i=1}^{m}\sum_{k=1}^{K}\mathbb{I}(y^{(i)}=k)\log P(y^{(i)}=k|x^{(i)}) J=−m1i=1∑mk=1∑KI(y(i)=k)logP(y(i)=k∣x(i))
7. 【实践】淘宝商品评价情感分类
7.1 任务背景
电商平台的用户评价蕴含丰富的情感信息。本实践使用Logistic回归对淘宝商品评价进行情感二分类(正面/负面),帮助商家快速了解用户满意度。
7.2 完整代码
python
import numpy as np
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import (accuracy_score, precision_score,
recall_score, f1_score,
classification_report, confusion_matrix)
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
python
# ==================== 1. 数据准备 ====================
# 模拟淘宝商品评价数据
reviews = [
"质量非常好,穿着很舒服,下次还会购买",
"物流很快,包装精美,宝贝很满意",
"衣服颜色很正,尺码标准,好评",
"非常喜欢这个款式,物超所值",
"快递速度很快,客服态度很好",
"面料舒适,做工精细,推荐购买",
"性价比很高,质量超出预期",
"穿上效果很好,朋友都说好看",
"质量太差了,穿了一次就破了",
"尺码不对,退货还要自己出运费",
"颜色和图片差距太大,很失望",
"物流太慢了,等了两周才到",
"做工很粗糙,线头很多",
"客服态度差,问什么都不回复",
"面料很薄,完全不值这个价",
"收到就是坏的,差评",
"包装简陋,衣服都皱了",
"洗了一次就掉色严重"
]
# 标签:1表示正面评价,0表示负面评价
labels = [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 扩充数据集(实际应用中应使用真实大规模数据)
np.random.seed(42)
positive_templates = [
"很满意,{},推荐购买", "质量不错,{},好评",
"非常喜欢,{},下次还来", "超值,{},五星好评"
]
negative_templates = [
"太差了,{},不推荐", "很失望,{},差评",
"不值这个价,{},退货", "质量问题,{},投诉"
]
keywords_pos = ["物流快", "质量好", "款式新", "服务好", "包装好"]
keywords_neg = ["质量差", "尺码不对", "发货慢", "服务差", "做工糙"]
for _ in range(100):
reviews.append(np.random.choice(positive_templates).format(
np.random.choice(keywords_pos)))
labels.append(1)
reviews.append(np.random.choice(negative_templates).format(
np.random.choice(keywords_neg)))
labels.append(0)
print(f"数据集大小: {len(reviews)}")
print(f"正面评价: {sum(labels)}, 负面评价: {len(labels) - sum(labels)}")
python
# ==================== 2. 文本预处理 ====================
def preprocess_text(text):
"""中文分词"""
words = jieba.cut(text)
return ' '.join(words)
# 对所有评论进行分词
reviews_cut = [preprocess_text(review) for review in reviews]
print("\n分词示例:")
print(f"原文: {reviews[0]}")
print(f"分词: {reviews_cut[0]}")
python
# ==================== 3. 特征提取 ====================
# 使用TF-IDF进行特征提取
tfidf = TfidfVectorizer(max_features=500)
X = tfidf.fit_transform(reviews_cut)
y = np.array(labels)
print(f"\n特征矩阵维度: {X.shape}")
print(f"特征示例: {tfidf.get_feature_names_out()[:10]}")
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"训练集大小: {X_train.shape[0]}, 测试集大小: {X_test.shape[0]}")
python
# ==================== 4. 模型训练与评估 ====================
# 构建基础Logistic回归模型
lr_model = LogisticRegression(random_state=42, max_iter=1000)
lr_model.fit(X_train, y_train)
y_pred = lr_model.predict(X_test)
# 模型评价函数
def evaluate_model(name, y_true, y_pred):
print(f"\n{'='*50}")
print(f"模型: {name}")
print(f"{'='*50}")
print(f"准确率 (Accuracy): {accuracy_score(y_true, y_pred):.4f}")
print(f"精确率 (Precision): {precision_score(y_true, y_pred):.4f}")
print(f"召回率 (Recall): {recall_score(y_true, y_pred):.4f}")
print(f"F1分数 (F1-Score): {f1_score(y_true, y_pred):.4f}")
print(f"\n分类报告:\n{classification_report(y_true, y_pred,
target_names=['负面', '正面'])}")
evaluate_model("Logistic回归(默认参数)", y_test, y_pred)
python
# ==================== 5. 网格搜索调参 ====================
param_grid = {
'C': [0.01, 0.1, 1, 10, 100],
'penalty': ['l1', 'l2'],
'solver': ['liblinear']
}
grid_search = GridSearchCV(
LogisticRegression(random_state=42, max_iter=1000),
param_grid,
cv=5,
scoring='f1',
n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"\n最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证F1分数: {grid_search.best_score_:.4f}")
# 使用最佳模型预测
best_model = grid_search.best_estimator_
y_pred_best = best_model.predict(X_test)
evaluate_model("Logistic回归(最优参数)", y_test, y_pred_best)
python
# ==================== 6. 特征重要性分析 ====================
# 获取特征权重
feature_names = tfidf.get_feature_names_out()
coefficients = best_model.coef_[0]
# 找出最重要的正面和负面特征词
top_k = 10
top_positive_idx = np.argsort(coefficients)[-top_k:]
top_negative_idx = np.argsort(coefficients)[:top_k]
print("\n" + "="*50)
print("特征重要性分析")
print("="*50)
print("\n正面情感关键词(权重最高):")
for idx in reversed(top_positive_idx):
print(f" {feature_names[idx]}: {coefficients[idx]:.4f}")
print("\n负面情感关键词(权重最低):")
for idx in top_negative_idx:
print(f" {feature_names[idx]}: {coefficients[idx]:.4f}")
python
# ==================== 7. 可视化 ====================
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 图1: 混淆矩阵
cm = confusion_matrix(y_test, y_pred_best)
im = axes[0].imshow(cm, cmap='Blues')
axes[0].set_xticks([0, 1])
axes[0].set_yticks([0, 1])
axes[0].set_xticklabels(['负面', '正面'])
axes[0].set_yticklabels(['负面', '正面'])
axes[0].set_xlabel('预测标签')
axes[0].set_ylabel('真实标签')
axes[0].set_title('混淆矩阵')
for i in range(2):
for j in range(2):
axes[0].text(j, i, cm[i, j], ha='center', va='center',
fontsize=20, color='white' if cm[i,j] > cm.max()/2 else 'black')
plt.colorbar(im, ax=axes[0])
# 图2: 正则化强度对性能的影响
C_values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
train_scores, test_scores = [], []
for C in C_values:
model = LogisticRegression(C=C, solver='liblinear',
random_state=42, max_iter=1000)
model.fit(X_train, y_train)
train_scores.append(f1_score(y_train, model.predict(X_train)))
test_scores.append(f1_score(y_test, model.predict(X_test)))
axes[1].semilogx(C_values, train_scores, 'o-', label='训练集F1', linewidth=2)
axes[1].semilogx(C_values, test_scores, 's-', label='测试集F1', linewidth=2)
axes[1].set_xlabel('正则化参数 C')
axes[1].set_ylabel('F1分数')
axes[1].set_title('正则化强度对模型性能的影响')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('logistic_regression_results.png', dpi=150, bbox_inches='tight')
plt.show()
python
# ==================== 8. 新评价预测示例 ====================
new_reviews = [
"宝贝收到了,质量很好,很满意这次购物",
"垃圾商品,再也不买了",
"还行吧,一般般",
"超级喜欢,已经推荐给朋友了"
]
new_reviews_cut = [preprocess_text(r) for r in new_reviews]
new_X = tfidf.transform(new_reviews_cut)
predictions = best_model.predict(new_X)
probabilities = best_model.predict_proba(new_X)
print("\n" + "="*50)
print("新评价预测结果")
print("="*50)
for review, pred, prob in zip(new_reviews, predictions, probabilities):
sentiment = "正面" if pred == 1 else "负面"
confidence = max(prob) * 100
print(f"\n评价: {review}")
print(f"预测: {sentiment} (置信度: {confidence:.1f}%)")
7.3 运行结果
数据集大小: 218
正面评价: 108, 负面评价: 110
分词示例:
原文: 质量非常好,穿着很舒服,下次还会购买
分词: 质量 非常 好 , 穿着 很 舒服 , 下次 还会 购买
特征矩阵维度: (218, 182)
==================================================
模型: Logistic回归(默认参数)
==================================================
准确率 (Accuracy): 0.9773
精确率 (Precision): 0.9565
召回率 (Recall): 1.0000
F1分数 (F1-Score): 0.9778
最佳参数: {'C': 1, 'penalty': 'l2', 'solver': 'liblinear'}
最佳交叉验证F1分数: 0.9815
==================================================
特征重要性分析
==================================================
正面情感关键词(权重最高):
满意: 1.2543
推荐: 1.1876
喜欢: 1.0234
好评: 0.9567
质量好: 0.8901
负面情感关键词(权重最低):
差评: -1.3421
失望: -1.2108
退货: -1.1543
差: -0.9876
质量差: -0.8765
==================================================
新评价预测结果
==================================================
评价: 宝贝收到了,质量很好,很满意这次购物
预测: 正面 (置信度: 94.2%)
评价: 垃圾商品,再也不买了
预测: 负面 (置信度: 87.6%)
评价: 还行吧,一般般
预测: 负面 (置信度: 56.3%)
评价: 超级喜欢,已经推荐给朋友了
预测: 正面 (置信度: 96.8%)
8. 算法特点总结
8.1 优势与局限
| 优势 | 局限 |
|---|---|
| ✅ 模型简单,可解释性强(系数即特征重要性) | ❌ 只能处理线性可分问题 |
| ✅ 训练速度快,适合大规模数据 | ❌ 对特征工程依赖较强 |
| ✅ 输出概率值,便于阈值调整和业务决策 | ❌ 容易欠拟合复杂非线性关系 |
| ✅ 不易过拟合(尤其加正则化后) | ❌ 对多重共线性敏感 |
| ✅ 易于扩展到多分类(Softmax) | ❌ 对异常值较敏感 |
8.2 个人思考与总结
我的思考:
Logistic回归是理解深度学习的基石:神经网络的输出层(二分类)本质上就是一个Logistic回归。理解了Logistic回归的前向传播、损失函数、梯度下降,就掌握了深度学习的核心范式。
特征工程是关键:由于Logistic回归只能学习线性决策边界,如果原始特征与标签之间存在非线性关系,需要通过特征变换(如多项式特征、TF-IDF、词嵌入)来增强表达能力。
概率输出的价值:在实际业务中,往往不只是需要一个分类结果,更需要知道模型对这个结果有多"确信"。比如在电商评价分析中,对于置信度较低的评价可以人工复核。
正则化的选择策略:
- 如果希望做特征选择(如筛选关键情感词),使用L1正则化
- 如果特征间存在多重共线性,使用L2正则化
- 如果不确定,先用L2(默认),观察效果后再调整
在NLP任务中的应用思考:
- Logistic回归 + TF-IDF 是文本分类的经典基线模型
- 虽然深度学习模型(如BERT)效果更好,但Logistic回归训练快、可解释,适合快速验证想法
- 特征权重可以直接告诉我们哪些词对分类最重要
笔记来源:常同学