本节摘要:SOURCE 4.1 列举朴素贝叶斯、SVM、逻辑回归与随机森林——配合 TF-IDF 仍是强基线。本节给出选型表与 sklearn Pipeline 示例。
| 算法 | 假设/特点 | 文本场景 |
|---|---|---|
| 朴素贝叶斯 | 特征条件独立 | 垃圾邮件经典基线 |
| 线性 SVM | 最大间隔超平面 | 高维 TF-IDF |
| 逻辑回归 | 线性+sigmoid 概率 | 需概率输出 |
| 随机森林 | 非线性集成 | 特征已稠密化 |
from sklearn.pipeline import Pipeline from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.svm import LinearSVC clf = Pipeline([ ("tfidf", TfidfVectorizer(max_features=50000, ngram_range=(1, 2))), ("svc", LinearSVC()), ]) # clf.fit(train_texts, train_labels)
2010 年代工业界大量系统 = TF-IDF + LinearSVM;今天仍用于:
⚠️ 常见坑:未调 C 与 ngram_range——默认配置在中文短文本上往往欠拟合。
💡 关键直觉:传统 ML 不是「落后」,而是演化阶梯上必踩的一级。
朴素贝叶斯在文本上的数学很简单:P(类别|词) 正比于 P(类别) 乘以各词类内概率的连乘,基于「词在类内条件独立」的强假设。垃圾邮件场景它仍是极强基线,原因在于词袋空间的独立性假设虽不成立,但在分类决策边界附近往往足够用。计算时用对数概率避免下溢,sklearn 的多项式朴素贝叶斯已处理好这些细节。
SVM 在文本高维稀疏空间里表现好的原因是:文本特征维度高、样本相对少,SVM 的最大间隔原则不容易过拟合,线性核足够且快。LinearSVC 用损失函数近似实现线性 SVM,训练快、适合大规模。超参上值得调的是 C(正则强度)与 ngram_range;很多中文短文本任务里,默认配置会欠拟合,把 ngram_range 开到一阶到二阶、把 C 在 0.1 到 10 之间网格搜索,往往能带来几个点的提升。
逻辑回归适合需要概率输出的场景,其输出可直接用于置信度阈值与业务规则联动;随机森林在文本上一般不如线性模型,因为文本特征稀疏且语义非线性主要靠特征工程弥补,但当你把文本特征与稠密特征(如用户行为)拼接后,随机森林仍有用武之地。选型口诀可以概括为:稀疏特征用线性模型,稠密特征再考虑非线性。
训练时还有个常被忽略的细节:文本管线一定要把「分词到 TF-IDF 到模型」封装在同一个 Pipeline 里,用 fit 与 predict 一以贯之。这样验证集与线上输入走同一套特征流程,不会出现「训练时带标点、预测时没清洗」的错位。交叉验证建议用分层 K 折,在类别不均衡时保留每类的比例,比随机划分更可靠。网格搜索要在验证集上做,搜索完把最优参数在完整训练集上再拟合一次,然后只在测试集上报一次分数。
最后回到演化视角:2010 年代大量工业系统就是 TF-IDF 加 LinearSVM,今天它依然是冷启动、可解释、超低延迟场景的默认答案。当你用 BERT 微调获得更高分数时,也别忘了把传统基线分数记下来——没有基线的 SOTA 没有说服力,基线也是评估「深度模型增量到底值多少」的标尺。
from sklearn.pipeline import Pipeline from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.model_selection import GridSearchCV pipe = Pipeline([ ("tfidf", TfidfVectorizer(ngram_range=(1, 2), min_df=2)), ("clf", LogisticRegression(class_weight="balanced")), ]) param_grid = {"clf__C": [0.1, 1, 10]} search = GridSearchCV(pipe, param_grid, cv=5, scoring="f1_macro")
| 模型 | 文本场景强项 | 关键超参 |
|---|---|---|
| MultinomialNB | 垃圾邮件基线 | alpha |
| LinearSVC | 高维稀疏 | C, ngram_range |
| 逻辑回归 | 概率输出 | C, class_weight |
| 随机森林 | 稠密特征拼接 | n_estimators |
传统模型的迭代要建立在可对比的分数台账上,而不是凭印象。
| 实验 | 特征 | 模型 | 验证 F1 | 备注 |
|---|---|---|---|---|
| E0 | TF-IDF uni | LinearSVC | 基线 | 先跑通 |
| E1 | TF-IDF uni+bi | LinearSVC | 加 n-gram | 记录分数 |
| E2 | TF-IDF + 情感特征 | 逻辑回归 | 拼规则特征 | 对比提升 |
每次实验只改一行配置并记录;当深度模型上线时,与台账里的最佳传统模型对比,用数字回答「深度模型的增量值不值」。这份台账同时也是第 5 章评估报告的输入,避免「分数散落在聊天记录里、无法追溯」的常见混乱。
类别不均衡时,除了 class_weight,还可以考虑过采样少数类或欠采样多数类。过采样(如 SMOTE)会生成合成样本,在文本特征空间里不一定合理,容易引入噪声;更稳妥的文本做法是简单复制少数类样本或做同义词增强。欠采样多数类会损失信息,适合数据量充足的情况。选择采样还是加权,可以用验证集 Macro-F1 对比决定,不必一开始就固化某一种。记住:任何采样或加权都在训练集上做,测试集永远保持原始分布,否则评估结果会失真。