使用Python,字标注及最大熵法进行中文分词

时间:2023-03-09 19:44:37
使用Python,字标注及最大熵法进行中文分词

使用Python,字标注及最大熵法进行中文分词

在前面的博文中使用python实现了基于词典及匹配的中文分词,这里介绍另外一种方法, 这种方法基于字标注法,并且基于最大熵法,使用机器学习方法进行训练,将训练出的模型 用于中文分词,效果优于基于词典及匹配的分词方法。

1 背景知识

2002年以前,自动分词方法基本上基于词(或词典)的,在此基础上可以进一步分成基于规则和 基于统计两大类。同时,在分词工作中,未登录词对分词精度的影响非常大。所谓未登录词即没有 在词典中出现过的词,对于这种词,基于词典的方法无能为力,因此中文分词需要新的方法才能有 革命性的进展。

Nianwen Xue等人在2002年提出了以字分词的方法,并于2003年使用最大熵模型配合以字标注,参加了Bakeoff-2003的评测, 在AS语料库与HK语料库的测试中,其未登录词召回率均居榜首。在此后的Bakeoff-2005中,基于字标注的分词方法大放异彩, Jin Kiat Low等人采用最大熵模型及字标注的系统在四项开放测试中取得三个冠军,Huihsin Tseng等人采用条件随机场 及字标注的系统在封闭测试中取得两个冠军。

2 分词思想

2.1 以字分词

首先介绍以字分词。先看一个句子:我是一名程序员。再将所有字分为4类,S表示单字,B表示词首,M表示词中,E表示词尾。

如果我们知道上述句子中每个字的类别,即:

我/S 是/S 一/B 名/E 程/B 序/M 员/E 。/S

那么我们就可以知道这个句子的分词结果:我 是 一名 程序员 。

从这里可以看出,分词问题转化成了一个分类问题,即对每个字分类。我们知道,机器学习方法可以很好地处理分类问题。 所以接下来,我们需要用机器学习的方法来解决分词。

2.2 机器学习

机器学习处理问题的基本思想是,首先对标注好的数据进行训练,得到模型,再根据模型对新数据进行预测。这样我们将 问题转化为三个子问题:

  • 标注数据是什么?
  • 模型是什么?
  • 如何使用模型进行预测?

具体到以字分词问题,我们简单地回答上述三个问题。

  • 标注好的数据就是:字x在情境A下类别为a,字y在情境B下类别为c,字x在情境C下类别为e …
  • 模型就是:一些公式。这些公式是对数据的一种描述,其中包含了标注好的数据的信息,以及一些未知的参数,

对模型的训练就是采用机器学习的方法,赋予未知的参数一些合适的值,这些值使得公式的值达到最优。

  • 如何预测:给定字x,情境Z,我们得到模型后,就可以根据 x,Z,模型,得到在这种情况下x取各个类别的概率是多少,

由此可以预测出x的类别。

在上述回答中,有几个地方是没有定义的,例如,什么叫情境。在以字分词中,情境就是对一个字环境的描述,例如在句子我是 程序员中,如果我们将一个字的情境定义为:这个字前面的字和这个字后面的字。那么“程”这个字的情境为:“是”,以及“序”。

所以,所谓标注好的数据就是:{类别:情境}的集合,我们举例说明。

将C-1定义为字前的字,C0定义为当前字,C1定义为字后的字,那么如果我们有一句分好词的句子:我 是 一名 程序员 。

首先我们需要对每个字打个标签,表示类别:我/S 是/S 一/B 名/E 程/B 序/M 员/E 。/S

然后就可以转化为标注数据了,例如“程”字,可以得到一条标注数据为: B C-1=名 C0=序 C1=员

这条标注数据意思为当遇到C-1=名 C0=序 C1=员这种情境时,类别为B。

所以,由一堆分好词的数据,就可以得到许多条这样的标注数据。得到标注数据后,就可以使用机器学习包进行训练, 不同的机器学习包有不同的格式,但基本的思想都是这样的,我用的是张乐博士的最大熵工具包。

训练后可以得到相应的模型,预测时导入模型,然后给出相应情境(即C-1=? C0=? C1=?),就可以知道在此情境下各个类别的概率,在此可以简单地 认识哪个类别概率大,结果就是哪个类别,当然,也可以设计其它的方式。

在整个过程中,情境,机器学习方法,预测的方法都是可变的,但是以字分词大概的思想应该都是这样的。

3 实验及代码

3.1 数据来源

数据来自 Bakeoff2005 官方网站:http://sighan.cs.uchicago.edu/bakeoff2005/ 下载其中的 icwb2-data.tar.bz2 解压后取出以下文件:

  • 训练数据:icwb2-data/training/pku_ training.utf8
  • 测试数据:icwb2-data/testing/pku_ test.utf8
  • 正确分词结果:icwb2-data/gold/pku_ test_ gold.utf8
  • 评分工具:icwb2-data/script/socre

