用MeCab打造一套实用的中文分词系统(三):MeCab-Chinese

Deep Learning Specialization on Coursera

我在Github上发布了一个MeCab中文分词项目: MeCab-Chinese , 目的是提供一个用于中文分词和词性标注的MeCab词典和模型数据,类似MeCab日文IPA词典(mecab-ipadic),并且提供一些我自己用到的特征模板和脚本,方便大家从源头开始训练一个MeCab中文分词系统。

自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后(《用MeCab打造一套实用的中文分词系统(二)》), 收到了一些反馈,而这些反馈又促使我深入的review了一下mecab,重新设计特征及特征模板,加入了一些新的词典数据,重新训练模型,感兴趣的同学可以先试试这个0.2版本: mecab-chinesedic-binary (链接: http://pan.baidu.com/s/1gdxnvFX 密码: kq9g)
注:目前所有发布的版本均默认utf-8编码,并且在Mac OS和Linux Ubuntu下测试有效,windows没有测试,感兴趣的同学可自行测试)

了解和安装mecab仍请参考:
日文分词器 Mecab 文档
用MeCab打造一套实用的中文分词系统

这里再补充一点,由于google code废弃的缘故,MeCab这个项目已经搬迁至github,但是一些资源反而不如之前那么好找了,可参考两个MeCab作者维护的页面:
MeCab日文文档: http://taku910.github.io/mecab/
MeCab github 页面:https://github.com/taku910/mecab

MeCab目前最新的版本是2013-02-18更新的MeCab 0.996,我在Mac OS和Linux Ubuntu下用的是这个版本,在MeCab-Chinese下,做了一个备份,感兴趣的同学可以从这里下载: MeCab 0.996

在安装完毕MeCab之后,请下载这个模型词典数据,解压之后,可以这样执行:
mecab -d mecab-chinesedic-binary
自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后
自从 p,p,BE,2,自从,zi_cong,自從
上次 t,t,BE,2,上次,shang_ci,上次
在 p,p,S,1,在,zai,在
愚人 n,n,BE,2,愚人,yu_ren,愚人
节 n,n,S,1,节,jie,節
的 u,u,S,1,的,de,的
时候 n,n,BE,2,时候,shi_hou,時候
发布 v,v,BE,2,发布,fa_bu,發佈
了 u,u,S,1,了,le,了
一个 m,m,BE,2,一个,yi_ge,一個
mecab unk,unk,*,*,*,*,*
中文 n,nz,BE,2,中文,zhong_wen,中文
词典 n,n,BE,2,词典,ci_dian,詞典
和 c,c,S,1,和,he,和
数据 n,n,BE,2,数据,shu_ju,數據
模型 n,n,BE,2,模型,mo_xing,模型
之后 f,f,BE,2,之后,zhi_hou,之後
EOS

如果想得到单行的中文分词输出结果,可以这样执行:
mecab -d mecab-chinesedic-binary -O wakati
自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后
自从 上次 在 愚人 节 的 时候 发布 了 一个 mecab 中文 词典 和 数据 模型 之后

如果想得到词性标注的输出结果,可以这样执行:
mecab -d mecab-chinesedic-binary -O pos
自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后
自从/p 上次/t 在/p 愚人/n 节/n 的/u 时候/n 发布/v 了/u 一个/m mecab/unk 中文/nz 词典/n 和/c 数据/n 模型/n 之后/f

注意词性标记可以参考:《现代汉语语料库加工规范——词语切分与词性标注》。

由于增加了拼音和繁体两个特征,这里还有两个副产品可以输出,一个是输出中文分词之后的对应拼音:
mecab -d mecab-chinesedic-binary -O pinyin
自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后
自从/zi_cong 上次/shang_ci 在/zai 愚人/yu_ren 节/jie 的/de 时候/shi_hou 发布/fa_bu 了/le 一个/yi_ge mecab/unk 中文/zhong_wen 词典/ci_dian 和/he 数据/shu_ju 模型/mo_xing 之后/zhi_hou

