美文网首页数据挖掘机器学习与数据挖掘python
jiaba关键词提取提速策略&基于word2vec的关键

jiaba关键词提取提速策略&基于word2vec的关键

作者: wong小尧 | 来源:发表于2018-03-23 11:05 被阅读514次

    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

    相关文章

      网友评论

      • 流川枫AI:你好,请教个问题:
        Mac系统运行的时候,这句:
        oword_l = model.trainables.syn1[oword.point].T
        报错:
        oword_l = model.trainables.syn1[oword.point].T
        AttributeError: 'Word2VecTrainables' object has no attribute 'syn1'
        你知道是什么原因么?难道API更新了?
        kaixinpi:@流川枫AI 'Word2Vec' object has no attribute 'trainables' 我的好像跟你的还不一样,这个有遇到吗?
        流川枫AI:是因为训练参数的问题,hs,还有一个
        kaixinpi:我也是这个问题,请问解决了吗?是什么原因
      • 4c029998bec7:您好,为什么我下载的模型不能用啊
        wong小尧:@思想_a664 在文件夹里找到那个文件的路径 要改路径的
        4c029998bec7:@wong小尧 就是说word2vec_wx文件不存在,我已经下载了您发的那个链接了
        wong小尧:@思想_a664 什么叫不能用 又报错了?

      本文标题:jiaba关键词提取提速策略&基于word2vec的关键

      本文链接:https://www.haomeiwen.com/subject/skwtcftx.html