概述

对机器学习感兴趣的小伙伴,可以借助python,实现一个N-gram分词中的Unigram和Bigram分词器,来进行入门, github地址

此项目并将前向最大切词FMM和后向最大切词的结果作为Baseline,对比分析N-gram分词器在词语切分正确率、词义消歧和新词识别等方面的优势。

数据说明

本实验使用的语料是人民日报1998年中文标注的语料库,19484条。在处理过程中,按照训练集 : 测试集 = 9 : 1的比例进行随机划分。 数据预处理包括:去词性、去文本行标识(19980101-01-001-001)、词典统计、标点统计等。

主要流程

  1. 文本预处理,分为:语料随机切分、去词性、统计词典等
  2. 使用前向FMM和后向BMM最大切分,对测试语料进行切分,统计准确率、召回率和F1值
  3. 统计训练语料词典概率,用Unigram模型对待切分文本采用递归的思想,进行最大概率切分,统计准确率、召回率和F1值
  4. 统计Bigram词典概率,用Bigram模型对文本进行切分方案概率计算,选取概率最大切分,统计准确率、召回率和F1值
  5. 对比分析不同切词方案对文本歧义和未登录词的处理效果。

算法描述

文本预处理

首先进行语料的随机切分,默认按照9 : 1的比例切分训练集合测试集。

"""语料的随机切分,默认按照9 : 1的比例切分训练集合测试集"""
def splitCorpus(train=0.9, fileName='199801.txt'):
train_file = open('train.txt', 'wb')
test_file = open('test.txt', 'wb')
with open(fileName, 'rb') as f:
for line in f:
if random() <= train:
train_file.write(line)
else:
test_file.write(line)
train_file.close()
test_file.close()
print('successfully to split corpus by train = %f test = %f' %
(train, 1 - train)) """统计语料词典"""
def toWordSet(file_name='train.txt', is_save=False, save_file='wordSet.pkl'):
# 获取词典
word_dict = defaultdict(float)
with open(file_name, 'rb') as f:
for line in f:
content = line.decode('gbk').strip().split()
# 去掉第一个词“19980101-01-001-001/m”
for word in content[1:]:
word_dict[word.split(u'/')[0]] += 1
if is_save:
# 保存wordSet以复用
joblib.dump(word_dict, save_file)
print("successfully get word dictionary!")
print("the total number of words is:{0}".format(len(word_dict.keys())))
return word_dict

FMM和BMM

前向最大切词,是以可变滑动窗口对文本进行顺序取词,若改词在词典中存在,则进行一次切分;否则,缩小窗口大小,继续取词与词典库进行搜索,知道窗口词长为1。后向切词原理相似,只不过是从后面开始进行窗口滑动。

def forwardMaxCut(ustring, word_set, word_max_len=5):
"""
前向最大切词
:param ustring: 待切词文本
:param word_set: 词典
:param word_max_len: 最大词长
:return: 词列表
"""
wordList = []
if not ustring:
return wordList
while ustring:
sentence_len = len(ustring)
if sentence_len < word_max_len:
word_max_len = sentence_len
for i in range(word_max_len, 0, -1):
if ustring[:i] in word_set or i == 1:
wordList.append(ustring[:i])
ustring = ustring[i:]
break
else:
i -= 1
return wordList

运行结果:

前向分词结果:
successfully to split corpus by train = 0.900000 test = 0.100000
the total number of punction is:47
the total number of words is:53198
召回率为:0.9466013860392212
准确率为:0.9154134377927275
F值为:0.9307462195496794 后向分词结果:
successfully to split corpus by train = 0.900000 test = 0.100000
the total number of punction is:47
the total number of words is:53767
召回率为:0.950686195146746
准确率为:0.92130516483316
F值为:0.9357651113664159

由于每次运行,都会对语料进行随机切分,因此运行结果中的词典大小有出入。

Unigram分词

Unigram切词的计算公式如下:

  • 基本思路: 首先统计出训练集词典中各个词的频率,用来表示公式中的wi;然后,对待切分文本的进行某种策略的切分,递归选择切分概率最大的子切分序列,最后回溯得到最大概率切分。
  • 举个栗子:
例句S:我是北京大学的一名研究生
# S的切分可以拆成两步
P(S) = P(我)*P(是北京大学的一名研究生)
#同时后面的子句,继续可以拆成:
P(S) = P(我)*P(是北京大学的一名研究生) = P(我)*P(是)*p(北京大学的一名研究生)
#这里有个问题,我们是如何知道应该拆成“我”和“是”两个词,而不是“我是”一个词呢
#上面计算最大概率,是递归调用的,假设我们开始有两种切分
[我,是北京大学的一名研究生]
[我是,北京大学的一名研究生]
#计算组合概率
P1 = P(我)*P(是北京大学的一名研究生)
P2 = P(我是)*P(北京大学的一名研究生)
#我们会发现
P1 > P2
#对于后面的任何子句,我们都采用无脑切分,即设置最大词长,这里假设为3,可得到以下切分:
[我,是北京大学的一名研究生]
[我是,北京大学的一名研究生]
[我是北,京大学的一名研究生]
#然后分别递归计算
#为了满足性能的要求,避免重复计算,我们采用将间接计算的子序列的组合概率,都存储起来
#每次计算新的子序列时,先查看子序列的切分组合中,是否包含已经计算过的子子序列,包含,则直接复用
  • 平滑,对于词典中搜索不到的词,需要做一定的平滑处理,常用的平滑方法原理见这里,本课程实验支持加1平滑、WItten-Bell平滑方法,默认采用的是Wittten-Bell平滑方法。以下为计算最大切分概率程序:
def maxP(self, sentence):
'''
计算最大切分方案
:param sentence: 待切分句子
:return:
'''
# 遍历所有切分组合中,找出最大概率切分
if len(sentence) <= 1:
return self.DICT.getPValue(self, sentence)
# 判断切词方向:backward 或 forward
sentence_split_words = [self.backwardSplitSentence(
sentence), self.forwardSplitSentence(sentence)][self.split_way != 'back']
# 记录最大概率值
max_p_value = 0
# 储存最大概率下的切分组合
word_pairs = []
# 组合概率值
word_p = 0
for pair in sentence_split_words:
p1, p2 = 0, 0
if pair[0] in self.value_dict:
p1 = self.value_dict[pair[0]]
else:
p1 = self.maxP(pair[0])
if pair[1] in self.value_dict:
p2 = self.value_dict[pair[1]]
else:
p2 = self.maxP(pair[1])
word_p = p1 * p2
if max_p_value < word_p:
max_p_value = word_p
word_pairs = pair
# 在词典中查询当前句对应的频率,不存在时,返回 1/N
sentence_p_value = self.DICT.getPValue(self, sentence)
# 不切分概率最大时,更新各值
if sentence_p_value > max_p_value and self.DICT.inDict(self, sentence):
self.value_dict[sentence] = sentence_p_value
self.seg_dict[sentence] = sentence
return sentence_p_value
# 某种切分组合概率最大时,更新sentence对应概率,避免后续切分重复计算
else:
self.value_dict[sentence] = max_p_value
self.seg_dict[sentence] = word_pairs
return max_p_value

运行结果:

successfully to split corpus by train = 0.900000 test = 0.100000
the total number of words is:53705
the total number of punction is:47
召回率为:0.9614382160763091
准确率为:0.9319770859102912
F值为:0.9464784466054017

Bigram分词

  • Bigram切词的计算公式如下:
  • 基本思路: 首先统计出训练集词典中各个Bigram的频率,如[我|是]、[我|来自],用来表示公式中的[wi|wi-1];然后,对待切分文本给出所有的切分方案,计算切分概率最大的切分序列。
  • 举个栗子:
例句S: 这几块地面积还真不小。
#对S进行切分,获得所有切分方案
S1 = ['这', '几', '块', '地', '面', '积', '还', '真', '不', '小']
S2 = ['这', '几', '块', '地', '面', '积', '还', '真', '不小']
S3 = ['这', '几', '块', '地', '面积', '还', '真', '不', '小']
S4 = ['这', '几', '块', '地', '面积', '还', '真', '不小']
S5 = ['这', '几', '块', '地面', '积', '还', '真', '不小']
#利用Bigram公式,计算所有的方案的切分概率,为了避免出现float下溢出,采用log求和
P(S1) = -64.745
P(S2) = -63.894
P(S3) = -55.041
P(S4) = -54.190
P(S5) = -58.190
P(S4) > P(S3)>P(S5)>P(S2)>P(S1)
#不难发现,上述例句对于机器是一个歧义句,S4和S5两种切分都可以
#但是根据语境,S4是正确的
  • 运行结果:
successfully to split corpus by train = 0.900000 test = 0.100000
the total number of words is:53260
The total number of bigram is : 403121.
successfully witten-Bell smoothing! smooth_value:1.3372788850370981e-05
the total number of punction is:47
召回率为:0.962036929819092
准确率为:0.9401303935308096
F值为:0.950957517059212

结果分析

  • 对比指标
指标 FMM BMM Unigram Bigram
准确率 91.54% 92.13% 93.20% 94.01%
召回率 94.66% 95.07% 96.14% 96.20%
F1值 93.07% 93.58% 94.64% 95.10%

根据上表可知:分词效果最好的是Bigram,最差的是FMM。 因为FMM只考虑了前向顺序词是否在字典中出现,而Bigram除了考虑词典中是否包含此词,同时也考虑了邻接词对分词的选择的影响。 在处理歧义上,Bigram具有较好的效果,能基本实现消除歧义,但是消除歧义的效果受文本训练大小的影响。 在处理未登录词上,这里仅仅是对未登录词切分为单个字,因此在未登录词的处理上还要进一步的研究讨论。

