jiaba关键词提取提速策略&基于word2vec的关键词提取方法&python中文编码问题&人人网的关键词提取策略

0.834字数 2251阅读 4450

1.jieba关键词提取提速

https://www.jianshu.com/p/450b84a07d3b
之前需要提取关键词,所以介绍了jieba关键词提取,这可能是最简单的提取关键词的方法了,此种方法代码少,(只有两行)但是速度非常慢,(实际上提取效果也很一般)对于大量文本的提取关键词效率太低,想要提速,那么就放弃使用结巴,转而利用sklearn自带tfidf来提取关键词。
大致流程如下:
1.先用读入文本然后用结巴分词切词。
2.降噪(只保留长度大于等于2的中文词,去除停用词)
3.使用sklearn中的计算各个词的tf-idf值。
4.对关键词按照其tf-idf的值从大到小排序。
5.取出表中前100个词。

用这个方法速度会比jieba自带的关键词提取至少快几十倍,而且这中间的分词部分还能使用jieba并行切词,分四核进一步提速以后能够快上百倍。
代码如下:


jieba.enable_parallel(4)

from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer

#简体可以使用encoding = 'utf-8',繁体需要使用encoding='gbk'
stopwords = [line.strip() for line in open('stopwords_fan.txt', 'r', encoding='gbk').readlines()] 
X,Y = ['\u4e00','\u9fa5']

#2.用sklearn的tfidf提取关键词
#2.1把文章全部合并再计算tfidf再提取关键词语 
#因为tfidf不止需要计算词频(tf)还需要求逆文档频率(idf),
#TF表示词条d在该文档中出现的频率。
#IDF的主要思想是:如果除去本文档包含词条t的文档越少,
#也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。
#具体计算公式见前一篇jieba分词博客的介绍部分。
#那么我们把所有文档合并,即总文档数为1,这样计算出来IDF值会偏大,很可能失去意义。
#Running time1: 4.5165 Seconds (不开启并行)
#此法提取一百个关键词的结果最终和jieba自带的分词结果重合度超过65%
tag = jieba.lcut(content.strip(),cut_all = False)
tag = [ i for i in tag if len(i) >= 2 and X<=i<=Y and i not in stopwords ]
tag_str = [' '.join(tag)]

vectorizer = CountVectorizer()
cif = vectorizer.fit_transform(tag_str)
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(cif )
word = vectorizer.get_feature_names()#得到所有切词以后的去重结果列表
word = np.array(word) #把词语列表转化为array数组形式 
weight = tfidf.toarray()#将tf-idf矩阵抽取出来
word_index = np.argsort(-weight)
word = word[word_index]#把word数组按照tfidf从大到小排序
tags = []
for i in range(100):
    tags.append(word[0][i])
    
##2.2分开所有文章做为语料,再计算总文章的tf-idf
#这样计算就是原生tfidf值所表达的意义
#
#Running time1: 5.256 Seconds (不开启并行)
'''
tag = []
corpus_list = []
vectorizer = CountVectorizer()
transformer = TfidfTransformer()
for i in range(len(list_content)):
    each_tag = jieba.lcut(list_content[i].strip(),cut_all = False)
    each_tag = [ i for i in each_tag if len(i) >= 2 and X<=i<=Y and i not in stopwords ]
    tag.append(each_tag)
    corpus_list.append([' '.join(tag[i])])

alltag_str = [y for x in corpus_list for y in x]
Alltag_str = ''
for i in range(len(list_content)):
    Alltag_str = Alltag_str + ' ' + alltag_str[i]
alltag_str = [Alltag_str]
corpus_list.append(alltag_str)

corpus = []
for i in range(len(corpus_list)):
    each_content_str = ''.join(corpus_list[i])
    corpus.append(each_content_str)

tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))
word=vectorizer.get_feature_names()
weight=tfidf.toarray()
word = np.array(word) #把词语列表转化为array数组形式 
weight = tfidf.toarray()#将tf-idf矩阵抽取出来
word_index = np.argsort(-weight)
word = word[word_index]#把word数组按照tfidf从大到小排序
tags = []
for i in range(100):
    tags.append(word[len(word)-1][i])
'''
t3 = time.time()
print (t3-t2)

