快速,准确的中文文本摘要实现方法

原创
2013/12/16 09:39
阅读数 8.2K

以前发布过一个Yaha库 ,里面有三种不同的摘要实现方法。它们都是基于关键字提取的,缺点很明显(测试地址):

  1. 基于关键字的摘要不够准确,会提供到不少关键字份量很大同时很垃圾的句子

  2. 基于cluster簇的办法,代码相对复杂,同时运行很慢

所以在实际项目中,我尝试过不少改进,但最好我发现了更好的摘要实现办法:

基于textrank它的思路是:

计算整个文章的各个句子之间的相似度

通过句子之间的相似性,建立一张句子之间的权重图,然后使用类似google的pagerank技术来获取权重最大的前面几个句子

上面具体算法自己参考网络文章,下面贴出具体的实现代码,非常简洁,配合numpy, scipy的矩阵运算库实现起来效率非常高:

# -*- coding: UTF-8 -*-
import cProfile as profile
import pstats
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import TfidfVectorizer
import networkx as nx

def textrank(content):
    sents = list(cut_sentence(content))
    vect = TfidfVectorizer(min_df=1,tokenizer=Tokenize)
    tfidf = vect.fit_transform(sents)
    tfidf_graph = tfidf*tfidf.T
    nx_graph = nx.from_scipy_sparse_matrix(tfidf_graph)
    scores = nx.pagerank(nx_graph)
    res = sorted(((scores[i],i) for i,s in enumerate(sents)), reverse=True)
    summary = [sents[i] for _,i in sorted(res[:3])]
    print 'text_rank', u'。 '.join(summary).replace('\r','').replace('\n','')+u'。'
    

'''
prof = profile.Profile()
prof.run('test4()')
stats = pstats.Stats(prof)
stats.strip_dirs().print_stats()
'''

可以看到,只需要通过9行代码便可以实现,关键的相似度计算直接使用scipy来优化。当然其中还调用了networkx库的pagerank函数,通过它可以得到textrank的权重最高的三个句子。

cut_sentence与Tokenize就只是中文分句与中文切词。可以从jieba或yaha库,或jieba的c++实现的Python封装版cppjiebapy(好绕口)

优点非常明显:

  1. 全程矩阵运算,速度快

  2. 通过句子之间的相似度,而不是单纯计算某些句子含有的关键字数量,考虑到了整个句子的信息

  3. 基于pagerank的算法,考虑到了句子的全文信息

继续优化:(考虑到整个语料的idf信息)

代码当中的fit_transform只是计算当前文章的idf,这样得到的结果只体现了当前文章的词的idf,难免不够准确。若要得到更准确的信息可以先输入给vect个很大的语料vect.fit(big_corpus),然后再对当前的content计算tfidf:vect.transform(sents)。同时vect训练了一个大的语料库之后可以保存到本地,在需要的时候再进行加载。


过程当中有疑问可加我开源项目交流QQ群:27498_3126 欢迎对数据处理有兴趣的同学多多交流。



展开阅读全文
打赏
2
14 收藏
分享
加载中
余争博主
在这个文件的最下面有cut_sentence函数:
https://github.com/jannson/yaha/blob/master/yaha/__init__.py
cut_list = frozenset(u".。!!?;?!。;")
def cut_sentence(txt):
if not isinstance(txt, unicode):
try:
txt = txt.decode('utf-8')
except UnicodeDecodeError:
txt = txt.decode('gbk','ignore')
str = ''
for c in txt:
if c in cut_list:
if str != '':
yield str
str = ''
else:
str += c
if str != '':
yield str
2014/02/20 11:31
回复
举报
这个必须要顶。。。
2014/02/19 23:57
回复
举报
余争博主
用pagerank_scipy有更好的性能
2014/01/06 11:52
回复
举报
余争博主
import networkx as nx

G=nx.gnp_random_graph(1000,0.01,directed=True)

%timeit nx.pagerank(G,tol=1e-10)
10 loops, best of 3: 157 ms per loop

%timeit nx.pagerank_scipy(G,tol=1e-10)
100 loops, best of 3: 14 ms per loop

%timeit nx.pagerank(G)
10 loops, best of 3: 137 ms per loop
2014/01/06 11:45
回复
举报
余争博主
改了几个错别字,呵呵。
2013/12/17 08:43
回复
举报
更多评论
打赏
5 评论
14 收藏
2
分享
返回顶部
顶部