问题与目标

两类模型使用同一份文本特征,但一个比较对数概率,另一个比较到分类边界的有符号间隔。
同一个文本分类问题可以从条件概率或分类间隔出发。对比模型假设,比只比较一次分数更有迁移价值。
完成标准:用自建短文本训练朴素贝叶斯和线性 SVM,比较预测及各自边界。
核心概念
多项式朴素贝叶斯根据词在类别中的出现概率分类,并假设给定类别后特征条件独立。假设很强,但在词袋文本上常是有效基线。
SVM 寻找间隔尽量大的分类边界;软间隔允许部分样本违反边界,C 控制惩罚强度。核函数可表达非线性边界,但调参、计算和解释成本更高。本例使用适合稀疏文本的线性 SVM。
朴素贝叶斯怎样形成判断
贝叶斯公式比较 P(类别) × P(特征|类别)。文本词袋中,每个词的类别条件概率来自训练语料计数;拉普拉斯平滑给未见词保留非零概率,避免整个乘积变成零。实际实现常在对数空间相加,防止许多小概率相乘后数值下溢。
| 模型 | 特征假设 | 常见输入 |
|---|---|---|
| GaussianNB | 每类连续特征近似高斯 | 连续数值 |
| MultinomialNB | 非负计数或权重 | 词频、TF-IDF |
| BernoulliNB | 二值出现/未出现 | 二值词袋 |
条件独立假设通常不完全成立,但模型仍可能作为快速、低数据量基线。
SVM 的间隔与 C
支持向量是距离边界最近、真正影响边界的样本。较小 C 容许更多训练错误以换取宽间隔,较大 C 更努力拟合训练样本,可能对异常值敏感。
线性不可分时,RBF 等核函数隐式映射到高维空间。核 SVM 的 C 和 gamma 都会影响边界,且训练成本随样本量快速增加,因此先尝试线性模型。
可运行实现
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline
from sklearn.svm import LinearSVC
texts = [
"任务完成 输出正常", "处理成功 文件已保存", "校验通过 结果可用",
"运行结束 没有错误", "服务超时 请重试", "解析失败 格式错误",
"连接中断 任务失败", "内存不足 执行终止",
]
labels = ["normal"] * 4 + ["error"] * 4
samples = ["文件解析失败", "任务完成并保存"]
for estimator in (MultinomialNB(), LinearSVC(C=1.0)):
model = make_pipeline(TfidfVectorizer(), estimator)
model.fit(texts, labels)
print(type(estimator).__name__, model.predict(samples).tolist())
输入是自建中文运行消息,输出是两条新文本的类别。样本极少,仅验证处理链;真实文本分类还要独立测试、分词策略和错误样本分析。
结果不只看预测标签
朴素贝叶斯可以查看类别概率,但独立假设可能使概率过于极端;LinearSVC 提供 decision_function 间隔分数,不是概率。业务必须使用概率阈值时,应在独立数据上校准。
示例用空格显式分隔词语;真实中文文本需要固定分词器、停用词和词表版本,并把向量器放入 Pipeline 防止泄漏。
手算一次朴素贝叶斯
假设 normal 类共有 8 个词,error 类共有 6 个词,词表大小为 5。“失败”在两类中分别出现 0 次和 3 次。使用加一平滑后:
P(失败 | normal) = (0 + 1) / (8 + 5) = 1/13P(失败 | error) = (3 + 1) / (6 + 5) = 4/11
另一个词使用同样方式计算,然后与类别先验概率相乘。实现中计算对数,把乘法改为加法:
import math
log_normal = math.log(0.5) + math.log(1 / 13)
log_error = math.log(0.5) + math.log(4 / 11)
print(round(log_normal, 3), round(log_error, 3))
这个简化计算只演示单词如何影响类别得分。完整文本会累加每个词的对数概率,词频也会影响贡献次数。
比较 SVM 的 C
只报告 C=1 的结果,无法知道边界是否过于宽松或过度追随训练样本。可以把向量化和模型都放入交叉验证:
from sklearn.model_selection import StratifiedKFold, cross_val_score
folds = StratifiedKFold(n_splits=4, shuffle=True, random_state=42)
for c_value in (0.05, 0.2, 1.0, 5.0):
candidate = make_pipeline(
TfidfVectorizer(),
LinearSVC(C=c_value),
)
scores = cross_val_score(candidate, texts, labels, cv=folds, scoring="f1_macro")
print(c_value, round(scores.mean(), 3), round(scores.std(), 3))
上例数据量太小,各折分数可能剧烈波动,不足以选择生产参数。它的价值在于展示:预处理必须随每折重新拟合,候选参数要使用同一套划分。
从输出要求反推模型
| 需求 | 更适合的起点 | 原因 |
|---|---|---|
| 小样本词频文本基线 | MultinomialNB | 训练快,可查词条统计 |
| 高维稀疏文本分类 | LinearSVC | 线性间隔模型通常高效 |
| 必须输出可验证概率 | 朴素贝叶斯或校准后 SVM | 原始间隔不是概率 |
| 百万级样本且频繁重训 | 先评估线性随机优化模型 | 核 SVM 训练成本可能过高 |
进一步验证
- 向语料加入两条包含否定词的文本,观察词袋模型的误判。
- 分别记录预测标签、贝叶斯概率和 SVM 间隔,不混用三种输出。
- 用宏平均 F1 比较至少三个
C,同时报告均值和标准差。
常见问题与排查
- 朴素贝叶斯概率为零:平滑参数用于处理未见组合。
- 把
LinearSVC.decision_function当概率:它是带符号间隔,不是校准概率。 - 文本向量器在全量数据拟合:词表也会泄漏,应放入 Pipeline。
- 非线性核训练很慢:先建立线性基线,再按数据规模评估。
小结
朴素贝叶斯依赖概率假设,SVM 强调最大间隔。模型选择应结合特征形式、样本规模、概率需求和推理成本。
License: CC BY-NC 4.0
Updated 2 hours ago
Was this article helpful? Give it a like.
0 comments