两种方法速度都能比jieba的关键词提取快几十倍到上百倍(但是结巴的关键词提取可以抽取词性,可以把很多不需要的词性的词去除),我们比较提取前100个关键词的结果,第一种方法经过测试和jieba原生的关键词重合度为66%,第二种重合度为55%。

2.基于word2vec的关键词提取

通常我们在使用word2vec的时候都是使用Gensim库下的word2vec。如果了解word2vec特性我们就知道如果在单篇文章中使用word2vec来提取关键词效果肯定是不好的,例如我们可以试着对得到的词向量用k-means聚类出几个簇,把簇中心附近的词作为关键词提取出来看看效果。
在网上看到了一个已经使用大量语料训练好的中文word2vec模型,我试着用他们的方法加载这个模型提取关键词,对比原文,发现关键词的效果还不错。
模型下载链接: https://pan.baidu.com/s/1cL_KZA-j_b5i_Lvq79FjLw 密码: fyez

import numpy as np
import gensim
model = gensim.models.word2vec.Word2Vec.load('word2vec_wx')

#此函数计算某词对于模型中各个词的转移概率p(wk|wi)
def predict_proba(oword, iword):
    #获取输入词的词向量
    iword_vec = model[iword]
    #获取保存权重的词的词库
    oword = model.wv.vocab[oword]
    oword_l = model.trainables.syn1[oword.point].T
    dot = np.dot(iword_vec, oword_l)
    lprob = -sum(np.logaddexp(0, -dot) + oword.code*dot) 
    return lprob

#各个词对于某词wi转移概率的乘积即为p(content|wi),
#如果p(content|wi)越大就说明在出现wi这个词的条件下,此内容概率越大,
#那么把所有词的p(content|wi)按照大小降序排列,越靠前的词就越重要,越应该看成是本文的关键词。

from collections import Counter
def keywords(s):
    #抽出s中和与训练的model重叠的词
    s = [w for w in s if w in model]
    ws = {w:sum([predict_proba(u, w) for u in s]) for w in s}
    return Counter(ws).most_common()

import pandas as pd
import jieba
#这里我们随便去弄一篇微博
#之前说过使用word2vec不需要去除停用词

w1 = u'美对华商品将大规模加征关税 我驻美大使:奉陪到底。当地时间22日,美国总统特朗普宣布将对从中国进口的商品大规模征收关税,涉税商品达600亿美元。我驻美大使崔天凯回应:中国从来不想与任何国家进行贸易战,但若其他国家非要对中国施加贸易战,中国一定会予以还击、奉陪到底。'
x = pd.Series(keywords(jieba.cut(w1)))
#输出最重要的前13个词
print (x[0:13])

前13个关键词

3.python中文编码问题

錯誤:AttributeError: 'str' object has no attribute 'decode'
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。
有时python3会报错:AttributeError: 'str' object has no attribute 'decode'
因为python3里str默认为 unicode 了。只能编码 encode 不能解码 decode。

fo = open("nlp.txt", "wb+")
str = '中文'
str = str.encode('utf-8')
fo.write(str)
fo.close()

Python 读写文件 中文乱码
需要使用utf-8來編碼
str = str.encode('utf-8')
錯誤:TypeError: write() argument must be str, not bytes+
打开语句修改为用二进制方式打开

附:
读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式

如:'rb','wb','r+b'等等

读写模式的类型有:

rU 或 Ua 以读方式打开, 同时提供通用换行符支持 (PEP 278)
w 以写方式打开,
a 以追加模式打开 (从 EOF 开始, 必要时创建新文件)
r+ 以读写模式打开
w+ 以读写模式打开 (参见 w )
a+ 以读写模式打开 (参见 a )
rb 以二进制读模式打开
wb 以二进制写模式打开 (参见 w )
ab 以二进制追加模式打开 (参见 a )
rb+ 以二进制读写模式打开 (参见 r+ )
wb+ 以二进制读写模式打开 (参见 w+ )
ab+ 以二进制读写模式打开 (参见 a+ )

錯誤:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 2: invalid continuation byte
出現這種錯誤說明需要漢字解碼方式,汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5,測試了一下Big5也會報類似的錯誤。

