利用word2vec提取关键词:
说到提取关键词,一般会想到TF-IDF和TextRank,大家是否想过,Word2Vec还可以用来提取关键词?而且,用Word2Vec提取关键词,已经初步含有了语义上的理解,而不仅仅是简单的统计了,而且还是无监督的!
很显然,我们希望通过提取的关键词能够尽可能快地获取文章的大意。也就是说,我们可以由关键词来猜到文本的大意,用数学来表示,那就是条件概率$$p(s|w_i)$$
这里的$s$代表着一段文本,$w_i$是文本中的某个词,如果$w_i$是文本的关键词,那么应该使得上述概率最大。也就是说,我们只需要对句子中所有的词,算一遍上述概率,然后降序排列,就可以提取关键词了。说白了,关键词就是最能让我们猜到原文的词语。那怎么估算这个概率?
利用Word2vec可以。为了估算$p(w_k|w_i)$,需要有大量的文本进行统计,好在这个过程是无监督的,统计是件很简单的事情。然而,我们有更好的工具,什么工具最擅长于对$p(w_k|w_i)$的建模呢?读者可能就已经猜到了,显然就是Word2Vec呀!Word2Vec的Skip-Gram模型,就是用来对这个概率进行建模的。
训练词向量的时候必须使用Skip-Gram + Huffman Softmax这个组合,也就是训练参数设置为sg=1,hs=1,才能在提取出关键词。
否则将训练的模型将少一个文件word2vec_cpws.model.trainables.syn1.npy。
具体实践代码如下:
import numpy as np
import gensim
from collections import Counter
import pandas as pd #引入它主要是为了更好的显示效果
import jieba
import re
#加载模型
model = gensim.models.word2vec.Word2Vec.load('model1/word2vec_cpws.model')
def predict_proba(oword, iword):
iword_vec = model[iword]
oword = model.wv.vocab[oword]
oword_l = model.syn1[oword.point].T
dot = np.dot(iword_vec, oword_l)
lprob = -sum(np.logaddexp(0, -dot) + oword.code*dot)
return lprob
def keywords(s):
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()
#
# jieba.load_userdict("jiebauserdict.txt")
stopword = [line.rstrip() for line in open("data/stop_words.txt", 'r', encoding='utf-8')]
def clean_text(text):
newtext = []
# text = re.sub(r'\d+', ' ', text) #去除数字
text = jieba.cut(text) # 分词
for word in text:
if word not in stopword: # 去停用词 + 词性筛选
newtext.append(word)
lineswords=' '.join(newtext)
return lineswords
reviews = pd.read_excel("data/cpws.xlsx")
f=open("write2.txt", "w", encoding='utf-8')
#选取有用的列
# reviews['comment'] = reviews['Summary'].astype(str) + reviews['Text'].astype(str)
reviews['comment'] = reviews['jslcm'].astype(str)
# print(reviews['comment'])
# reviews = reviews.drop(['Id'], 1)
# reviews = reviews.reset_index(drop=True)
for i in range(len(reviews)):
print("keyword #", i + 1)
content = reviews.jslcm[i]
# print(reviews.jslcm[i])
result = pd.Series(keywords(jieba.cut(content)))
# result = pd.Series(keywords(clean_text(content)))
results = result[:10]
# print(results)
for word in results:
f.write(word[0] + ' ')
f.write('\n')
f.flush()
f.close()
提取的结果不是很好,数据没有经过预处理。当然单靠这种方法提取关键词是不可能有较好的结果的,需要将多种关键词提取算法进行结合,取各之所长。