另外一个是输出中文分词之后简体词到繁体词的转换:
mecab -d mecab-chinesedic-binary -O fan
自从上次在愚人节的时候发布了一个mecab中文词典和数据模型之后
自从/自從 上次/上次 在/在 愚人/愚人 节/節 的/的 时候/時候 发布/發佈 了/了 一个/一個 mecab/unk 中文/中文 词典/詞典 和/和 数据/數據 模型/模型 之后/之後

因为之前有同学留言如何输出词性标记,这个输出时可以指定格式或者在dicrc里面自定义,所以我在这个版本的dicrc里加了上述三种类型的输出:
cost-factor = 800
bos-feature = BOS/EOS,*,*,*,*,*,*
eval-size = 7
unk-eval-size = 4
config-charset = UTF-8

; pos
node-format-pos = %m/%f[1]\s
unk-format-pos = %m/unk\s
eos-format-pos = \n

; pinyin
node-format-pinyin = %m/%f[5]\s
unk-format-pinyin = %m/unk\s
eos-format-pinyin = \n

; fan
node-format-fan = %m/%f[6]\s
unk-format-fan = %m/unk\s
eos-format-fan = \n

感兴趣的同学可以参考《日文分词器 Mecab 文档》里第四节关于输出格式的一些说明。

在backoff2005 人民日报语料库上的测试结果:

=== SUMMARY:
=== TOTAL INSERTIONS: 3637
=== TOTAL DELETIONS: 1643
=== TOTAL SUBSTITUTIONS: 4969
=== TOTAL NCHANGE: 10249
=== TOTAL TRUE WORD COUNT: 104372
=== TOTAL TEST WORD COUNT: 106366
=== TOTAL TRUE WORDS RECALL: 0.937
=== TOTAL TEST WORDS PRECISION: 0.919
=== F MEASURE: 0.928
=== OOV Rate: 0.058
=== OOV Recall Rate: 0.495
=== IV Recall Rate: 0.964
### pku_test.result 3637 1643 4969 10249 104372 106366 0.937 0.919 0.928 0.058 0.495 0.964

召回率93.7%,准确率91.9%, F值为92.8%, 比上一个版本略好一些,另外感兴趣的同学也可以通过这个版本的中文分词Demo 进行测试。

==============================================================

如果觉得仅仅使用MeCab进行中文分词和词性标注还不过瘾,想自己train一个mecab分词所用的模型和词典,那么可以继续。之前在这里写过一篇《用MeCab打造一套实用的中文分词系统》 ,但是回过头来再看,其实问题多多,特别是特征模板这块儿,有很多歉考虑的地方,不过整个套路应该是没问题的,所以依然有一定的参考价值。

这个版本里定义了7个特征:
*词性1级分类(其实仅仅为了方便,取词性标记首字母而已)
*词性2(这是真实的词性)
*字标注tag(BEMS)
*中文词字数
*中文词基本型
*拼音
*繁体

所以训练语料需转换为如下的形式:
中文 n,nz,BE,2,中文,zhong_wen,中文
词典 n,n,BE,2,词典,ci_dian,詞典
和 c,c,S,1,和,he,和
数据 n,n,BE,2,数据,shu_ju,數據
模型 n,n,BE,2,模型,mo_xing,模型
之后 f,f,BE,2,之后,zhi_hou,之後
EOS

而词典文件需转换为如下的形式:
中文,0,0,0,n,nz,BE,2,中文,zhong_wen,中文
词典,0,0,0,n,n,BE,2,词典,ci_dian,詞典
和,0,0,0,c,c,S,1,和,he,和
数据,0,0,0,n,BE,2,数据,shu_ju,數據
模型,0,0,0,n,n,BE,2,模型,mo_xing,模型
之后,0,0,0,f,f,BE,2,之后,zhi_hou,之後

关于这个版本对应的配置文件可以在MeCab-Chinese上查看, 其中dicrc和上述一致,这里就不说了。这里分别说一下几个配置文件。

char.defunk.def 用于未登录词的处理,这里基本复用了mecab日文ipadic里的两个文件,做了少许修改:

