zoukankan      html  css  js  c++  java
  • 写了一个基于MMSeg分词算法的中文分词器(C++)

    MMSEG恐怕是最简单易实现而且效果还可以的基于字典的机械分词算法。http://nzinfo.spaces.live.com/Blog/cns!67694E0B61E3E8D2!344.entry

    当前我的程序放在http://code.google.com/p/chinese-word-segmentaion/

    网上有一个C++版本的源代码,但是我运行老是字典载入不成功。我看了下他的代码内部用的map而没有用hash map,这应该会影响效率。当然这个好改但是完全弄懂别人的代码很费劲,于是我自己重写了一个。另外那个网上的程序时用UTF8表示的,我的程序内部完全采用UTF16表示,利用u16string作为key.这样统一处理hash比较快,英文什么的也是UTF16所以处理方便。其余的输入文件完全可以用软件或者程序内部写代码转换成UTF16格式。

    具体效率等等还有待优化验证。另外我没有完全实现MMSEG算法,当前简单实现了下所以暂时忽略了MMSEG之中的规则4.而且我的字典也是自己在网上随便找的一个处理了一下,词比较少算上单字一共775534个词。网上那个默认的字典应该是109228个词。

    • 规则1:取最大匹配的chunk (Rule 1: Maximum matching)
    • 规则2:取平均词长最大的chunk (Rule 2: Largest average word length)
    • 规则3:取词长标准差最小的chunk (Rule 3: Smallest variance of word lengths)
    • 规则4:取单字词自由语素度之和最大的chunk (Rule 4: Largest sum of degree of morphemic freedom of one-character words)

    即使在当前比较粗糙的情况下,效果还是勉强凑合的,虽然由于有些词字典中不存在以及我没有实现规则4当前,影响了效果。我用平凡的世界验证了下(由于文字区分的问题还有点bug,主要是像这个文本中的"没有被识为标点,这个造成了段错误)。恩,大部分不对的地方是由于字典中缺少那个词,比如“快到”没有,“无终无影”没有,这个没办法字典里是“无影无踪”, “足不出户”也没有,连“响过"都没有,看来回头试试搜狗输入法的字典吧。

    往往还没等落地
    往$往还$没$等$落地$   这个分的比较郁闷,因为词典里有 往往,也有 往还 , 最终这里选择了往还 ,“没等”这个词当前字典里没有:(
    发这么一篇不成熟的东西是希望能和同样喜欢分词的朋友多交流。

    当前的程序太粗糙了,因为是用深度优先暴力搜索索引复杂度很高,尤其是局长长度比较大的时候,当前机械式的将长句子中间割断,毕竟正常文本中的长句子很少。

    就是用MMSEG算法的步骤1,2,3以及一个简单的字典我用SIGHAN 2005提供的测试语料测试了一下pku_test.txt.呵呵,结果很惨,不过毕竟是简单的开始,

    希望有时间继续完善一下程序。

    恩,速度很慢。。。 主要是算法实现的原因,当前指数级别的:)这个时间是全部时间包括读字典建立字典分词,写入到输出文件的全部时间。

    pku_test_utf16是一个UTF16格式的文本大小为345K。

    allen:~/study/my_project/chinese-word-segmentaion/build/bin$ time ./create_dict /mnt/hgfs/ubuntu.data/icwb2-data/testing/pku_test_utf16.txt
    [==========] Running 1 test from 1 test case.
    [----------] Global test environment set-up.
    [----------] 1 test from test_dict
    [ RUN      ] test_dict.perf
    [       OK ] test_dict.perf (7436 ms)
    [----------] 1 test from test_dict (7437 ms total)

    [----------] Global test environment tear-down
    [==========] 1 test from 1 test case ran. (7441 ms total)
    [  PASSED  ] 1 test.

    real    0m7.492s
    user    0m5.904s
    sys     0m1.120s

    恩,正确度也比较惨,比较式初始版本。。 还有字典比较弱。。。

    allen:/mnt/hgfs/ubuntu.data/icwb2-data$ perl scripts/score gold/pku_training_words.txt gold/pku_test_gold.txt result.unicode.text > score.txt

    === SUMMARY:
    === TOTAL INSERTIONS: 13007
    === TOTAL DELETIONS: 3195
    === TOTAL SUBSTITUTIONS: 13570
    === TOTAL NCHANGE: 29772
    === TOTAL TRUE WORD COUNT: 104372
    === TOTAL TEST WORD COUNT: 114184
    === TOTAL TRUE WORDS RECALL: 0.839
    === TOTAL TEST WORDS PRECISION: 0.767
    === F MEASURE: 0.802
    === OOV Rate: 0.058
    === OOV Recall Rate: 0.232
    === IV Recall Rate: 0.876
    ### result.unicode.text 13007 3195 13570 29772 104372 114184 0.839 0.767 0.802 0.058 0.232 0.876

    我又换了一个更大一点的词典试了下,精度稍有提高到了83%

    allen:~/study/my_project/chinese-word-segmentaion/build/bin$ time ./create_dict /mnt/hgfs/ubuntu.data/icwb2-data/testing/pku_test_utf16.txt
    [==========] Running 1 test from 1 test case.
    [----------] Global test environment set-up.
    [----------] 1 test from test_dict
    [ RUN      ] test_dict.perf
    finshed set up dict
    [       OK ] test_dict.perf (10693 ms)
    [----------] 1 test from test_dict (10693 ms total)

    [----------] Global test environment tear-down
    [==========] 1 test from 1 test case ran. (10694 ms total)
    [  PASSED  ] 1 test.

    real    0m10.745s
    user    0m8.365s
    sys     0m1.680s

    pku_test_utf16.txt是我将原测试文本转换成了UTF16格式,大小为345K,内容应该就是那个98人民日报社语料。

    这样看来大概每秒30k,考虑到我的主机1G内存,虚拟机768M,虚拟机还很慢,算法还是暴力搜索指数级的,这个速度还可以了,

    至少说明了SGI STL的 unorederd_map速度还是很快的:)

    === SUMMARY:
    === TOTAL INSERTIONS: 8061
    === TOTAL DELETIONS: 4066
    === TOTAL SUBSTITUTIONS: 10045
    === TOTAL NCHANGE: 22172
    === TOTAL TRUE WORD COUNT: 104372
    === TOTAL TEST WORD COUNT: 108367
    === TOTAL TRUE WORDS RECALL: 0.865
    === TOTAL TEST WORDS PRECISION: 0.833
    === F MEASURE: 0.849
    === OOV Rate: 0.058
    === OOV Recall Rate: 0.388
    === IV Recall Rate: 0.894
    ### result.unicode.text2 8061 4066 10045 22172 104372 108367 0.865 0.833 0.849 0.058 0.388 0.894

    //用更新的词典运行对《平凡的世界》分词,效果如下,对比原始词典效果稍好

      《 平凡 的 世界 》 作者 : 路 遥  
     
     第一章 
     
     
         1 9 7 5 年 二 、 三月 间 , 一个 平平常常 的 日子 , 细 蒙蒙 的 雨丝 夹 着 一星半点 的 雪花 , 正 纷纷 淋淋 地 向 大地 飘洒 着 。 时令 已 快 到 惊蛰 , 雪 当然 再 不会 存留 , 往 往还 没 等 落地 , 就 已经 消失 得 无 踪 无 影 了 。 黄土高原 严寒 而 漫长 的 冬天 看来 就要 过去 , 但 那 真正 温暖 的 春天 还 远远 地 没有 到来 。  
     
     
         在 这样 雨雪 交加 的 日子 里 , 如果 没有什么 紧 要事 , 人们 宁愿 一整天 足不出户 。 因此 , 县城 的 大街小巷 倒 也 比 平时 少 了 许多 嘈杂 。 街巷 背阴 的 地方 。 冬天 残留 的 积雪 和 冰 溜子 正在 雨点 的 敲击 下 蚀 化 , 石板 街上 到处 都 漫 流 着 肮脏 的 污水 。 风 依然 是 寒冷 的 。 空荡荡 的 街道 上 , 有 时会 偶尔 走 过来 一个 乡下人 , 破 毡帽 护 着 脑门 , 胳膊 上 挽 一 筐子 土豆 或 萝卜 , 有气无力 地 呼唤 着 买主 。 唉 , 城市 在 这样 的 日子 里 完全 丧失 了 生气 , 变得 没有 一点 可爱 之 处 了 。  
     
     
         只有 在 半山腰 县立 高 中的 大 院坝 里 , 此刻 却 自有 一番 热闹 景象 。 午饭 铃声 刚刚 响 过 , 从 一 排排 高低 错落 的 石 窑洞 里 , 就 跑 出来 了 一群 一 伙 的 男男女女 。 他们 把 碗筷 敲 得 震 天价 响 , 踏 泥 带 水 、 叫 叫 嚷嚷 地 跑 过 院坝 , 向 南面 总务处 那 一排 窑洞 的 墙根 下 蜂 涌 而 去 。 偌大 一个 院子 , 霎时 就 被 这 纷乱 的 人群 踩踏 成 了 一片 烂泥 滩 。 与此同时 , 那些 家 在 本 城 的 走读生 们 , 也 正 三三两两 涌出 东面 学校 的 大门 。 他们 撑 着 雨伞 , 一路 说说笑笑 , 通过 一 段 早年间 用 横 石片 插 起 的 长长的 下坡路 , 不多时 便 纷纷 消失 在 城市 的 大街小巷 中 。  
     
     
         在校园内 的 南 墙根 下 , 现在 已经 按 班级 排 起 了 十几 路 纵队 。 各 班 的 值日生 正在 忙碌 地 给 众人 分 饭菜 。 每个人 的 饭菜 都 是 昨天 登记 好 并 付 了 饭票 的 , 因此 程序 并不 复杂 , 现在 值日生 只是 按 饭 表 付给 每人 预订 的 一 份 。 菜 分 甲 、 乙 、 丙 三等 。 甲 菜 以 土豆 、 白菜 、 粉条 为主 , 里面 有些 叫 人 嘴 馋 的 大 肉片 , 每份 三 毛 钱 ; 乙 菜 其它 内容 和 甲 菜 一样 , 只是 没有 肉 , 每份 一 毛 五 分钱 。 丙 菜 可 就 差 远 了 , 清水 煮 白萝卜 似乎 只是 为了 掩饰 这 过分 的 清淡 , 才 在 里面 象征性 地 漂 了 几点 辣子 油花 。 不过 , 这 菜 价钱 倒 也 便宜 , 每份 五 分钱 。  
     
     
         各 班 的 甲 菜 只是 在 小 脸盆 里 盛 一点 , 看来 吃 得 起 肉 菜 的 学生 没有 几个 。 丙 菜 也 用 小 脸盆 盛 一点 , 说明 吃 这种 下等 伙食 的 人 也 没有 多少 。 只有 乙 菜 各 班 都 用 烧 瓷 大 脚盆 盛 着 , 海 海 漫漫 的 , 显然 大部分 人 都 吃 这种 既 不 奢侈 也不 寒酸 的 菜 。 主食 也 分 三等 : 白 面馍 , 玉米 面馍 , 高粱 面馍 ; 白 、 黄 、 黑 , 颜色 就 表 明了 一种 差别 ; 学生 们 戏称 欧洲 、 亚洲 、 非洲 。  

    //原始词典分词结果

    下面是一个当前的结果,我先将文本分成了句子,利用一个句子iterator,然后对每个句子调用MMSEG算法分词.我的程序实现了对UTF16格式文本的读

    //单字的iterator和读sentence的iterator

     平凡$的$世界$
    作者
    作者$
    路遥
    路$遥$
    第一章
    第一章$
    年二
    年$二$
    三月间
    三月$间$
    一个平平常常的日子
    一个$平平常常$的$日子$
    细蒙蒙的雨丝夹着一星半点的雪花
    细$蒙蒙$的$雨丝$夹$着$一$星$半点$的$雪花$
    正纷纷淋淋地向大地飘洒着
    正$纷纷$淋$淋$地$向$大地$飘洒$着$
    时令已快到惊蛰
    时令$已$快$到$惊蛰$
    雪当然再不会存留
    雪$当然$再$不会$存留$
    往往还没等落地
    往$往还$没$等$落地$
    就已经消失得无踪无影了
    就$已经$消失$得$无$踪$无$影$了$
    黄土高原严寒而漫长的冬天看来就要过去
    黄土高原$严寒$而$漫长$的$冬天$看来$就$要$过去$
    但那真正温暖的春天还远远地没有到来
    但$那$真正$温暖$的$春天$还$远远$地$没有$到来$
    在这样雨雪交加的日子里
    在$这样$雨$雪$交$加$的$日子$里$
    如果没有什么紧要事
    如果$没有什么$紧$要事$
    人们宁愿一整天足不出户
    人们$宁愿$一$整天$足$不$出$户$
    因此
    因此$
    县城的大街小巷倒也比平时少了许多嘈杂
    县城$的$大街小巷$倒$也$比$平时$少$了$许多$嘈杂$
    街巷背阴的地方
    街$巷$背阴$的$地方$
    冬天残留的积雪和冰溜子正在雨点的敲击下蚀化
    冬天$残留$的$积$雪$和$冰$溜$子$正在$雨点$的$敲击$下$蚀$化$
    石板街上到处都漫流着肮脏的污水
    石板$街上$到处$都$漫$流$着$肮脏$的$污水$
    风依然是寒冷的
    风$依然$是$寒冷$的$
    空荡荡的街道上
    空荡荡$的$街道$上$
    有时会偶尔走过来一个乡下人
    有时$会$偶尔$走$过来$一个$乡下$人$
    破毡帽护着脑门
    破$毡$帽$护$着$脑门$
    胳膊上挽一筐子土豆或萝卜
    胳膊$上$挽$一$筐$子$土豆$或$萝卜$
    有气无力地呼唤着买主
    有气无力$地$呼唤$着$买主$

    唉$
    城市在这样的日子里完全丧失了生气
    城市$在$这样$的$日子$里$完全$丧失$了$生气$
    变得没有一点可爱之处了
    变得$没有$一点$可爱$之$处$了$
    只有在半山腰县立高中的大院坝里
    只有$在$半$山腰$县$立$高$中的$大院$坝$里$
    此刻却自有一番热闹景象
    此刻$却$自$有$一$番$热闹$景象$
    午饭铃声刚刚响过
    午饭$铃声$刚刚$响$过$
    从一排排高低错落的石窑洞里
    从$一排$排$高低$错落$的$石$窑洞$里$
    就跑出来了一群一伙的男男女女
    就$跑$出来$了$一群$一$伙$的$男$男女$女$
    他们把碗筷敲得震天价响
    他们$把$碗$筷$敲$得$震$天$价$响$
    踏泥带水
    踏$泥$带$水$
    叫叫嚷嚷地跑过院坝
    叫$叫嚷$嚷$地$跑$过$院$坝$
    向南面总务处那一排窑洞的墙根下蜂涌而去
    向$南面$总务$处$那$一排$窑洞$的$墙根$下$蜂$涌$而$去$
    偌大一个院子
    偌大$一个$院子$
    霎时就被这纷乱的人群踩踏成了一片烂泥滩
    霎$时$就$被$这$纷乱$的$人群$踩踏$成$了$一片$烂泥$滩$
    与此同时
    与此同时$
    那些家在本城的走读生们
    那些$家$在$本$城$的$走$读$生$们$
    也正三三两两涌出东面学校的大门
    也$正$三$三$两$两$涌$出$东面$学校$的$大门$
    他们撑着雨伞
    他们$撑$着$雨伞$
    一路说说笑笑
    一$路$说说$笑$笑$
    通过一段早年间用横石片插起的长长的下坡路
    通过$一$段$早$年间$用$横$石片$插$起$的$长$长$的$下坡路$
    不多时便纷纷消失在城市的大街小巷中
    不$多$时$便$纷纷$消失$在$城市$的$大街小巷$中$
    在校园内的南墙根下
    在校园内$的$南$墙根$下$
    现在已经按班级排起了十几路纵队
    现在$已经$按$班级$排$起$了$十几$路$纵队$
    各班的值日生正在忙碌地给众人分饭菜
    各$班$的$值日生$正在$忙碌$地$给$众人$分$饭菜$
    每个人的饭菜都是昨天登记好并付了饭票的
    每个人$的$饭菜$都$是$昨天$登记$好$并$付$了$饭$票$的$
    因此程序并不复杂
    因此$程序$并不$复杂$
    现在值日生只是按饭表付给每人预订的一份
    现在$值日生$只是$按$饭$表$付给$每人$预订$的$一$份$
    菜分甲
    菜$分$甲$

    乙$
    丙三等
    丙$三$等$
    甲菜以土豆
    甲$菜$以$土豆$
    白菜
    白菜$
    粉条为主
    粉$条$为主$
    里面有些叫人嘴馋的大肉片
    里面$有些$叫$人$嘴$馋$的$大$肉片$
    每份三毛钱
    每$份$三$毛$钱$
    乙菜其它内容和甲菜一样
    乙$菜$其它$内容$和$甲$菜$一样$
    只是没有肉
    只是$没有$肉$
    每份一毛五分钱
    每$份$一$毛$五$分钱$
    丙菜可就差远了
    丙$菜$可$就$差$远$了$
    清水煮白萝卜似乎只是为了掩饰这过分的清淡
    清水$煮$白萝卜$似乎$只是$为了$掩饰$这$过分$的$清淡$
    才在里面象征性地漂了几点辣子油花
    才$在$里面$象征性$地$漂$了$几点$辣子$油$花$
    不过
    不过$
    这菜价钱倒也便宜
    这$菜$价钱$倒$也$便宜$
    每份五分钱
    每$份$五$分钱$
    各班的甲菜只是在小脸盆里盛一点
    各$班$的$甲$菜$只是$在$小$脸盆$里$盛$一点$
    看来吃得起肉菜的学生没有几个
    看来$吃$得$起$肉$菜$的$学生$没有$几个$
    丙菜也用小脸盆盛一点
    丙$菜$也$用$小$脸盆$盛$一点$
    说明吃这种下等伙食的人也没有多少
    说明$吃$这种$下$等$伙食$的$人$也$没有$多少$
    只有乙菜各班都用烧瓷大脚盆盛着
    只有$乙$菜$各$班$都$用$烧$瓷$大脚$盆$盛$着$
    海海漫漫的
    海$海$漫$漫$的$
    显然大部分人都吃这种既不奢侈也不寒酸的菜
    显然$大部分$人$都$吃$这种$既$不$奢侈$也不$寒$酸$的$菜$
    主食也分三等
    主食$也$分$三$等$
    白面馍
    白面$馍$
    玉米面馍
    玉$米面$馍$
    高粱面馍
    高粱$面$馍$

    白$

    黄$

    黑$
    颜色就表明了一种差别
    颜色$就$表$明了$一种$差别$
    学生们戏称欧洲
    学生$们$戏$称$欧洲$
    亚洲
    亚洲$
    非洲
    非洲$
    从排队的这一片黑鸦鸦的人群看来
    从$排队$的$这$一片$黑$鸦$鸦$的$人群$看来$
    他们大部分都来自农村
    他们$大部分$都$来自$农村$
    脸上和身上或多或少都留有体力劳动的痕迹
    脸$上$和$身上$或多或少$都$留$有$体力劳动$的$痕迹$
    除过个把人的衣装和他们的农民家长一样土气外
    除$过$个把$人$的$衣装$和$他们$的$农民$家长$一样$土$气$外$
    这些已被自己的父辈看作是“先生”的人
    这些$已$被$自己$的$父$辈$看作$是$“$先生$”$的$人$
    穿戴都还算体面
    穿戴$都$还$算$体面$

  • 相关阅读:
    javascript高级知识分析——灵活的参数
    javascript高级知识分析——实例化
    javascript高级知识分析——上下文
    javascript高级知识分析——作为对象的函数
    javascript高级知识分析——函数访问
    javascript高级知识分析——定义函数
    new到底做了什么?
    JavaScript中的计时器原理
    解析Function.prototype.bind
    将类数组对象(array-like object)转化为数组对象(Array object)
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1622813.html
Copyright © 2011-2022 走看看