#需要把
fo = open("nlp.txt", "wb+")
#改為
fo = open("nlp.txt", "wb+",encoding='GB2312')
#或者
fo = open("nlp.txt", "wb+",encoding='GBK')

錯誤:UnicodeDecodeError: 'gbk' codec can't decode byte 0x91 in position 8: illegal multibyte sequence

解决办法1.

#文本為中文選用第一種方法
fo = open("nlp.txt",'r', encoding='UTF-8')

解决办法2.

fo = open("nlp.txt",'rb')

后来找到了解决中文乱码的通用方法,python2X3X皆可

import codecs
with codecs.open('h.csv', 'rb', 'gb2312') as csvfile:
    for line in csvfile:
        print line

4.人人网关键词提取策略

下面的部分转自:http://ugc.renren.com/2010/02/01/keywords-extraction-overview/

基于词频(TF-IDF)统计的方法

思想:常用TFIDF计算文本特征权重,权重高的为关键词,该方法简单,效果也不错。

在实际操作中常会对文本进行聚类处理,计算文本特征权重后,先对文本向量(在聚类操作中,常用文本的句子做为向量单位)利用余弦定理计算文本相似度或距离,然后通过聚类算法,将相似文本聚类。最后在各文本类中选择关键词,合并得出最终结果。这样先通过文本相似度聚类,提高了关键词准确率。

TFIDF:TF(term frequency)为特征在文本中出现频率,IDF(inverse document frequency)文档中出现该词的频率log(D/Dw),该公式的思想是:特征权重除了和出现频率成正比外,还和文档频率成反比(如果只有文本中包含该特征,则认为该特征更能体现文本的专有特性)。

特征权重=TF*IDF。

特征权重计算方法还有:用于VSM的信息熵算法,基于增益的对TFIDF改进算法算法等。

该方法常结合聚类算法一同使用。

基于词语共现图提取方法

思想:文本中两个特征经常共现在文本的同一段落,则认为两个特征在意义上是相互关联的,共现概率越高,关联越紧密。

由此计算每个特征节点重要性,即与其他特征同现指数连乘,选取最重要的节点作为关键词。

其中最简单的特征同现指数可以用两个特征同现频率表示。

该方法在小规模文本集时并不能很好的反映特征间的关系。

因此文本集的大小会影响算法的稳定性和准确性。

基于词语网络的方法

思想:它是词语共现图的发展,因此与同现图类似,每个特征为网络中的节点,网络的边表示特征间的关系,不同的是该算法引入了图论的模型及算法。

首先要提到最小世界网络(Small-World-Network)这个概念:具有高聚类系数,且平均路径长度短的网络。

其中图的聚类系数为所有节点的(实际边数/最多可能边数)和平均值;
图的平均路径长度即:网络图中,任意两个节点间最短路径边数的平均值。

这种网络和我们以人为节点,人与人之间关系为边,构成的现实世界具有同样的特性:聚类系数高,平均路径短。同理,该模型适用于词语网络。下图为SWN的模型图
在该网络中,特征即为节点,边表示除了前面说的特征同现频率外,还有jaccard系数等计算方法。网络图构建完成后,提取关键词工作即转换为对关键节点的选择。而由于我们认为词语网络是适用于SWN模型的,那关键节点即为影响SWN性质的节点。在现实世界网络中,就相当于去寻找影响社会发展的人,一个公司中的关键人物一样。
通常寻找关键节点的方法有两种,一是直接衡量节点的属性值来判断节点的重要程度,如节点的度(节点到其他节点距离和的倒数)、节点中介性指标(Betweenness Centrality:其他节点间最短路径 经过该节点的概率)等。另一种是通过衡量删除节点后,对SWN性质的破坏程度,即衡量删除节点后聚类系数和平均路径长度的变化,决定该节点的重要度。

References:

[1]http://ugc.renren.com/2010/02/01/keywords-extraction-overview/
[2]https://radimrehurek.com/gensim/models/word2vec.html
[3]https://kexue.fm/archives/4304
[4]https://spaces.ac.cn/archives/4316

推荐阅读更多精彩内容