本文目录导读:

我来详细讲解如何使用TextRank算法进行文本摘要提取,包括完整的Python实现案例。
TextRank算法原理
TextRank是一种基于图的排序算法,通过构建词或句子的图结构,计算节点的重要性来提取关键词或摘要。
完整实现案例
基础版:使用jieba实现
import jieba
import jieba.analyse
import numpy as np
from collections import defaultdict
import re
class TextRankSummarizer:
def __init__(self):
self.damping = 0.85 # 阻尼系数
self.max_iter = 200 # 最大迭代次数
self.min_diff = 0.001 # 收敛阈值
def preprocess(self, text):
"""文本预处理"""
# 分句
sentences = re.split('[。!?!?]', text)
sentences = [s.strip() for s in sentences if len(s.strip()) > 5]
return sentences
def sentence_similarity(self, sent1, sent2):
"""计算句子相似度"""
# 分词并去重
words1 = set(jieba.cut(sent1))
words2 = set(jieba.cut(sent2))
# 如果句子为空,返回0
if not words1 or not words2:
return 0
# 计算词交集
intersection = words1 & words2
# 使用Jaccard相似度
return len(intersection) / (len(words1) + len(words2) - len(intersection))
def build_similarity_matrix(self, sentences):
"""构建句子相似度矩阵"""
n = len(sentences)
similarity_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
if i != j:
similarity_matrix[i][j] = self.sentence_similarity(
sentences[i], sentences[j]
)
# 归一化
for i in range(n):
row_sum = np.sum(similarity_matrix[i])
if row_sum > 0:
similarity_matrix[i] /= row_sum
return similarity_matrix
def textrank(self, similarity_matrix):
"""TextRank算法实现"""
n = len(similarity_matrix)
scores = np.ones(n) / n # 初始分数
for _ in range(self.max_iter):
prev_scores = np.copy(scores)
# 更新分数
scores = (1 - self.damping) + self.damping * \
similarity_matrix.T.dot(scores)
# 检查收敛
if np.sum(np.abs(scores - prev_scores)) < self.min_diff:
break
return scores
def summarize(self, text, num_sentences=3):
"""生成摘要"""
# 预处理
sentences = self.preprocess(text)
if len(sentences) <= num_sentences:
return text
# 构建相似度矩阵
similarity_matrix = self.build_similarity_matrix(sentences)
# 计算TextRank分数
scores = self.textrank(similarity_matrix)
# 获取最重要的句子
ranked_sentences = sorted(
[(score, sent) for score, sent in zip(scores, sentences)],
reverse=True
)
# 选取得分最高的句子
summary_sentences = [sent for _, sent in ranked_sentences[:num_sentences]]
# 按原顺序排序
summary_sentences.sort(key=lambda x: sentences.index(x))
return '。'.join(summary_sentences) + '。'
# 使用示例
if __name__ == "__main__":
text = """
人工智能(Artificial Intelligence,简称AI)是计算机科学的一个分支,
它试图理解智能的本质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。
人工智能的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大。
可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。
人工智能可以对人的意识、思维的信息过程的模拟。
人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
深度学习和机器学习是人工智能的重要分支,它们让计算机能够从数据中学习和改进。
人工智能的发展已经对各行各业产生了深远的影响,从医疗诊断到自动驾驶,
从语音助手到智能客服,AI正在改变我们的生活方式。
"""
summarizer = TextRankSummarizer()
summary = summarizer.summarize(text, num_sentences=3)
print("原文长度:", len(text))
print("摘要长度:", len(summary))
print("\n原文:")
print(text)
print("\n摘要:")
print(summary)
进阶版:使用NetworkX优化
import jieba
import networkx as nx
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
class AdvancedTextRankSummarizer:
def __init__(self):
self.damping = 0.85
def split_sentences(self, text):
"""智能分句"""
# 处理常见标点
text = re.sub('([。!?\?!])([^"\'》)])', r"\1\n\2", text)
text = re.sub('(\.{6})([^"\'》)])', r"\1\n\2", text)
text = re.sub('(\…{2})([^"\'》)])', r"\1\n\2", text)
text = re.sub('([。!?\?!\.{6}\…{2}]["\'》)])([^"\'》)])', r"\1\n\2", text)
sentences = text.split('\n')
sentences = [s.strip() for s in sentences if len(s.strip()) > 5]
return sentences
def get_sentence_vectors(self, sentences):
"""获取句子向量表示"""
vectorizer = TfidfVectorizer(tokenizer=jieba.lcut, max_features=5000)
vectors = vectorizer.fit_transform(sentences)
return vectors.toarray()
def build_graph(self, sentences):
"""构建句子图"""
# 获取句子向量
vectors = self.get_sentence_vectors(sentences)
# 计算相似度矩阵
similarity_matrix = cosine_similarity(vectors)
# 构建图
graph = nx.Graph()
# 添加节点
for i, sentence in enumerate(sentences):
graph.add_node(i, text=sentence)
# 添加边
for i in range(len(sentences)):
for j in range(i+1, len(sentences)):
if similarity_matrix[i][j] > 0.1: # 设置阈值
graph.add_edge(i, j, weight=similarity_matrix[i][j])
return graph
def summarize(self, text, num_sentences=3):
"""生成摘要"""
sentences = self.split_sentences(text)
if len(sentences) <= num_sentences:
return text
# 构建图
graph = self.build_graph(sentences)
# 使用PageRank算法计算句子重要性
scores = nx.pagerank(graph, alpha=self.damping)
# 排序并选择重要句子
ranked_sentences = sorted(
[(scores[i], i, sentences[i]) for i in range(len(sentences))],
reverse=True
)
# 选择最重要的句子
summary_indices = [item[1] for item in ranked_sentences[:num_sentences]]
summary_indices.sort()
summary = '。'.join([sentences[i] for i in summary_indices]) + '。'
return summary
# 使用示例
if __name__ == "__main__":
summarizer = AdvancedTextRankSummarizer()
text = """
自然语言处理是人工智能的一个重要分支,它研究如何让计算机理解和生成人类语言。
近年来,随着深度学习技术的发展,自然语言处理取得了突破性进展。
特别是Transformer架构的出现,极大地推动了机器翻译、文本生成等任务的发展。
BERT、GPT等预训练模型的出现,更是让自然语言处理进入了新的时代。
这些模型在大规模语料上进行预训练,然后通过微调适应各种下游任务。
自然语言处理技术已经广泛应用于智能客服、机器翻译、情感分析等领域。
随着技术的不断进步,自然语言处理将在更多领域发挥重要作用。
"""
summary = summarizer.summarize(text, num_sentences=2)
print("摘要生成结果:")
print(summary)
完整的工具类封装
import jieba
import jieba.analyse
import numpy as np
import networkx as nx
from sklearn.feature_extraction.text import TfidfVectorizer
import re
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class TextRankSummarizer:
"""
TextRank摘要提取器
支持关键词提取和摘要生成
"""
def __init__(self, use_networkx=True):
"""
初始化摘要提取器
Args:
use_networkx: 是否使用NetworkX库(更稳定)
"""
self.use_networkx = use_networkx
self.damping = 0.85
self.max_iter = 200
self.min_diff = 0.001
def clean_text(self, text):
"""清理文本"""
# 移除多余空格和换行
text = re.sub(r'\s+', ' ', text)
# 移除特殊字符
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:""''()\(\)\[\]]', '', text)
return text.strip()
def split_sentences(self, text):
"""分句"""
# 按标点分句
text = re.sub('([。!?\?!;;])', r'\1\n', text)
sentences = text.split('\n')
# 过滤空句子和太短的句子
sentences = [s.strip() for s in sentences if len(s.strip()) > 10]
return sentences
def calculate_similarity(self, sent1, sent2, method='jaccard'):
"""
计算句子相似度
Args:
sent1: 句子1
sent2: 句子2
method: 相似度计算方法 ('jaccard', 'cosine', 'tfidf')
"""
if method == 'jaccard':
words1 = set(jieba.lcut(sent1))
words2 = set(jieba.lcut(sent2))
if not words1 or not words2:
return 0
intersection = words1 & words2
return len(intersection) / (len(words1) + len(words2) - len(intersection))
elif method == 'cosine':
# 简单余弦相似度
words1 = list(jieba.lcut(sent1))
words2 = list(jieba.lcut(sent2))
# 构建词频向量
all_words = list(set(words1 + words2))
vec1 = np.array([words1.count(w) for w in all_words])
vec2 = np.array([words2.count(w) for w in all_words])
if np.linalg.norm(vec1) == 0 or np.linalg.norm(vec2) == 0:
return 0
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
elif method == 'tfidf':
# 使用TF-IDF
vectorizer = TfidfVectorizer(tokenizer=jieba.lcut)
try:
vectors = vectorizer.fit_transform([sent1, sent2])
similarity = (vectors * vectors.T).toarray()[0][1]
return similarity
except:
return 0
else:
raise ValueError(f"Unknown similarity method: {method}")
def build_similarity_matrix(self, sentences, similarity_method='jaccard'):
"""构建相似度矩阵"""
n = len(sentences)
similarity_matrix = np.zeros((n, n))
print(f"构建相似度矩阵: {n} x {n}")
for i in range(n):
for j in range(i+1, n):
similarity = self.calculate_similarity(
sentences[i], sentences[j],
method=similarity_method
)
similarity_matrix[i][j] = similarity
similarity_matrix[j][i] = similarity
return similarity_matrix
def textrank_with_networkx(self, similarity_matrix):
"""使用NetworkX的PageRank算法"""
n = len(similarity_matrix)
# 构建图
graph = nx.Graph()
graph.add_nodes_from(range(n))
# 添加边
for i in range(n):
for j in range(i+1, n):
if similarity_matrix[i][j] > 0:
graph.add_edge(i, j, weight=similarity_matrix[i][j])
# 计算PageRank
scores = nx.pagerank(graph, alpha=self.damping)
return [scores[i] for i in range(n)]
def textrank_manual(self, similarity_matrix):
"""手动实现TextRank"""
n = len(similarity_matrix)
# 归一化相似度矩阵
normalized_matrix = np.copy(similarity_matrix)
for i in range(n):
row_sum = np.sum(normalized_matrix[i])
if row_sum > 0:
normalized_matrix[i] /= row_sum
# 初始化分数
scores = np.ones(n) / n
# 迭代计算
for iteration in range(self.max_iter):
prev_scores = np.copy(scores)
# 更新分数
scores = (1 - self.damping) + self.damping * \
normalized_matrix.T.dot(scores)
# 检查收敛
diff = np.sum(np.abs(scores - prev_scores))
if diff < self.min_diff:
print(f"收敛于第{iteration+1}次迭代")
break
return scores
def extract_keywords(self, text, topK=10):
"""提取关键词"""
keywords = jieba.analyse.textrank(text, topK=topK, withWeight=True)
return keywords
def summarize(self, text, num_sentences=3, similarity_method='jaccard'):
"""
生成摘要
Args:
text: 输入文本
num_sentences: 摘要句子数量
similarity_method: 相似度计算方法
Returns:
summary: 生成的摘要
sentences_with_scores: 每个句子的得分
"""
# 清理文本
text = self.clean_text(text)
# 分句
sentences = self.split_sentences(text)
print(f"共{len(sentences)}个句子")
if len(sentences) <= num_sentences:
return text, [(sentences[i], 1.0) for i in range(len(sentences))]
# 构建相似度矩阵
similarity_matrix = self.build_similarity_matrix(sentences, similarity_method)
# 计算TextRank分数
if self.use_networkx:
scores = self.textrank_with_networkx(similarity_matrix)
else:
scores = self.textrank_manual(similarity_matrix)
# 排序句子
sentences_with_scores = list(zip(sentences, scores))
sentences_with_scores.sort(key=lambda x: x[1], reverse=True)
# 选择重要句子
important_sentences = sentences_with_scores[:num_sentences]
# 按原顺序排序
selected_indices = [sentences.index(s[0]) for s in important_sentences]
selected_indices.sort()
# 生成摘要
summary = '。'.join([sentences[i] for i in selected_indices])
if summary and not summary.endswith('。'):
summary += '。'
# 返回所有句子的得分(已排序)
all_scores = sorted(sentences_with_scores, key=lambda x: sentences.index(x[0]))
return summary, all_scores
# 使用示例
def demo():
"""演示函数"""
# 创建摘要提取器
summarizer = TextRankSummarizer(use_networkx=True)
# 测试文本
text = """
人工智能(Artificial Intelligence)是计算机科学的一个重要分支。
它致力于研究如何让计算机模拟人类的智能行为,包括学习、推理、感知和理解自然语言等能力。
近年来,深度学习技术的突破让AI取得了前所未有的进展。
在图像识别领域,卷积神经网络(CNN)让计算机能够准确识别和理解图像内容。
在自然语言处理领域,循环神经网络(RNN)和Transformer架构让机器翻译和文本生成更加自然。
特别是BERT、GPT等预训练模型的提出,开创了自然语言处理的新范式。
这些模型通过在大规模语料上进行预训练,学习到了丰富的语言知识。
然后通过微调,可以适应各种特定的自然语言处理任务。
人工智能已经在医疗诊断、自动驾驶、智能客服等领域得到了广泛应用。
随着技术的不断进步,AI将会在更多领域发挥重要作用,推动社会进步。
"""
print("="*50)
print("原文:")
print(text)
print("="*50)
# 提取关键词
print("\n关键词提取结果:")
keywords = summarizer.extract_keywords(text, topK=5)
for word, weight in keywords:
print(f" {word}: {weight:.4f}")
# 生成摘要
print("\n摘要生成结果:")
summary, sentences_scores = summarizer.summarize(text, num_sentences=3)
print(summary)
print("\n句子得分详情:")
for sentence, score in sentences_scores:
print(f" {score:.4f}: {sentence[:50]}...")
if __name__ == "__main__":
demo()
优化建议
性能优化
# 使用缓存提高重复计算效率
from functools import lru_cache
@lru_cache(maxsize=1024)
def cached_similarity(sent1, sent2):
# 缓存相似度计算结果
pass
# 使用更高效的数据结构
from collections import Counter
def fast_similarity(sent1, sent2):
words1 = Counter(jieba.lcut(sent1))
words2 = Counter(jieba.lcut(sent2))
# 快速计算交集
intersection = sum(min(words1[w], words2[w]) for w in words1 if w in words2)
return intersection
质量优化
def enhanced_summarize(self, text, num_sentences=3):
"""
增强版摘要生成
考虑位置信息、长度惩罚等因素
"""
sentences = self.split_sentences(text)
# 计算基础得分
base_scores = self.calculate_textrank_scores(sentences)
# 位置权重(越靠前越重要)
position_weights = [1.0 / (i + 1) for i in range(len(sentences))]
# 长度惩罚(过长的句子适当降低权重)
length_weights = []
for sent in sentences:
length = len(sent)
if 20 <= length <= 100:
length_weights.append(1.0)
else:
length_weights.append(max(0.5, 1.0 - abs(length - 50) / 100))
# 综合得分
final_scores = [
base * pos * length
for base, pos, length in zip(base_scores, position_weights, length_weights)
]
# 选择最重要的句子
# ...
实际应用建议
- 文本预处理:根据具体领域进行针对性预处理
- 参数调优:根据文本特点调整相似度阈值和阻尼系数
- 多方法融合:结合TF-IDF、LDA等方法提高效果
- 并行计算:处理大量文本时使用多线程/多进程
这个实现涵盖了TextRank摘要提取的核心原理和完整代码,可以根据实际需求进行调整和优化。