赞
踩
利用 Python,结合 LDA + Word2Vec + Pagerank 实现关键词的挖掘。先用 LDA 方法初步选择出主题及其词分布,接着将每个主题下的词表示为词向量,用相似性表示词与词之间的权重,最后用 TextRank 方法对于主题下的关键词进行二次过滤。
文献:融合主题词嵌入和网络结构分析的主题关键词提取方法
主要方法:词向量(Word2Vec) + 主题模型(LDA) + 关键词网络分析
这篇文献提供了一种 关键词提取 的思路:
首先利用 LDA 对于数据集的主题进行初步提取,生成 主题 - 词 (m×n) 矩阵;
接着,用 Word2Vec 训练数据集,得到词向量模型;
For each t in Topic (m):
For each w in KeyWords (n):
利用生成的词向量模型,用余弦法计算该主题下词与词的相似度,作为两点之间的权重;
设置阈值,过滤掉权重较低的词关系,其余的两两词之间连成一条边;
利用 PageRank 方法进行迭代,最后输出 PR 值最高的 TopN 个词作为该主题下的关键词。
总结:先用 LDA 方法初步选择出主题及其词分布,接着将每个主题下的词表示为词向量,用相似性表示词与词之间的权重,最后用 PageRank 方法对于主题下的关键词进行二次过滤。
在开始关键词提取之前,我希望您已经准备好了以下条件:
pip install numpy
如果有疑问,请参考我之前的文章:【用Word2Vec训练中文词向量】 【用Python实现主题模型LDA】
如果一切准备就绪,那就开始吧!!!
在这一步,主要实现了 参数定义 + 文件读取 + 加载模型 的步骤。
首先是定义函数,主要传入三个参数:
def __init__(self, simvalue, alpha, iter_num):
self.word_list = [] # 记录主题-词模型
self.edge_dict = {} # 记录节点的边连接字典
self.simvalue = simvalue # 满足该最小相似性值,词与词之间可构成边
self.alpha = alpha
self.iter_num = iter_num # 迭代次数
接下来是读取 主题-词 文档,保存在" topicword.txt "。每一行为一个主题,每个主题下有30个词,保存在 word_list 中。我一共分了5个主题。
# 读取文档,返回一个总的主题-词列表
def readFile(self):
with open("topicword.txt", "r", encoding='utf-8') as tw:
for line in tw:
self.word_list.append(line.strip().split(" "))
# print(self.word_list)
return self.word_list
在这一步的最后,是要加载之前训练好的 Word2Vec 模型。
# 加载Word2Vec模型
def loadModel(self):
self.path = "word2vec.model" # Word2Vec模型路径
self.model = word2vec.Word2Vec.load(self.path)
print("模型加载完成")
return self.model
def calTR(self): # 首先根据词语之间相似性,构建每个词的相邻词,过滤掉相似性较小的词,返回边的集合 word_list_len = len(self.word_list) # 主题个数 term_num = 30 # 每个主题下词的个数 names = globals() for list, t in zip(self.word_list, range(word_list_len)): # list表示每一个主题-词,t为主题序数,即第几个主题 names['self.edge_dict_' + str(t)] = {} # 为每一个主题建立一个词典,如第一个主题的词典名称为 self.edge_dict_0 for index, word in enumerate(list): # 枚举可以同时遍历索引和值 if word not in names.get('self.edge_dict_' + str(t)).keys(): # 表明该词还未进行边的连接 tmp_set = set() # set()函数创建一个无序不重复元素集 for i in range(term_num): if i == index: continue # 若为该单词,则跳出本次循环 word0 = list[i] similarity = self.model.wv.similarity(word, word0) # 计算当前词与剩余词语的相似性 if similarity > self.simvalue: tmp_set.add(word0) # 返回一个词的相邻节点 names.get('self.edge_dict_' + str(t))[word] = tmp_set
以第0个主题为例,返回的形式为 self.edge_dict_0 = {'Word0' : { 'Word1, Word 5'}, 'Word1' : {'Word0, Word 2'}......}
# 根据边的相连关系,构建矩阵 # 用0来初始化矩阵 names['self.matrix_' + str(t)] = np.zeros([len(set(list)), len(set(list))]) self.word_index = {} # 记录词的index self.index_dict = {} # 记录节点index对应的词 for i, v in enumerate(set(list)): self.word_index[v] = i # 用词来找到它的索引 self.index_dict[i] = v # 用索引来找到它的词 for key in names.get('self.edge_dict_' + str(t)).keys(): # 对于字典里的每一个节点 for w in names.get('self.edge_dict_' + str(t))[key]: # 对于每一个节点的相邻点 # 相邻节点的边权重变为向量相似度 names.get('self.matrix_' + str(t))[self.word_index[key]][self.word_index[w]] = self.model.wv.similarity(key, w) names.get('self.matrix_' + str(t))[self.word_index[w]][self.word_index[key]] = self.model.wv.similarity(w, key) # print(t) # print(names.get('self.matrix_' + str(t))) # 归一化 for j in range(names.get('self.matrix_' + str(t)).shape[1]): # 对第j列元素 sum = 0 for i in range(names.get('self.matrix_' + str(t)).shape[0]): # 对第i行元素 sum += names.get('self.matrix_' + str(t))[i][j] for i in range(names.get('self.matrix_' + str(t)).shape[0]): names.get('self.matrix_' + str(t))[i][j] /= sum # print(t) # print(names.get('self.matrix_' + str(t)))
# 根据textrank公式计算权重 self.TR = np.ones([len(set(list)), 1]) for i in range(self.iter_num): self.TR = (1 - self.alpha) + self.alpha * np.dot(names.get('self.matrix_' + str(t)), self.TR) print("主题#%d:" % t) #print(self.TR) # 输出词和相应的权重 word_pr = {} for i in range(len(self.TR)): word_pr[self.index_dict[i]] = self.TR[i][0] # sorted() 函数对所有可迭代的对象进行排序操作,返回的是一个新的 list,key指用来进行比较的元素,reverse为排序规则 ,True降序 ,False升序(默认) res = sorted(word_pr.items(), key=lambda x: x[1], reverse=True) # print(res) list = [] for n in range(len(res)): list.append(res[n][0]) print(list)
import gensim.models as word2vec import numpy as np from gensim.models.word2vec import LineSentence class TextRank(object): def __init__(self, simvalue, alpha, iter_num): self.word_list = [] # 记录主题-词模型 self.edge_dict = {} # 记录节点的边连接字典 self.simvalue = simvalue # 满足该最小相似性值,词与词之间可构成边 self.alpha = alpha self.iter_num = iter_num # 迭代次数 # 读取文档,返回一个总的主题-词列表 def readFile(self): with open("topicword.txt", "r", encoding='utf-8') as tw: for line in tw: self.word_list.append(line.strip().split(" ")) # print(self.word_list) return self.word_list # 加载Word2Vec模型 def loadModel(self): self.path = "word2vec_hotel.model" # Word2Vec模型路径 self.model = word2vec.Word2Vec.load(self.path) print("模型加载完成") return self.model # 计算TR值 def calTR(self): # 首先根据词语之间相似性,构建每个词的相邻词,过滤掉相似性较小的词,返回边的集合 word_list_len = len(self.word_list) # 主题个数 term_num = 30 # 每个主题下词的个数 names = globals() for list, t in zip(self.word_list, range(word_list_len)): # list表示每一个主题-词,t为主题序数,即第几个主题 names['self.edge_dict_' + str(t)] = {} # 为每一个主题建立一个词典,如第一个主题的词典名称为 self.edge_dict_0 for index, word in enumerate(list): # 枚举可以同时遍历索引和值 if word not in names.get('self.edge_dict_' + str(t)).keys(): # 表明该词还未进行边的连接 tmp_set = set() # set()函数创建一个无序不重复元素集 for i in range(term_num): if i == index: continue # 若为该单词,则跳出本次循环 word0 = list[i] similarity = self.model.wv.similarity(word, word0) # 计算当前词与剩余词语的相似性 if similarity > self.simvalue: tmp_set.add(word0) # 返回一个词的相邻节点 names.get('self.edge_dict_' + str(t))[word] = tmp_set # print(names.get('self.edge_dict_' + str(t))) # 根据边的相连关系,构建矩阵 # for list, t in zip(self.word_list, range(word_list_len)): # 用0来初始化矩阵 names['self.matrix_' + str(t)] = np.zeros([len(set(list)), len(set(list))]) self.word_index = {} # 记录词的index self.index_dict = {} # 记录节点index对应的词 for i, v in enumerate(set(list)): self.word_index[v] = i # 用词来找到它的索引 self.index_dict[i] = v # 用索引来找到它的词 for key in names.get('self.edge_dict_' + str(t)).keys(): # 对于字典里的每一个节点 for w in names.get('self.edge_dict_' + str(t))[key]: # 对于每一个节点的相邻点 # 相邻节点的边权重变为向量相似度 names.get('self.matrix_' + str(t))[self.word_index[key]][self.word_index[w]] = self.model.wv.similarity(key, w) names.get('self.matrix_' + str(t))[self.word_index[w]][self.word_index[key]] = self.model.wv.similarity(w, key) # print(names.get('self.matrix_' + str(t))) # 归一化 for j in range(names.get('self.matrix_' + str(t)).shape[1]): # 对第j列元素 sum = 0 for i in range(names.get('self.matrix_' + str(t)).shape[0]): # 对第i行元素 sum += names.get('self.matrix_' + str(t))[i][j] for i in range(names.get('self.matrix_' + str(t)).shape[0]): names.get('self.matrix_' + str(t))[i][j] /= sum # 根据textrank公式计算权重 # for list, t in zip(self.word_list, range(word_list_len)): self.TR = np.ones([len(set(list)), 1]) for i in range(self.iter_num): self.TR = (1 - self.alpha) + self.alpha * np.dot(names.get('self.matrix_' + str(t)), self.TR) print("主题#%d:" % t) #print(self.TR) # 输出词和相应的权重 word_pr = {} for i in range(len(self.TR)): word_pr[self.index_dict[i]] = self.TR[i][0] # sorted() 函数对所有可迭代的对象进行排序操作,返回的是一个新的 list,key指用来进行比较的元素,reverse为排序规则 ,True降序 ,False升序(默认) res = sorted(word_pr.items(), key=lambda x: x[1], reverse=True) # print(res) list = [] for n in range(len(res)): list.append(res[n][0]) print(list) if __name__ == '__main__': tr = TextRank(0.45, 0.85, 800) tr.readFile() tr.loadModel() tr.calTR()
LDA获取的 主题-词 文档
经过TextRank计算的 主题-词
就此完结 @^_^@
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。