DEFAULT,0,0,0,unk,unk,*,*,*,*,*
SPACE,0,0,0,unk,unk,*,*,*,*,*
KANJI,0,0,0,unk,unk,*,*,*,*,*
SYMBOL,0,0,0,unk,unk,*,*,*,*,*
NUMERIC,0,0,0,unk,unk,*,*,*,*,*
ALPHA,0,0,0,unk,unk,*,*,*,*,*
HIRAGANA,0,0,0,unk,unk,*,*,*,*,*
GREEK,0,0,0,unk,unk,*,*,*,*,*
CYRILLIC,0,0,0,unk,unk,*,*,*,*,*
KANJINUMERIC,0,0,0,unk,unk,*,*,*,*,*
KATAKANA,0,0,0,unk,unk,*,*,*,*,*

rewrite.def, 做了最小化的精简:
[unigram rewrite]
*,*,*,*,*,*,* $1,$2,$3,$4,$5,$6,$7

[left rewrite]
*,*,*,* $1,$2,$3,$4

[right rewrite]
*,*,*,* $1,$2,$3,$4

feature.def是crf特征模板,重新基于特征定义了一下:
# POS Unigram
UNIGRAM U1:%F[0]
UNIGRAM U2:%F[0],%F?[1]
UNIGRAM U3:%F[0],%F[1],%F[2]

# Word-POS
UNIGRAM W0:%F[4]
UNIGRAM W1:%F[0]/%F[4]
UNIGRAM W2:%F[1]/%F[4]
UNIGRAM W3:%F[2]/%F[4]
UNIGRAM W4:%F[0],%F?[1]/%F[4]
UNIGRAM W5:%F[1],%F?[2]/%F[4]
UNIGRAM W6:%F[0],%F[1],%F?[2]/%F[4]

# Word-Freq
UNIGRAM WF0:%F[3]
UNIGRAM WF1:%F[3]/%F[4]

# POS-Freq
UNIGRAM PF1:%F[0]/%F[3]
UNIGRAM PF2:%F[1]/%F[3]
UNIGRAM PF3:%F[0],%F?[1]/%F[3]
UNIGRAM PF4:%F[1],%F?[2]/%F[3]
UNIGRAM PF5:%F[0],%F[1],%F?[2]/%F[3]

# Read-POS
UNIGRAM RP0:%F[5]
UNIGRAM RP1:%F[0]/%F[5]
UNIGRAM RP2:%F[1]/%F[5]
UNIGRAM RP3:%F[2]/%F[5]
UNIGRAM RP4:%F[0],%F?[1]/%F[5]
UNIGRAM RP5:%F[1],%F?[2]/%F[5]
UNIGRAM RP6:%F[0],%F[1],%F?[2]/%F[5]

# Fan-POS
UNIGRAM RP0:%F[6]
UNIGRAM RP1:%F[0]/%F[6]
UNIGRAM RP2:%F[1]/%F[6]
UNIGRAM RP3:%F[2]/%F[6]
UNIGRAM RP4:%F[0],%F?[1]/%F[6]
UNIGRAM RP5:%F[1],%F?[2]/%F[6]
UNIGRAM RP6:%F[0],%F[1],%F?[2]/%F[6]

# Word-Read-POS
UNIGRAM R1:%F[4],%F[5]
UNIGRAM R2:%F[0],%F[4],%F[5]
UNIGRAM R3:%F[1],%F[4],%F[5]
UNIGRAM R4:%F[2],%F[4],%F[5]
UNIGRAM R5:%F[0],%F?[1],%F[4],%F[5]
UNIGRAM R6:%F[1],%F?[2],%F[4],%F[5]
UNIGRAM R7:%F[0],%F[1],%F?[2],%F[4],%F[5]

# Word-Fan-POS
UNIGRAM F1:%F[4],%F[6]
UNIGRAM F2:%F[0],%F[4],%F[6]
UNIGRAM F3:%F[1],%F[4],%F[6]
UNIGRAM F4:%F[2],%F[4],%F[6]
UNIGRAM F5:%F[0],%F?[1],%F[4],%F[6]
UNIGRAM F6:%F[1],%F?[2],%F[4],%F[6]
UNIGRAM F7:%F[0],%F[1],%F?[2],%F[4],%F[6]

