前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于凝聚度和自由度的非监督词库生成

基于凝聚度和自由度的非监督词库生成

作者头像
张宏伦
发布2018-06-07 14:51:48
1.9K0
发布2018-06-07 14:51:48
举报
文章被收录于专栏:宏伦工作室宏伦工作室

中文分词是中文文本自然语言处理的第一步,然而分词效果的好坏取决于所使用的语料词库和分词模型。主流的分词模型比较固定,而好的语料词库往往很难获得,并且大多需要人工标注。这里介绍一种基于词频、凝聚度和自由度的非监督词库生成方法,什么是非监督呢?输入一大段文本,通过定义好的模型和算法,即可自动生成词库,不需要更多的工作,听起来是不是还不错?

参考文章:互联网时代的社会语言学:基于SNS的文本数据挖掘,点击阅读原文即可查看。访问我的个人网站查看更详细的内容,包括所使用的测试文本和代码。

获取所有的备选词语

假设对于一段很长的文本,例如《西游记》的全文,我的网站上提供了utf-8和gbk两个版本,我在mac上进行处理,因此使用的是utf-8版本,我关注的最大词语长度为5,因此可以使用正则匹配出全部的单个汉字、双汉字、三汉字、四汉字、五汉字,作为可能的备选词语。

由于python中的re模块进行的是非重叠匹配,因此在匹配多汉字词语时返回的数量会有遗漏,以下是python的re模块官方文档中的说明。

# Return all non-overlapping matches of pattern in string, # as a list of strings. The string is scanned left-to-right, # and matches are returned in the order found. # If one or more groups are present in the pattern, # return a list of groups; # this will be a list of tuples if the pattern has more than one group. # Empty matches are included in the result unless they touch the beginning of another match. re.findall(pattern, string, flags=0)

所以我用的是python的regex模块,可以进行多汉字的重叠匹配。

import regex as re # 以下为在utf-8编码中匹配汉字的正则表达式 reg = ur'[\u4e00-\u9fa5]{2}' # 返回的reg为一个list,即为去重后的全部双汉字词语 reg = list(set(re.findall(reg, self.content, overlapped=True)))

因此使用正则表达式,可以很方便地提取出全部可能的备选词语。

词频

一个很直观的认识是,真正的词语应该至少出现一定次数,而那些局部切割出来的碎片出现次数则较少,因此可以统计一下以上全部可能备选词语的词频,作为我们判断是否成词的第一个标准。

对于《西游记》而言,一共出现了4459个汉字,而长度不超过5个汉字的全部可能备选词语共824567个。为了得到这些词语的词频,我写了一个循环,挨个在《西游记》中查找每一个词的词频。但是事实证明这样相当浪费时间,因为这个循环需要进行824567次!所以更好的方法是,同样还是使用regex匹配单汉字、双汉字、三汉字、四汉字和五汉字词语,只不过不进行set、list的去重操作,这样返回的匹配结果中便包含了全部备选词语的词频,而且一共只需执行五次正则匹配,所需时间会少很多。

聚合度

我们已经得到了全部可能备选词语的词频了,但这并不是判断成词的全部标准。自然语言处理中有停用词的概念,也就是那些使用频繁,但是不包含有用信息的词语,如“的”、“了”、“着”等,因此还需要计算更多用于判断是否成词的标准。

聚合度的概念很好理解,例如“齐天”会和“大圣”出现在一起,因为“齐天大圣”这个词的聚合度很高。同样,我们还能想到类似“葡萄”、“蝙蝠”、“师父”这样的词,这些词往往作为一个整体而出现,说明它们确实是有意义的词语。

那么如何计算词语的聚合度呢?假设该词语为S,首先计算该词语出现的概率P(S),然后尝试S的所有可能的二切分,即分为左半部分sl和右半部分sr并计算P(sl)和P(sr),例如双汉字词语存在一种二切分、三汉字词语存在两种二切分。接下来计算所有二切分方案中,P(S)/(P(sl)×P(sr))的最小值,取对数之后即可作为聚合度的衡量。

以双汉字词语为例,可以想象到,如果该词语的聚合度很低,说明其第一个字和第二个字的相关性很弱,甚至是不相关的,那么P(S)和P(sl)×P(sr)将处于同一个数量级。相反,如果该词语的聚合度很高,“齐天”、“大圣”和“齐天大圣”三者的概率都很接近,因此P(S)/(P(sl)×P(sr))将是一个远大于1的数值。

取对数有三个好处:

  • 避免概率过低造成下溢出;
  • 将取值范围映射到更平滑的区间中;
  • 当P(S)和P(sl)×P(sr)处于同一个数量级时,P(S)/(P(sl)×P(sr))接近1,取对数后为0,对应一个很低的聚合度。

通过以上方式,我们可以计算全部可能备选词语的聚合度。有意思的是,《西游记》的824567个备选词中,对应的聚合度范围为-6至20。为什么会出现负数呢?说明P(S)比P(sl)×P(sr)更小,即sl和sr同时出现的可能性更低,因此别提聚合,可能还存在某些排斥。

