4、基于机器学习的摘要方法:朴素贝叶斯、支持向量机在文本分类与摘要中的应用

好,咱们进入第四章。这一章聊的,是机器学习在文本摘要里最经典的两个模型——朴素贝叶斯和支持向量机。

说实话,我刚入行那会儿,觉得深度学习才是王道,朴素贝叶斯这种“老古董”早该淘汰了。后来在做一个金融舆情摘要项目时,数据量不大,标注样本才几千条,深度学习模型怎么调都过拟合。最后是朴素贝叶斯救了我一命。嗯,从那以后我再也不敢小看这些经典模型了。

4.1 朴素贝叶斯:简单但高效的文本分类器

朴素贝叶斯,说白了就是基于贝叶斯定理,加上一个“朴素”的假设——特征之间相互独立。

你想想看,在文本里,这个词出现和那个词出现,真的独立吗?显然不。但神奇的是,就算这个假设不成立,朴素贝叶斯在文本分类任务上依然表现很好。我个人习惯把它当作基线模型,先跑一遍看看数据质量。

4.1.1 数学原理回顾

公式其实很简单:

P(类别|文本) = P(文本|类别) * P(类别) / P(文本)

我们实际计算时,分母都一样,所以只需要比较分子大小:

P(类别|文本) ∝ P(类别) * ∏ P(词_i|类别)

这里有个坑——如果某个词在训练集中没出现过,概率直接变0。我曾经在这个问题上栽过跟头,后来加了拉普拉斯平滑才解决。

避坑指南: 我曾经在金融公告摘要任务中,直接用原始词频做朴素贝叶斯,结果模型把“风险”这个词当成负面信号,但很多正面公告里也会出现“风险控制”这个词。后来我改用TF-IDF加权,效果好了不少。

4.1.2 在摘要提取中的应用

朴素贝叶斯在摘要里怎么用?主要有两种方式:

  • 句子分类:把每个句子分成“该保留”和“该删除”两类
  • 主题识别:判断句子属于哪个主题,再按主题抽取关键句

我给大家看一段我当时写的代码,虽然简单,但很实用:

from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfVectorizer

# 假设我们有标注好的句子数据
sentences = ["公司净利润同比增长20%", "市场风险提示", ...]
labels = [1, 0, ...]  # 1表示保留,0表示删除

# 特征提取
vectorizer = TfidfVectorizer(max_features=5000)
X = vectorizer.fit_transform(sentences)

# 训练模型
model = MultinomialNB(alpha=1.0)  # alpha就是拉普拉斯平滑参数
model.fit(X, labels)

# 对新句子做预测
new_sentence = ["本季度营收创历史新高"]
X_new = vectorizer.transform(new_sentence)
pred = model.predict(X_new)  # 1表示应该保留
小技巧: 我建议你在做句子分类时,不要只用词频特征。加上句子位置、句子长度、是否包含数字等特征,效果会提升10%-15%。

4.2 支持向量机:小样本下的王者

支持向量机,简称SVM。这玩意儿在深度学习火起来之前,是文本分类的扛把子。

为什么SVM适合文本摘要?因为文本特征维度通常很高(几千到几万维),而SVM天生擅长处理高维稀疏数据。我在一个金融研报摘要项目里,用SVM配合RBF核,在只有2000条标注数据的情况下,F1值达到了0.87。换成深度学习,同等数据量下只有0.79。

4.2.1 SVM的核心思想

SVM说白了就是找一个超平面,把不同类别的数据分开,而且让这个超平面离两边数据都尽可能远。

为什么会这样?因为间隔越大,泛化能力越强。你想想看,如果分类边界紧贴着某个样本点,新来一个稍微不同的样本就可能分错。

下面是我画的一张图,展示了SVM在文本分类中的工作流程:

SVM文本分类与摘要提取流程 文本预处理 分词、去停用词、词干化 特征提取 TF-IDF / Word2Vec SVM分类器训练 线性核 / RBF核 / 多项式核 句子二分类 保留(1) vs 删除(0) 摘要句子排序 按置信度/位置排序 最终摘要输出 Top-K个句子 核函数选择建议 线性核:文本维度高 RBF核:非线性可分 多项式核:少用 ⚠️ 金融文本建议 先用线性核 效果不好再换RBF

4.2.2 代码实战:SVM做句子分类

下面是我在金融公告摘要项目中实际用过的代码,做了简化处理:

from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV

# 构建pipeline
pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(max_features=8000, ngram_range=(1,2))),
    ('svm', SVC(kernel='linear', C=1.0, class_weight='balanced'))
])

# 参数调优——我建议你一定要做这一步
param_grid = {
    'svm__C': [0.1, 1.0, 10.0],
    'svm__kernel': ['linear', 'rbf']
}

grid = GridSearchCV(pipeline, param_grid, cv=5, scoring='f1')
grid.fit(train_sentences, train_labels)

print(f"最佳参数: {grid.best_params_}")
print(f"最佳F1: {grid.best_score_:.4f}")

# 预测摘要句子
test_sentences = ["公司发布2023年年度报告", "本报告期内..." , ...]
predictions = grid.predict(test_sentences)
confidence = grid.decision_function(test_sentences)  # 置信度

# 按置信度排序,取前3个句子作为摘要
summary_indices = np.argsort(confidence)[-3:][::-1]
关键经验: 我在做金融文本摘要时发现,SVM的class_weight='balanced'参数特别重要。因为金融公告里,真正重要的句子往往只占20%-30%,如果不做类别平衡,模型会倾向于把所有句子都判为“不重要”。

4.3 朴素贝叶斯 vs SVM:怎么选?

这个问题我经常被问到。直接给结论:

对比维度 朴素贝叶斯 支持向量机
训练速度 极快,适合大规模数据 中等,数据量大时较慢
小样本表现 一般,需要较多数据 优秀,小样本也能出好效果
特征维度 适合高维,但特征独立性假设限制效果 非常适合高维稀疏数据
可解释性 强,可以看每个词的概率 中等,线性核可解释,RBF核较难
金融文本适用场景 快速原型、数据量大、特征独立性强 小样本、需要高精度、非线性关系

我个人习惯是:先用朴素贝叶斯跑一遍,看看数据质量和特征分布。如果效果不理想,再上SVM。说白了,朴素贝叶斯是“快而糙”,SVM是“慢而精”。

我的建议: 如果你做的是金融公告摘要,数据量在1万条以下,直接上SVM+线性核。如果数据量超过10万条,考虑朴素贝叶斯或者换成深度学习。中间那档,两个都试试,看哪个F1高就用哪个。

4.4 实际项目中的避坑经验

最后分享几个我在项目中踩过的坑:

  • 特征选择别偷懒:我曾经只用了unigram(单个词),结果模型把“不”和“好”分开考虑,把“不好”当成了正面词。后来加了bigram,问题解决。
  • 类别不平衡要处理:金融公告里,90%的句子都是“废话”,只有10%是核心信息。不做处理的话,模型会学成一个“全删模型”。
  • 不要迷信默认参数:SVM的C参数、核函数参数,一定要调。我见过太多人直接用默认参数,效果差就说SVM不行。
  • 评估指标要选对:准确率在摘要任务里基本没用。用F1或者ROUGE指标,才能真实反映模型好坏。

嗯,这一章就到这里。朴素贝叶斯和SVM虽然“老”,但在金融文本摘要这个场景下,它们依然是利器。关键是你要知道什么时候用哪个,怎么调参,怎么避坑。


专注资料整理