Python案例如何用TextRank摘要提取

wen python案例 2

本文目录导读:

Python案例如何用TextRank摘要提取

  1. TextRank算法原理
  2. 完整实现案例
  3. 完整的工具类封装
  4. 优化建议
  5. 实际应用建议

我来详细讲解如何使用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)
    ]
    # 选择最重要的句子
    # ...

实际应用建议

  1. 文本预处理:根据具体领域进行针对性预处理
  2. 参数调优:根据文本特点调整相似度阈值和阻尼系数
  3. 多方法融合:结合TF-IDF、LDA等方法提高效果
  4. 并行计算:处理大量文本时使用多线程/多进程

这个实现涵盖了TextRank摘要提取的核心原理和完整代码,可以根据实际需求进行调整和优化。

抱歉,评论功能暂时关闭!