在具体实现上,由于上一步中已经计算了全部可能备选词语的词频,当然也包括全部的二切分词,因此计算词语的概率以及聚合度都是很方便的。

自由度

有了聚合度的概念,我们可以自动识别出类似“齐天大圣”这样的词语。那么问题来了,“天大圣”是一个有效词语吗?“齐天大”呢?可以推测到,这两个词语的聚合度也很高,但是它们却不应该成为有效的词语。

一个有效的词语,应该能够被灵活地运用到各种语句中,其上下文搭配应当是丰富的,这便是自由度的概念。“天大圣”的左边绝大多数都是“齐”,“齐天大”的右边绝大多数都是“圣”,因此它们的自由度很低。

可以用熵来衡量一个词语的自由度。假设一个词语一共出现了N次,其左边共出现过n个汉字,每个汉字依次出现N1,N2,……,Nn次,则满足N = N1 + N2 + …… + Nn,因此可以计算该词语左边各个汉字出现的概率,并根据熵公式计算左邻熵。熵越小则自由度越低,例如“天大圣”的左邻熵接近于0,因为“齐”字的概率几乎为1;熵越大则自由度越高,表示用词搭配越混乱、越自由、越多样。因为“天大圣”的左邻熵很小,而右邻熵则相对较大,因此我们将一个词语左邻熵和右邻熵中较小者作为最终的自由度。

通过以上方式,我们可以计算出全部可能备选词语的自由度,《西游记》的824567个备选词中,对应的自由度范围为0至8,这和熵的非负性相吻合。

在具体实现中,一开始我也是写了个循环,对《西游记》的824567个词语各写一个正则,匹配出其左右可能搭配的汉字,结果依旧非常耗时。更好更快的解决方案是,依旧使用regex只写五次正则,分别处理单汉字、双汉字、三汉字、四汉字和五汉字,只不过在原来的基础上在两边各加一个字符,然后将全部的匹配结果映射到对应的词语中即可。

综合起来

有了频数、聚合度和自由度,就可以对全部可能的备选词语进行筛选了。例如,对频率、聚合度和自由度分别设置阈值,仅保留三项指标都超过阈值的词语。对于筛选过后的词语,可以考虑使用频率,或者频率、聚合度、自由度三者的乘积,作为最终输出的排序指标。基于以上方法,能够很好地去除停用词,并自动生成有意义和有代表性的词语。

《西游记》输出的词语包括行者、师父、八戒、唐僧、菩萨、大圣、和尚、三藏、妖精、沙僧、老孙等,还是很有代表性的。

实现

我的网站上提供了一个代码corpus.py,里面的CorpusGenerator类构造函数的参数包括待分析的文本content、最大词长maxlen、返回得分靠前的词数量topK、频率阈值tfreq、凝聚度阈值tDOA和自由度阈值tDOF,还提供了以下几个函数:

  • get_characters(),返回一个list,对应全部可能的单字;
  • get_possible_words(),返回一个list,对应长度不超过maxlen的全部可能备选词语;
  • get_frequency(),计算全部可能备选词语的词频,存储在self.result[key]['freq']中;
  • get_doa(),计算全部可能备选词语的凝聚度,存储在self.result[key]['doa']中;
  • get_dof(),计算全部可能备选词语的自由度,存储在self.result[key]['dof']中;
  • get_score(),基于频率、凝聚度、自由度计算全部可能备选词语的得分,存储在self.result[key]['score']中;
  • generate(),依次执行以上四个计算函数,并根据得分和topK返回一个list,每个元素即为一个经过筛选的备选词语;
  • distribution(),在执行generate()之后可调用,根据self.result绘制全部可能备选词语的频率、凝聚度、自由度的散点图矩阵,以便查看各参数分布情况。

进一步的工作

我们建立了一个基于凝聚度和自由度的非监督词库生成模型,输入一大段文本,可以自动输出符合要求的词语。那么除此之外,我们还可以做些什么?

假设我们的输入不是类似《西游记》这样的大段文本,而是具有时间戳的互联网语料,例如每天发布的用户微博和评论等内容。通过对每一天的UGC(User Generated Content,用户产生内容)进行成词,我们可以发现每天的热点词语有哪些。如果使用更短的时间间隔,则可以进一步发现更为实时的热词结果。

通过对子类别分别进行成词,可以做一些群体画像的工作。例如分别对男性和女性的UGC成词,可以发现男女用词的特点和不同;分别对不同城市和地区的UGC成词,可以发现语言用词的地域变化;分别对不同年龄段的UGC成词,可以发现70后、80后、90后和00后们分别在关注什么。如果文本语料有足够的额外信息,能够进一步做的工作是相当丰富的。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 宏伦工作室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取所有的备选词语
  • 词频
  • 聚合度
  • 自由度
  • 综合起来
  • 实现
  • 进一步的工作
相关产品与服务
NLP 服务
NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档