无监督关键短语的生成问题博客13--Segmentation.py的分析
2021SC@SDUSC
在上一篇博客中,我们分析了TextRank4Keyword类中的函数,但实际上TextRank中词图的构建和文本预处理是由Segmentation.py和utils.py实现的,本篇博客中,我们将分析Segmentation.py和util.py两个文件,并对此次的课题进行总结。
一、util.py的分析
util.py的主要函数如下:
图1: util.py的主要函数
- combine:构造在window下的单词组合,用来构造单词之间的边
- get_similarity:默认的用于计算两个句子相似度的函数
- sort_words:将单词按关键程度从大到小排序
- sort_sentences:将句子按照关键程度从大到小排序
下面我们来一一分析这些函数,首先是combine。
1.combine函数的分析
def combine(word_list, window = 2):if window < 2: window = 2 # window过小时,初始化窗口为2for x in xrange(1, window): # 外层循环为窗口if x >= len(word_list): # 遍历完word_list,breakbreakword_list2 = word_list[x:] # 从x开始取word_listres = zip(word_list, word_list2) #利用zip打包word_list,word_list2对应位置元素for r in res:yield r
首先是参数:
- word_list:list或str, 由单词组成的列表
- windows:int, 窗口大小
首先遍历窗口,当遍历完word_list之后break循环,zip返回列表元素打包后的元组的列表,这里的实现逻辑非常巧妙!例如我们的window=3,也就是对于第四个词,它和它的前三个词,后三个词都有边相连。我们假定一个词列表为[]那么对于而言,[]和[]都应该被一起考虑,也就是对于,这个节点应该和这些节点有边相邻,这里我们依据图论中的定义,依旧将图的边理解成顶点,这里也就是有顶点对.理解了这些之后,我们来看这个函数的逻辑。
首先x==1,从word_list下标为1的地方开始取出子list赋给word_list2,然后用zip函数打包word_list2和word_list,也就是对应位置的元素配对成元组,之后形成列表,得到的结果非常amazing啊!就是我们需要的顶点对!这里word_list2=[],word_list=[]就是配对出了,指定x==1,就是相邻单词之间应该有边相连。x==2时,word_list2=[],word_list=[],配对除出了,也就是相隔一个单词的两个单词配对,x==3时,配对出,对于第一个点而言,配对出了,与window=3一致!
yield的作用类似于return,但可以认为带yield的函数是一个生成器,函数不是立即返回,而是依赖于之后调用next(),下一步的next开始的地方是接着上一次的next停止的地方执行的,而不是重新执行。
2.get_similarity的分析
def get_similarity(word_list1, word_list2):words = list(set(word_list1 + word_list2)) # 列表word_list1和word_list2拼接后转为set去重 vector1 = [float(word_list1.count(word)) for word in words]# 遍历集合words中的word,对出现在list1中的计数,得到向量,出现的位置记1vector2 = [float(word_list2.count(word)) for word in words]# 遍历集合words中的word,对出现在list2中的计数,得到向量,出现的位置记1vector3 = [vector1[x]*vector2[x] for x in xrange(len(vector1))] # 得到向量分量相乘的结果vector4 = [1 for num in vector3 if num > 0.]# 记录大于1的结果,就是共同出现的词co_occur_num = sum(vector4)# 没有共同出现的词,相似性为0if abs(co_occur_num) <= 1e-12:return 0.denominator = math.log(float(len(word_list1))) + math.log(float(len(word_list2))) # 分母经过log处理if abs(denominator) < 1e-12:return 0.return co_occur_num / denominator
参数word_list1, word_list2 :分别代表两个句子,都是由单词组成的列表。
对于两个句子组成的list,首先合并去除共同的单词,得到合并后的集合words,然后遍历words中的word,产生两个向量,分别记录在list1和list2出现的单词,words中的word在list出现了则对应位置计作1,之后作向量对应分量的乘法,然后sum得到1的个数,其实也就是vector1和vector2共同地方出现1的次数,也就是两个list共同出现词的次数。之后处理分母,分母用了len(list)后用log处理然后对数相加后,最后返回相似性结果。
3.sort_words函数的分析
def sort_words(vertex_source, edge_source, window = 2, pagerank_config = {'alpha': 0.85,}):sorted_words = []word_index = {}index_word = {}_vertex_source = vertex_source_edge_source = edge_source#初始化word_number为0,是对应vocabulary的词的索引words_number = 0
sort_words函数实现了将单词按重要性程度从大到小排序,首先分析函数的参数:
- vertex_source:二维列表,子列表代表句子,子列表的元素是单词,这些单词用来构造pagerank中的节点
- edge_source:二维列表,子列表代表句子,子列表的元素是单词,根据单词位置关系构造pagerank中的边
- window:一个句子中相邻的window个单词,两两之间认为有边
- pagerank_config:pagerank的设置
# 遍历每一个sentence
for word_list in _vertex_source:# 遍历sentence中的wordfor word in word_list:# word没有出现在word_index中if not word in word_index:word_index[word] = words_number # 记录word2idxindex_word[words_number] = word # 记录idx2wordwords_number += 1
若list中句子的word没有出现在word_index中,则令word_index字典的word索引的value为words_number,同时初始化index_word的key为words_number的value为word,之后words_number自增。这里的处理和我们之前分析的vocabulary类非常相似。
graph = np.zeros((words_number, words_number))
# 初始化图的邻接矩阵for word_list in _edge_source:for w1, w2 in combine(word_list, window):# 取出combine的w1和w2if w1 in word_index and w2 in word_index:index1 = word_index[w1] # 获得配对的单词的索引index2 = word_index[w2]graph[index1][index2] = 1.0 # 无向图边赋值,对称矩阵graph[index2][index1] = 1.0debug('graph:\n', graph)
通过刚才的初始化 ,我们已经构建好了词和索引的对应字典,记录下了语料库中所有单词的总数,为words_number,初始化图为words_number*words_number大小的邻接矩阵,对于指定格式的_edge_source,通过conbine函数,得到了途中的顶点对,这里用表示,然后取出和,用word2idx获得两个点的索引,(注意这里的仍然还是单词word的形式)然后在对应索引处的邻接矩阵位置赋值,最后完成了图的初始化。
nx_graph = nx.from_numpy_matrix(graph)
scores = nx.pagerank(nx_graph, **pagerank_config)
sorted_scores = sorted(scores.items(), key = lambda item: item[1], reverse=True)
# 按序排列分数
for index, score in sorted_scores:
# 遍历sorted_scoresitem = AttrDict(word=index_word[index], weight=score)# 通过idx2word找到单词sorted_words.append(item)# 返回排序好的单词
return sorted_words
得到graph后,经过pagerank计算可以得到scores,我们得到的是词典的形式,然后遍历sorted_scores,通过idx2word找到word(因为图的构建经过了一遍word2idx换成了索引形式),同时加入score,遍历完之后就能得到排序好的单词。
二、Segmentation.py的分析
Segmentation.py的主要函数如下:
图2:Segmentation.py的类与函数
- WordSegmentation:该类主要用来分词,有init函数、segment函数和segment_sentence函数
- SentenceSegmentation:该类主要用来分句,有init函数,segment函数
- Segmentation:基于WordSegmentation类和SentenceSegmentation类实现,有init函数和segment函数
这里我们将简单分析WordSegmentation类及其函数。
1.init函数
def __init__(self, stop_words_file = None, allow_speech_tags = util.allow_speech_tags): allow_speech_tags = [util.as_text(item) for item in allow_speech_tags]# 默认的speech_tag_filter为allow_speech_tagsself.default_speech_tag_filter = allow_speech_tags# 初始化stop_words为空集合self.stop_words = set()self.stop_words_file = get_default_stop_words_file()if type(stop_words_file) is str:# 指定stop_words_file路径self.stop_words_file = stop_words_filefor word in codecs.open(self.stop_words_file, 'r', 'utf-8', 'ignore'):# 加入stop_words_file中的stop_words(删除空格)self.stop_words.add(word.strip())
- stop_words_file:保存停止词的文件路径,utf8编码,每行一个停止词。若不是str类型,则使用默认的停止词
- allow_speech_tags:词性列表,用于过滤
首先是初始化stop_words和stop_words_file,读stop_words_file后取出每一个单词,加入stop_words集合中,这个函数主要说明了stopwords。
2.segment函数
def segment(self, text, lower = True, use_stop_words = True, use_speech_tags_filter = False):text = util.as_text(text)jieba_result = pseg.cut(text) # 对文本进行分词# 是否采用词性过滤if use_speech_tags_filter == True:jieba_result = [w for w in jieba_result if w.flag in self.default_speech_tag_filter]else:jieba_result = [w for w in jieba_result]# 去除特殊符号word_list = [w.word.strip() for w in jieba_result if w.flag!='x']word_list = [word for word in word_list if len(word)>0]# 对于word_list每个单词取小写if lower:word_list = [word.lower() for word in word_list]# 去除停词if use_stop_words:word_list = [word.strip() for word in word_list if word.strip() not in self.stop_words]return word_list
segment函数对一段文本进行分词,并返回list类型的分词结果 。其参数如下:
- lower:是否将单词小写(英文)
- use_stop_words:若为True,则利用停止词集合来过滤(去掉停止词)
- use_speech_tags_filter:是否基于词性进行过滤。若为True,则使用self.default_speech_tag_filter过滤。否则不过滤
首先是用jieba对文本初步分词,然后用单词的flag进行词性过滤,接着判断是否去除特殊符号和是否小写,是否去除停词,注意word.strip()的调用。
3.segment_sentence函数
def segment_sentences(self, sentences, lower=True, use_stop_words=True, use_speech_tags_filter=False):res = []# 遍历每一个句子for sentence in sentences:# 调用segment函数res.append(self.segment(text=sentence, lower=lower, use_stop_words=use_stop_words, use_speech_tags_filter=use_speech_tags_filter))return res
该函数将列表sequences中的每个元素/句子转换为由单词构成的列表,输入参数sequences为列表,每个元素是一个句子(字符串类型)
对于每一个句子,调用segment函数,采用小写,使用停词,过滤符号列表的形式。也就是segment函数实现了对一句话的分词,segment_sentence函数通过调用segment函数对很多句话分词。
至此,我们已经完成了对TextRank4ZH的大致分析,也完成了此次项目源码的分析,通过这门课程,我还是收获很多的。
无监督关键短语的生成问题博客13--Segmentation.py的分析相关推荐
- 无监督关键短语的生成问题博客02--extract.py的分析
2021SC@SDUSC 在上一篇博客中,我们小组各位成员阅读了<Unsupervised Deep Keyphrase Generation>这篇论文,了解了这一关键词抽取模型的任务与主 ...
- 无监督关键短语的生成问题博客07--create_vocabulary.py的分析
2021SC@SDUSC 本文我们将分析create_vocabulary.py文件,该文件主要的功能是创立了一个词典,统计了文本的所有词和词对应的索引,以便后续的指标的计算和处理,将得到的结果保存到 ...
- 无监督关键短语的生成问题01--综述
2021SC@SDUSC 一.问题背景 关键短语提取(Keyphrase generation)可以得到一个能够总结输入的长文档的短语列表,被广泛应用于信息检索.文本总结.文本分类等领域.研究表明,对 ...
- 使用hugo生成静态博客并部署在GitHub上
使用hugo生成静态博客并部署在GitHub上 hugo是一个用Go语言编写的静态网页生成器,只需要一个命令 hugo 就可以在几秒钟内生成一个静态的博客页面,被称为世界上最快的网站构建框架,使hug ...
- 博客搜索引擎索引博文数量分析与评估
/*版权声明:可以任意转载,转载时请务必标明文章原始出处和作者信息 .*/ 博客搜索引擎索引博文数量分析与评估 ...
- 无需成对示例、无监督训练,CycleGAN生成图像简直不要太简单
作者 | Jason Brownlee 译者 | Freesia,Rachel 编辑 | 夕颜 出品 | AI科技大本营(ID: rgznai100) [导读]图像到图像的转换技术一般需要大量的 ...
- 无服务器+域名也能搭建个人博客?真的,而且很快
基于Gitee快速搭建个人博客 一. 背景 个人搭建博客也是有成本的 关于 jekyll 二. 部署 拉取代码 修改和上传配置 _config.yml locale.yml 构建和访问(gitee部署 ...
- ChatGPT写作:快速生成优质博客文章的神器
今天我们将聊聊如何使用ChatGPT快速生成优质的博客文章,并且在短时间内提高写作效率. 首先,让我们简单介绍一下ChatGPT.它是一种基于深度学习的自然语言处理模型,能够自动地生成人类般的文本.通 ...
- 基于selenium生成Csdn 博客文章简索的excel文件
Csdn 上各大博主的博客文章很有参考价值和独特见解,查看起来总觉得不是特别的方便.于是抽空用selenium 做了个简索生成工具.生成的是excel 2007的文章格式. 截图一 截图二 截图三 截 ...
最新文章
- 真正的全栈工程师!B站硬核UP主自己造了一个激光雷达
- 观察者模式及Java实现例子
- 特征选择---文本分类:叉方统计量
- python numpy库安装 mac_教程|如何在mac上为Python安装XGBoost!
- 如何优雅的激怒C/C++程序员
- matlab如何将相近的数据,matlab新手,求帮助!主要是如何将数据和公式导入
- [vue] 你知道nextTick的原理吗?
- SUN服务器清除所有报错信息,SUN服务器可能遇到的问题总结.doc
- 华为c语言编程规范_C语言编程规范
- cocos2d-x和objective-c中的retain()和release()
- 关于max(X,Y),min(X,Y)
- django 之模板层
- AOP如何实现及实现原理
- (转)Hinton、LeCun和Bengio——深度学习综述
- Python列表(list)练习题
- 三星 android 调试模式设置,三星 W2016 开启USB调试模式
- scanf可以输入负数吗_在excel表格中输入负数应该怎样输
- jstat命令查看jvm的GC情况
- vrchat模型房_VRChat之blender教程
- iOS:简易的音视屏播放框架XYQPlayer