# char type
UNIGRAM T0:%t
UNIGRAM T1:%F[0]/%t
UNIGRAM T2:%F[0],%F?[1]/%t
UNIGRAM T3:%F[0],%F[1],%F?[2]/%t
UNIGRAM T4:%F[0],%F[1],%F[2],%F?[3]/%t
UNIGRAM T5:%F[0],%F[1],%F[2],%F[3],%F[4]/%t

#
# bigram
#

BIGRAM B00:%L[0]/%R[0]
BIGRAM B01:%L[0],%L?[1]/%R[0]
BIGRAM B02:%L[0]/%R[0],%R?[1]
BIGRAM B03:%L[0]/%R[0],%R[1],%R?[2]
BIGRAM B04:%L[0],%L?[1]/%R[0],%R[1],%R?[2]
BIGRAM B05:%L[0]/%R[0],%R[1],%R[2],%R?[3]
BIGRAM B06:%L[0],%L?[1]/%R[0],%R[1],%R[2],%R?[3]
BIGRAM B07:%L[0],%L[1],%L?[2]/%R[0]
BIGRAM B08:%L[0],%L[1],%L?[2]/%R[0],%R?[1]
BIGRAM B09:%L[0],%L[1],%L[2],%L?[3]/%R[0]
BIGRAM B10:%L[0],%L[1],%L[2],%L?[3]/%R[0],%R?[1]
BIGRAM B11:%L[0],%L[1],%L?[2]/%R[0],%R[1],%R?[2]
BIGRAM B12:%L[0],%L[1],%L?[2]/%R[0],%R[1],%R[2],%R?[3]
BIGRAM B13:%L[0],%L[1],%L[2],%L?[3]/%R[0],%R[1],%R?[2]

最后提供两个脚本,你只需按如下形式准备词典和训练语料即可:

词典格式:中文词/中文词性标记(这里不限制使用某个特定的词性标记), 例如:
中文/n
词典/n
和/c
数据/n
模型/n

语料格式:带词性标注即可
中文/n 词典/n 和/c 数据/n 模型/n

具体可以参考script的两个脚本文件: make_mecab_seed_data.py 和 make_mecab_train_data.py

注意,这里用的是这个汉字到拼音的转换方案,使用脚本前需要先安装: https://github.com/cleverdeng/pinyin.py

另外汉字简体到繁体的转换代码已经拷贝和数据已经放到script目录下,不需要安装了,这个来源于:https://github.com/skydark/nstools

执行上述两个脚本的时候都需要在script目录下执行,需要load一些数据。

ok,MeCab-Chinese的一些介绍就到此为止了,欢迎大家一起参与共建MeCab-Chinese。

注:原创文章,转载请注明出处“我爱自然语言处理”:www.52nlp.cn

本文链接地址:用mecab打造一套实用的中文分词系统三:mecab-chinese

欢迎关注我们的公众号

NLPJob