3.2 各部分数据示例

  1. 原始训练数据
    迈向  充满  希望  的  新  世纪
    
  2. 打标签后的训练数据
    迈/B向/E充/B满/E希/B望/E的/S新/S世/B纪/E
    
  3. 机器学习包可以接收的训练数据
    B C-1=b C0=迈 C1=向 C-1=bC0=迈 C0=迈C1=向 C-1=bC1=向 Num=0
    E C-1=迈 C0=向 C1=充 C-1=迈C0=向 C0=向C1=充 C-1=迈C1=充 Num=0
    B C-1=向 C0=充 C1=满 C-1=向C0=充 C0=充C1=满 C-1=向C1=满 Num=0
    E C-1=充 C0=满 C1=希 C-1=充C0=满 C0=满C1=希 C-1=充C1=希 Num=0
    B C-1=满 C0=希 C1=望 C-1=满C0=希 C0=希C1=望 C-1=满C1=望 Num=0
    E C-1=希 C0=望 C1=的 C-1=希C0=望 C0=望C1=的 C-1=希C1=的 Num=0
    S C-1=望 C0=的 C1=新 C-1=望C0=的 C0=的C1=新 C-1=望C1=新 Num=0
    S C-1=的 C0=新 C1=世 C-1=的C0=新 C0=新C1=世 C-1=的C1=世 Num=0
    B C-1=新 C0=世 C1=纪 C-1=新C0=世 C0=世C1=纪 C-1=新C1=纪 Num=0
    E C-1=世 C0=纪 C1=— C-1=世C0=纪 C0=纪C1=— C-1=世C1=— Num=0

    其中,Ci 表示与当前字偏移为i的字;Num表示是否为数字。

  4. 原始的测试数据
    共同创造美好的新世纪
    
  5. 可供模型预测的测试数据
    C-1=b C0=共 C1=同 C-1=bC0=共 C0=共C1=同 C-1=bC1=同 Num=0
    C-1=共 C0=同 C1=创 C-1=共C0=同 C0=同C1=创 C-1=共C1=创 Num=0
    C-1=同 C0=创 C1=造 C-1=同C0=创 C0=创C1=造 C-1=同C1=造 Num=0
    C-1=创 C0=造 C1=美 C-1=创C0=造 C0=造C1=美 C-1=创C1=美 Num=0
    C-1=造 C0=美 C1=好 C-1=造C0=美 C0=美C1=好 C-1=造C1=好 Num=0
    C-1=美 C0=好 C1=的 C-1=美C0=好 C0=好C1=的 C-1=美C1=的 Num=0
    C-1=好 C0=的 C1=新 C-1=好C0=的 C0=的C1=新 C-1=好C1=新 Num=0
    C-1=的 C0=新 C1=世 C-1=的C0=新 C0=新C1=世 C-1=的C1=世 Num=0
    C-1=新 C0=世 C1=纪 C-1=新C0=世 C0=世C1=纪 C-1=新C1=纪 Num=0
    C-1=世 C0=纪 C1=— C-1=世C0=纪 C0=纪C1=— C-1=世C1=— Num=0
  6. 预测结果
    共/B同/E创/B造/E美/B好/E的/S新/S世/B纪/E
    
  7. 分词结果
共同 创造 美好 的 新 世纪

注:上面展示的仅仅是数据示例,并非完整的数据

3.3 各部分代码示例

  1. 训练
    def training(feature_file_path, trained_model_file, times):
    m = MaxentModel()
    fr = codecs.open(feature_file_path, 'r', 'utf-8')
    all_list = []
    m.begin_add_event()
    for line in fr:
    line = line.rstrip()
    line_list = line.split(' ')
    str_list = []
    for item in line_list:
    str_list.append(item.encode('utf-8'))
    all_list.append(str_list)
    m.add_event(str_list[1:], str_list[0], 1)
    m.end_add_event()
    print 'begin training'
    m.train(times, "lbfgs")
    print 'end training'
    m.save(trained_model_file)
    return all_list

    这一部分使用了张乐博士的最大熵工具包提供的python接口,关键的代码是:

    m = MaxentModel()
    m.begin_add_event()
    m.add_event(str_list[1:], str_list[0], 1)
    m.end_add_event()
    m.train(times, "lbfgs")
    m.save(trained_model_file)
  2. 预测
def tag_test(test_feature_file, trained_model_file,  tag_test_set_file):
fr = codecs.open(test_feature_file, 'r', 'utf-8')
fw = codecs.open(tag_test_set_file, 'w', 'utf-8')
m = MaxentModel()
m.load(trained_model_file) for ...:
label_prob_list = m.eval_all(str_feature)
label = max_prob(label_prob_list)

这里只给出了部分代码,str_feature表示被测试的情境, label_prob_list表示各个类别的概率。

完整的代码可以参考我的Github主页上的分词工具: https://github.com/minixalpha/PyCWS/tree/master/src

参考文献:

1 黄昌宁,赵海.2007.中文分词十年回顾.中文信息学报,21(3): 8-19

2 Nianwen Xue, Suan P.Converse. 2002. Combining classifiers for Chinese word segmentation. Proceedings of the First SIGHAN workshop on Chinese language processing, 18:1-7.

3 Nianwen Xue, Libin Shen.2003. Chinese word segmentation as LMR tagging. Proceedings of the Second SIGHAN workshop on Chinese language processing, 17:176-179.

4 Richard Sproat, Thomas Emerson. 2003. The First international Chinese word segmentation Bakeoff. 17:133-143.

5 Thomas Emerson. 2005. The Second International Chinese Word Segmentation Bakeoff.

6 Jin Kiat Low, Hwee Tou Ng, and Wenyuan Guo. A Maximum Entropy Approach to Chinese Word Segmentation. 2005. Proceedings of the Fourth SIGHAN workshop on Chinese language processing.

7 Hai Zhao, Chang-Ning Huang and Mu Li. An Improved Chinese Word Segmentation System with Conditional Random Field. 2006. Proceedings of the Fifth SIGHAN workshop on Chinese language processing.

8 Adwait Ratnaparkhi. A maximum entropy model for part-of-speech tagging. 1996. Proceedings of the Empirical Methods in Natural Language Processing.

9 Le Zhang. Maximum Entropy Modeling Toolkit for Python and C++ . 2013,6. http://homepages.inf.ed.ac.uk/lzhang10/maxent_toolkit.html