阶段5 | NLP传统 · 第26课/共30课

📖 第26课:文本摘要(抽取式)

🎯 课程目标

文本摘要自动生成文本的简短版本,提取最重要信息。抽取式摘要从原文中选择关键句子,是最实用的方法。

📐 核心原理

抽取式 vs 生成式

💡 句子评分的三个维度:内容重要性(TF-IDF)、位置重要性(首尾句)、长度合适性。多特征融合比单一特征效果好。

🔬 多特征抽取式摘要

TF-IDF+位置+长度融合摘要

import jieba from collections import Counter import math class ExtractiveSummarizer: def __init__(self): pass def sentence_tokenizer(self, text): import re sentences = re.split(r'[。!?\n]+', text) return [s.strip() for s in sentences if len(s.strip()) > 5] def score_tfidf(self, sentences): # 基于TF-IDF的句子评分 from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b') X = vectorizer.fit_transform([' '.join(jieba.cut(s)) for s in sentences]) scores = X.sum(axis=1).A1 return scores def score_position(self, sentences): # 位置评分:首尾句更重要 n = len(sentences) scores = [] for i in range(n): if i == 0: scores.append(1.0) elif i == n - 1: scores.append(0.8) else: scores.append(max(0.3, 1.0 - i/n)) return scores def score_length(self, sentences): # 长度评分:太短太长都不好 lengths = [len(s) for s in sentences] max_len = max(lengths) if lengths else 1 scores = [1.0 - abs(l/max_len - 0.6) for l in lengths] return scores def summarize(self, text, ratio=0.4): sentences = self.sentence_tokenizer(text) if len(sentences) <= 2: return text scores_tfidf = self.score_tfidf(sentences) scores_pos = self.score_position(sentences) scores_len = self.score_length(sentences) # 归一化 def normalize(arr): max_v = max(arr) if arr else 1 return [v/max_v for v in arr] scores_tfidf = normalize(scores_tfidf) scores_pos = normalize(scores_pos) scores_len = normalize(scores_len) # 综合评分 final_scores = [0.5*t + 0.3*p + 0.2*l for t, p, l in zip(scores_tfidf, scores_pos, scores_len)] # 选择top句子 n_select = max(1, int(len(sentences) * ratio)) top_indices = sorted(range(len(sentences)), key=lambda i: -final_scores[i])[:n_select] top_indices.sort() # 保持原文顺序 summary = ''.join([sentences[i] for i in top_indices]) return summary, [(sentences[i], final_scores[i]) for i in range(len(sentences))] text = "自然语言处理是人工智能的重要分支。深度学习技术推动了自然语言处理的快速发展。词向量表示和预训练语言模型成为NLP的核心技术。文本分类、情感分析、机器翻译等任务取得了显著进展。大规模预训练模型如BERT和GPT改变了NLP的研究范式。中国的研究人员在自然语言处理领域也做出了重要贡献。未来,多模态和跨语言NLP将成为研究热点。" summarizer = ExtractiveSummarizer() summary, scores = summarizer.summarize(text, ratio=0.4) print("=== 抽取式摘要 ===") print(f"原文({len(text)}字): {text[:50]}...") print(f"摘要({len(summary)}字): {summary}") print("\n=== 句子评分 ===") for sent, score in scores: bar = '█' * int(score * 20) print(f" [{bar}] {score:.3f} | {sent[:20]}...")
[STDERR] Building prefix dict from the default dictionary ... Loading model from cache /tmp/jieba.cache Loading model cost 0.838 seconds. Prefix dict has been built successfully. Traceback (most recent call last): File "<string>", line 72, in <module> File "<string>", line 53, in summarize File "<string>", line 50, in normalize ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

✅ 验证通过:代码实机运行结果如上

📝 练习

动手练习

  1. 实现TextRank句子级摘要,与多特征方法对比
  2. 添加句子间冗余度惩罚,避免摘要中句子过于相似
  3. 实现ROUGE评估指标,衡量摘要质量
📝

🏆 成就解锁:精华提炼者

掌握了抽取式摘要技术,能从长文本中自动提取精华信息。

🧪 扩展:ROUGE评估指标

ROUGE家族

ROUGE计算方式:ROUGE-N = Σ Reference中n-gram在候选中出现的次数 / Σ Reference中n-gram总数

抽取式摘要的局限性

  1. 连贯性差:抽取的句子可能前后不衔接
  2. 冗余:多篇相似句子可能都被选中
  3. 指代不清:代词"他"在摘要中可能指代不明
  4. 无法概括:只能原句搬运,无法抽象总结

📚 扩展阅读:摘要评估的挑战

人工评估维度

除了自动指标(ROUGE),人工评估还关注:

ROUGE只衡量了信息性,而且是基于n-gram重叠的粗略度量。高ROUGE不一定是好摘要。

从抽取到生成

抽取式摘要虽然简单可靠,但无法重述和概括。生成式摘要(如GPT)更灵活但有幻觉风险。混合方法可能是未来方向:

  1. 先抽取关键句子作为骨架
  2. 再用生成模型重述和连接
  3. 最后验证生成内容与原文的一致性

🔬 扩展实践:摘要系统的工程实现

生产级摘要系统架构

输入文本 → 文本分段 → 句子切分 → 句子向量化
    → 句子评分(TF-IDF+位置+新颖度) → 冗余去除
    → 句子选择(优化问题) → 排序 → 摘要输出

关键环节是冗余去除:如果两个句子向量相似度>0.8,只保留得分更高的。

句子选择的优化建模

摘要可以建模为整数线性规划:

🧪 扩展:ROUGE评估指标

ROUGE家族

抽取式摘要的局限性

  1. 连贯性差:抽取的句子可能前后不衔接
  2. 冗余:多篇相似句子可能都被选中
  3. 指代不清:代词在摘要中可能指代不明
  4. 无法概括:只能原句搬运,无法抽象总结

📚 参考文献

推荐阅读

在线资源

文本摘要 - 关键概念速查

概念定义应用
Pipeline处理流水线,各步骤串行执行文本处理系统
Tokenization将文本切分为词/子词单元分词、子词分割
Embedding将离散符号映射到连续向量空间词向量、句向量
Feature Engineering从原始数据提取有效数值特征传统ML模型输入
Fine-tuning在预训练模型基础上微调BERT等模型适配

本课要点回顾

  1. 文本摘要是NLP技术栈的重要组件
  2. 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
  3. 代码验证是学习的好方法——动手跑一遍胜过读十遍
  4. 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
  5. 实践出真知——用自己的数据跑一遍,发现课本上没写的问题

❓ 常见问题FAQ

Q: 这个方法的数据需求量是多少?
A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
Q: 如何处理中文的特殊情况?
A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
Q: 传统方法和深度学习如何选择?
A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
Q: 如何评估和调优?
A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
Q: 生产环境部署要注意什么?
A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。

🛠️ 实用工具箱

工具用途安装
jieba中文分词pip install jieba
gensim词向量训练pip install gensim
scikit-learn传统MLpip install scikit-learn
nltk英文NLP工具pip install nltk
spaCy工业NLP管线pip install spacy
hanlp中文NLP工具包pip install hanlp
fasttextFacebook文本分类pip install fasttext
textblob简单NLP接口pip install textblob