用MeCab打造一套实用的中文分词系统(三):MeCab-Chinese》上有28条评论

  1. Janvn

    你好,为什么我用msr_training_words.utf8 作爲詞源,在script文件夹下执行 python make_mecab_seed_data.py ../icwb2-data/gold/msr_training_words.utf8 msr_words.csv,生成的msr_words.csv是個空文件?(文件路勁都是對的)

    [回复]

  2. Janvn

    哦,我是不是詞源的格式有誤吧?請問你用的詞源能發我一份嗎?

    [回复]

    52nlp 回复:

    这里带有词性,如果处理msr_training_words.utf8的文字,参考第一篇文章的脚本。这个脚本对应的格式如下:

    词典格式:中文词/中文词性标记(这里不限制使用某个特定的词性标记), 例如:
    中文/n
    词典/n
    和/c
    数据/n
    模型/n

    语料格式:带词性标注即可
    中文/n 词典/n 和/c 数据/n 模型/n

    我用的语料和词典可能有版权问题,暂时无法提供,抱歉。不过部分用到了这个词典,可以自己制作上述格式的词典:http://www.nlpcn.org/resource/25

    [回复]

  3. Lei

    你好,经常拜读你的文章,受益匪浅。
    有几个关于MECAB的问题,想请你指教。
    1. 请问这两个特征对训练有用处吗?比如,“BE,2”,“BME,3”。因为在日本版没有看到这两个特征。
    2. 请问你使用了未登陆词的处理吗?我自测的版本,使用了未登陆词的处理,发现结果不是很满意。第一,未登陆词是固定长度n,这和文档写的1~n不符合。第二,未登陆词大多是和右边的单字词合并,所以经常会有这样的错误:张 嫚说, 而不是 张嫚 说 (嫚是unk)。不知道你对未登陆词的处理有什么好的建议吗?

    谢谢!

    [回复]

    52nlp 回复:

    谢谢,关于问题1,我只是想把字标注的一些特征用进来,所以加了这两个特征,但是没有详细测试;关于问题2,这里的未登录词处理比较简单,主要是处理一些特殊字符,没有特别的处理。

    [回复]

  4. vangogh

    看了你的文章,非常有帮助。
    请问一个关于特征的问题?如果我想设置的特征为:左边term的词性+当前term的词性,请问如何设置呢? 看了特征那块,不是很明白bigram特征设置方法,它只能设置左右两边的term特征组合吗?
    谢谢啦

    [回复]

  5. hyj

    mecab -d mecab_chinese_data_binary/ test_set.txt
    param.cpp(77) [pos != std::string::npos] format error:

    其中 mecab_chinese_data_binary 就是从你给出的链接下载的(v0.3)

    mecab 版本是0.996 , 通过apt-get直接安装的。
    如果不用 -d 选项是可以运行的,但是现实乱码,估计是日文(不懂。。。)

    [回复]

    52nlp 回复:

    test_set.txt里面文本格式是什么?

    [回复]

    hyj 回复:

    跟test_set.txt无关, 我不用-d 就可以运行的。
    只是显示日文。
    及时没有test_set.txt, 也会有异常
    mecab -d mecab_chinese_data_binary/
    param.cpp(77) [pos != std::string::npos] format error:

    [回复]

    52nlp 回复:

    怀疑和apt-get这个安装方式有关,默认应该也给你安装了日文词典,具体为什么这样报错我不太清楚,难道和编码有关?不太确定,你可以试试源代码安装方式。

  6. AndyJi

    您好,麻烦请教问下词典还有语料的词性标注该怎么做,只能按照链接的那个百度文库的文档自己手动标记?还是可以通过python脚本实现?谢谢您

    [回复]

    52nlp 回复:

    纯粹的标注还是手工标注的,可以在一个机器标注的语料上进行人工修正

    [回复]

  7. AndyJi

    您好,还想麻烦问下训练出来的COST值有负值这个对么,不应该都是大于等于0的正整数么,我训练出来有好多负的。我贴了几个数值:
    公司,124,124,423,n,n,BE,2,公司,gong_si,公司
    表示,416,416,-2294,v,v,BE,2,表示,biao_shi,表示
    目前,409,409,-4497,t,t,BE,2,目前,mu_qian,目前
    市场,124,124,193,n,n,BE,2,市场,shi_chang,市場
    记者,124,124,906,n,n,BE,2,记者,ji_zhe,記者
    中国,236,236,-45,n,ns,BE,2,中国,zhong_guo,中國
    进行,416,416,-1917,v,v,BE,2,进行,jin_xing,進行
    已经,51,51,1380,d,d,BE,2,已经,yi_jing,已經
    我们,396,396,-3554,r,r,BE,2,我们,wo_men,我們
    通过,389,389,-501,p,p,BE,2,通过,tong_guo,通過

    上面几个是训练的结果,copy了10行出来,这个可能是什么问题啊
    谢谢您

    [回复]

    52nlp 回复:

    之前没注意这个问题,看了一下mecab文档,负值是允许的,另外也看了一下之前训练的数据,有少量负值,但是没有这里这么频繁。另外你的cost-factor是怎么设置的?

    [回复]

    AndyJi 回复:

    我还没懂那些配置文件怎么写,所以cost-factor是按照您的文件copy来的。
    词典和训练语料我是网上找的然后加工成需要的格式,但我的词典和语料感觉不好,不知道这个会不会有影响。
    然后还想麻烦问下,我一开始按照第一个教程去了解mecab工作流程,当时训练的权重是一样的,我在那个教程也请教过您,我现在猜测会不会是应为那些词都没有加特征的缘故,就是没有特征,所以词典的各词权重才一样,不知道这猜测合不合理。
    我还有个猜测就是,即使词都没有加特征,但通过修改配置文件里的一些参数,应该也能把词典的权重训练出来,但又有个小问题就是,词不加特征,那么feature.def还起作用么?谢谢您,麻烦您了

    [回复]

    52nlp 回复:

    第一个教程确实只是走通了流程,特征很少,真正起作用的还是词典。feature.def是特征模板,基于它才能生成特征进行训练的,必须起作用吧。

  8. AndyJi

    再打扰问下如何去理解mecab这里面的特征模板啊,我看了下crf原理,那些理论公式也都能推导出来,但有点云里雾里没有感性的认识,还是不知道怎么和他这个特征模板对上,能不能麻烦您挑一两句讲解下,谢谢您

    [回复]

    52nlp 回复:

    去看一下model.def里的特征,大概就有了直观的感受;大致来说,特征模板就是定义了一些匹配模式,然后训练的时候如果这个模式匹配上了,就计数。

    [回复]

  9. ylnlp

    emm,我进行训练后输出的词性标注结果基本都是/0是怎么回事?可以帮忙分析一下吗?

    [回复]

    52nlp 回复:

    抱歉,这个没有办法帮你分析,和你自己的训练集以及设定的特征有关,可以检验你指定的词性标注输出的参数是否正确。

    [回复]

    ylnlp 回复:

    感谢回复,是这样的,我比对了一下加词性标注之前的训练结果,也就是“用MeCab打造一套实用的中文分词系统”里面的流程做的训练,seed词典和最后生成的二进制词典都比加了词性标注后的词典大10倍不只。而使用的词性标注训练数据其实是比单纯分词的数据量大的,有5M左右,只做分词的msr_training只有1M左右。是因为训练数据的原因导致的吗?

    [回复]

    52nlp 回复:

    第一个版本数据量确实会小一些,这个增大的最主要原因是特征集合增大了,体现在model文件里,至于seed增大到10倍左右,我不太确定什么原因,你额外加词典了吗?

    ylnlp 回复:

    啊,我找到问题了,制作seed词典的时候数据格式不对,导致有效数据量骤减。我之前的意思其实是第一个版本的词典要大。现在已经成功训练好了自己的版本。还是感谢回复

    [回复]

  10. 夏云

    Hi, 我尝试了一下,但发现未登录词不能识别,不知道是不是我有什么做的不对

    [回复]

  11. zhang

    我是一个程序初学者,我用了RMeCab来处理日语分词,但是,RMeCabC的命令只能输入文字,无法导入txt文件,想请教一下 如果希望对大量的文字进行分词处理,例如我现在的文章集中在某一个txt文件中,需要用什么命令呢?

    [回复]

    52nlp 回复:

    没有用过RMeCab,不清楚R语言下Mecab的处理流程。不过你既然已经可以使用RMeCab了,那么直接调用Mecab处理待分词文件就可以了,类似这样的:

    mecab -d -O wakati 带分词的日文文件路径 -o 分词后的文件输出路径

    [回复]

    zhang 回复:

    mecab -d -O wakati 这个在R里面怎么找 我真的是不太清楚,您是用什么来直接分词的,不需要显示词性之类的 命令如何实现呢?非常感谢您的回复。

    [回复]

    52nlp 回复:

    命令行,不需要在R里找,我在Linux Ubuntu下或者Mac OS下都可以执行。

发表评论

电子邮件地址不会被公开。 必填项已用*标注