机器学习新手项目之N-gram分词的更多相关文章

  1. 2016年GitHub排名前20的Python机器学习开源项目(转)

    当今时代,开源是创新和技术快速发展的核心.本文来自 KDnuggets 的年度盘点,介绍了 2016 年排名前 20 的 Python 机器学习开源项目,在介绍的同时也会做一些有趣的分析以及谈一谈它们 ...

  2. Python & 机器学习之项目实践

    机器学习是一项经验技能,经验越多越好.在项目建立的过程中,实践是掌握机器学习的最佳手段.在实践过程中,通过实际操作加深对分类和回归问题的每一个步骤的理解,达到学习机器学习的目的. 预测模型项目模板不能 ...

  3. 机器学习开源项目精选TOP30

    本文共图文结合,建议阅读5分钟. 本文为大家带来了30个广受好评的机器学习开源项目. 640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1 最近,Mybridge发布了 ...

  4. 百度DMLC分布式深度机器学习开源项目(简称“深盟”)上线了如xgboost(速度快效果好的Boosting模型)、CXXNET(极致的C++深度学习库)、Minerva(高效灵活的并行深度学习引擎)以及Parameter Server(一小时训练600T数据)等产品,在语音识别、OCR识别、人脸识别以及计算效率提升上发布了多个成熟产品。

    百度为何开源深度机器学习平台?   有一系列领先优势的百度却选择开源其深度机器学习平台,为何交底自己的核心技术?深思之下,却是在面对业界无奈时的远见之举.   5月20日,百度在github上开源了其 ...

  5. 深入浅出Hadoop Mahout数据挖掘实战(算法分析、项目实战、中文分词技术)

    Mahout简介 Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目, 提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建 ...

  6. 自然语言处理高手_相关资源_开源项目(比如:分词,word2vec等)

    (1) 中科院自动化所的博士,用神经网络做自然语言处理:http://licstar.net (2) 分词项目:https://github.com/fxsjy/jieba(3) 清华大学搞的中文分词 ...

  7. 机器学习:项目流程及方法(以 kaggle 实例解释)

    一.项目目录 (一)数据加载 基础统计 特征分类 基本分布(scatter) (二)数据分析 正态性检验 偏离度分析 (hist | scatter) 峰度分析 (hist | scatter) 分散 ...

  8. 盘点当下大热的7大Github机器学习创新项目

    哪个平台有最新的机器学习发展现状和最先进的代码?没错——Github!本文将会分享近期发布的七大GitHub机器学习项目.这些项目广泛覆盖了机器学习的各个领域,包括自然语言处理(NLP).计算机视觉. ...

  9. GitHub排名TOP30的机器学习开源项目/贪心学院

    对于机器学习者来说,阅读开源代码并基于代码构建自己的项目,是一个非常有效的学习方法.看看以下这些Github上平均star为3558的开源项目,你错了哪些? 1. FastText:快速文本表示和文本 ...

随机推荐

  1. 使用PostgreSQL注意事项

    一.大小写特别敏感 大写字段需要用“”引号(pg字段名使用“”,MySQL字段名使用``) ******表名以及字段名如果是小写但是为关键字,比如name,则也需使用"": 二.分 ...

  2. 【原创】Linux select/poll机制原理分析

    前言 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 1. 概述 Linux系统 ...

  3. Android | 教你如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓拍神器

    Android | 只要三十分钟就可以在手机上开发一个微笑抓拍神器!!! 前言 前段时间Richard Yu在发布会上给大家介绍了华为HMS Core4.0,回顾发布会信息请戳: 华为面向全球发布HM ...

  4. adb的多种连接方式(二)

    一,设备连接 1,USB数据线连接 win10下USB连接Android 1.手机端的设置,以红米4为例: a.打开开发者模式,小米手机打开开发者模式方法为,连续点击MIUI版本,就可以进入开发者模式 ...

  5. 高并发解决方案限流技术-----使用RateLimiter实现令牌桶限流

    1,RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率.通常可应用于抢购限流防止冲垮系统:限制某接口.服务单位 ...

  6. Activiti任务分配

    分配任务负责人 一.固定分配 在进行业务流程建模时指定固定的任务负责人 在properties 视图中,填写Assignee 项为任务负责人. 注意: 由于固定分配方式,任务只管一步一步执行任务,执行 ...

  7. Oracle如何查询不等于某数值

    前言 今天在使用Oracle查询“不等于”的时候,发现得到的数据与期望中的不一样,进一步查找资料才有发现. 1.Oracle的不等于 在Oracle中,"<>".&qu ...

  8. vue实现选项卡切换--不用ui库

    vue的ui库中基本都有选项卡切换的组件,但是在项目开发过程中却不一定能很好的为我们所用,因为里面的样式和 一些状态并不能很好的根据我们的项目需求进行定制.最近项目中使用的是vant-ui中的标签页, ...

  9. 如何做监控?Google SRE 解密

    监控值班室: @隔壁老王头 SQL执行耗时时间过长,达到了报警阈值[5000ms] 隔壁老王头: @监控值班室 少量报警请忽略,批量关注即可. 监控值班室: @隔壁老王头 订单号[88886666]状 ...

  10. iOS、Android 开发的前景真的那么差吗?

    程序员问问周刊:别蕉绿了,问问「IT老兵哥」吧! Q:本科 985 在上海二线互联网企业工作,公司有人才落户指标,但要排队等五年左右.除此外只能等居住满七年落户,现在想换工作追求更好的发展,纠结是继续 ...