聚合国内IT技术精华文章,分享IT技术精华,帮助IT从业人士成长

日文分词器 Mecab 文档

2013-04-26 21:01 浏览: 3145344 次 我要评论(0 条) 字号:

一、日文分词器 MeCab 简介

mecab (http://mecab.sourceforge.net/) 是奈良先端科学技術大学院的工藤拓开发的日文分词系统, 该作者写过多个 machine learning 方面的软件包, 最有名的就是 CRF++, 目前该作者在 google@Japan 工作。

mecab 是基于CRF 的一个日文分词系统,代码使用 c++ 实现, 基本上内嵌了 CRF++ 的代码, 同时提供了多种脚本语言调用的接口(python, perl, ruby 等).整个系统的架构采用通用泛化的设计, 用户可以通过配置文件定制CRF训练中需要使用的特征模板。 甚至, 如果你有中文的分词语料作为训练语料,可以在该架构下按照其配置文件的规范定制一个中文的分词系统。

日文NLP 界有几个有名的开源分词系统, Juman, Chasen, Mecab.   Juman 和 Chasen 都是比较老的系统了, Mecab 系统比较新, 在很多方面都优于 Juman 和 Chasen, mecab 目前开发也比较活跃。 Mecab 虽然使用 CRF 实现, 但是解析效率上确相当高效, 据作者的介绍, Mecab 比基于 HMM 的 Chasen 的解析速度要快。 笔者在一台 Linux 机器上粗略测试过其速度,将近达到 2MB/s, 完全达到了工程应用的需求, 该系统目前在日文 NLP 界被广泛使用。

中文和日文的有着类似的分词需求,因此mecab 对于中文处理来说有着很好的借鉴价值, 由于mecab 的内部模块化得很清晰,如果能读懂其文档的话,是比较容易能看懂整套代码的。 可惜目前中文的资料很少, 而其自带的文档又都是日文的, 所以了解它的中国人不多。

笔者把 mecab 自带的文档从日文翻译成中文, 希望mecab对于中文分词有兴趣的读者能有借鉴价值。日语水平很烂, 大家凑合着看吧。 对于自由的文档翻译,有一句话: Document is like sex. If it’s good, it’s very very good. If it’s bad, it’s better than nothing.

二、关于 MeCab (和布蕪)

Mecab 是京都大学情报学研究科-日本电信电话股份有限公司通信科学基础研究所通过 Unit Project 的合作研究共同开发的词法分析引擎。其设计的基本方针是不依赖于具体的语言,词典,语料库, 采用 Conditional Random Fields (CRF) 模型进行参数估计, 性能优于使用隐马模型的 ChaSen 。同时, 平均解析速度高于 ChaSenJumanKAKASI 这些日文词法分析器. 顺便说一下, Mecab (和布蕪, めかぶ), 是作者最喜欢的食物.

目录

  • 特征

    • 不依赖于词典,语料的通用设计
    • 基于条件随机场(CRF)模型,解析精度高
    • 比 ChaSen 和 KAKASI 速度快
    • 词典检索的算法/数据结构使用双数组 Double-Array.
    • 库函数可重入再入
    • 各种脚本语言接口绑定(perl/ruby/python/java/C#)

    比较

    MeCabChaSenJUMANKAKASI
    解析模型bi-gram 马尔科夫模型可变长 马尔科夫模型bi-gram 马尔科夫模型最长一致
    cost 估计从语料库学习从语料库学习人手没有 cost 的概念
    学习模型CRF (区别式模型)HMM (生成式模型)
    词典检索算法Double ArrayDouble ArrayPatricia TreeHash?
    求解算法ViterbiViterbiViterbi决定的?
    连接表的实现2元 Table自动机2元 Table?没有连接表?
    词性层级无限制多级词性无限制多级词性固定2级没有词性概念?
    未登陆词处理字符种类 (动作定义可变更)字符种类 (不可变更)字符种类 (不可变更)
    带约束的解析可能2.4.0 以后可能不可能不可能
    N-best解可能不可能不可能不可能

    Mecab 为止词法分析器的开发历史请参考 这里

    邮件列表

    最新消息

    • 2008-02-03 MeCab 0.97
      • 修正多线程环境中词典打开时,独占控制不正常的 bug
      • Windows版本安装的时候, 可以指定词典的编码
      • 修正某些编译器无法编译的问题
      • 修改部分解析模式, 添加相应的 API(Tagger::set_partial())
      • 添加用于修改 word-lattice 生成级别的API (Tagger::set_lattice_level())
      • 添加修改温度参数的 API (Tagger::set_theta())
      • 添加变换到输出全切分模式的 API (Tagger::set_all_morphs())
    • 2007-06-10 MeCab 0.96
      • 修正缓冲区溢出的 bug
      • 设定为总是生成 POS-ID(-p 选项废除)
      • 词典分隔符从 : 改为 ,(CSV)
      • 修正了 charset 判定的 bug, 以及由此导致的 用户词典和系统词典 不兼容的 bug
      • 修正用户词典和系统词典的字符编码不一致的时候, 无法生成词典的 bug
      • 添加 –dump-config 选项, 把命令行选项 dump 出来
      • 添加基于 EM 的 HMM训练的函数 (experimental)
    • 2007-03-11 MeCab 0.95
      • 修正老的编译器无法编译的问题
      • csvのエスケープの不具合で “,”を含む単語が追加できなかった問題を修正
      • 修正一些 UTF8 词典无法正常生成的 bug
      • recall/precisionの表示が反対になっていたバグの修正
      • 修正命令行解析错误
      • 修正其他小 bug
    • 2007-02-24MeCab 0.94
      • 修正很多 bug
      • 加入 HMM 训练的支持 (experimental)
      • 添加 API 获取解析结果的所有信息 (begin_node_list, end_node_list)
      • char.def, unk.def, matrix.def 没有定义的时候, 修改为也可以顺利生成词典
      • 废除Windows版对 iconv.dll的依赖
      • 清理代码
    • 2006-07-30 MeCab 0.93
      • License 从 LGPL 修改为 BSD,LGPL,GPL
    • 2006-07-10 MeCab 0.92
      • 词典编译等, 一部分由 perl 实现的脚本使用 C++ 重写, 排除对 Perl 的依赖。
      • 词典编译 (mecab-dict-index) 高速化
      • 修改 rewrite.def 的语法
      • 追加 -x 选项用于指定未登录词词性
      • 支持词性 id
      • 修正字符种类信息在某些训练中失败的 bug
      • 其他小 bug 的修正
    • 2006-04-30 MeCab 0.91
      • 修正Windows 环境中字符串末尾半角空格丢失的 bug
      • 修正连接表前件和后见的大小不同时无法正常解析的bug
      • 在 mecab-dict-index 中添加 -f 选项, 使得用户可以指定 CSV 词典文件的编码
      • 修正一些 API 函数无法 export 的问题
      • CRF 训练时使用 pthread 加入并行支持 (experimental)
      • 修正无法生成用户词典的问题
      • example 目录中添加 MeCab 使用的例子 (unittest)
      • 其他小 bug 的修正
    • 2006-03-26 MeCab 0.90
      • Initial release!

    下载

    • MeCab 是自由软件.遵从GPL(the GNU General Public License), LGPL(Lesser GNU General Public License), 以及 BSD 许可证, 可以再发布, 详细说明请参看随附的 COPYING, GPL, LGPL, BSD 这几个文件.
    • MeCab 本体

      Source

      • mecab-0.97.tar.gz:下载
      • 不包含词典, 运行时词典是必需.

    Binary package for MS-Windows

    • mecab-0.97.exe:下载
    • Windows 版中包含编译好的 IPA 词典
    • MeCab 使用的词典

      IPA 词典

      • IPA 辞書, 基于IPA语料库, 使用 CRF 进行参数估计的词典 (推荐) 下载

      Juman 词典

      • Juamn 词典, 基于京都语料库, 使用 CRF 进行参数估计的词典 下载

      Canna dic

      • Canna 词典: 公开预定
    • perl/ruby/python/java 绑定

    安装

    UNIX

    • 运行依赖
      • C++ 编译器 (g++ 3.4.3 和 VC7 确认可以编译通过)
      • iconv (libiconv): 用于词典的编码转换
    • 安装步骤一般的自由软件的安装步骤即可.
       % tar zxfv mecab-X.X.tar.gz
      % cd mecab-X.X
      % ./configure
      % make
      % make check
      % su
      # make install

      词典的安装

      % tar zxfv mecab-ipadic-2.7.0-XXXX.tar.gz
      % mecab-ipadic-2.7.0-XXXX
      % ./configure
      % make
      % su
      # make install

    Windows

    从二进制安装的场合, 运行自解压安装程序 (mecab-X.X.exe). 词典也会同时装上.

    使用方法

    首先尝试词法解析

    mecab 启动的时候, 从标准输入读取数据,逐行对文本进行解析 .

    % mecab
    すもももももももものうち
    すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ
    も 助詞,係助詞,*,*,*,*,も,モ,モ
    もも 名詞,一般,*,*,*,*,もも,モモ,モモ
    も 助詞,係助詞,*,*,*,*,も,モ,モ
    もも 名詞,一般,*,*,*,*,もも,モモ,モモ
    の 助詞,連体化,*,*,*,*,の,ノ,ノ
    うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
    EOS

    输出格式和 ChaSen 有较大差异, 从左开始,依次为,

    表层形t词性,词性细分类1,词性细分类2,词性细分类3,活用形,活用型,原形,读音,发音

    如果给定输入文件参数, 则该文件成为解析对象. 另外, -o 选项可以用来指定输出文件 .

    % mecab INPUT -o OUTPUT

    逐词分隔输出

    使用 -O 选项可以得到如下输出格式.

    % mecab -O wakati
    太郎はこの本を二郎を見た女性に渡した。
    太郎 は この 本 を 二郎 を 見 た 女性 に 渡し た 。

    输出格式变更

    使用 -O 选项可以指定如下输出格式.

    % mecab -Oyomi (包含读音)
    % mecab -Ochasen (ChaSen兼容格式)
    % mecab -Odump (输出所有信息)

    这些输出格式都在 /usr/local/lib/mecab/ipadic/dicrc 文件中定义,另外, 用户也可以自由定义输出格式, 请参看 这里.

    高级使用方法

    文字编码转换

    没有特别说明, 缺省使用 euc 编码. 如果要使用 shift-jis 和 utf8 编码, 可以修改词典的 configure 脚本中 charset 选项, 重新编译词典, 这样就能生成 shift-jis 和 utf8 编码的词典.

    % tar zxfv mecab-ipadic-2.7.0-xxxx
    % cd mecab-ipadic-2.7.0-xxxx
    % ./configure --with-charset=sjis
    % make

    % tar zxfv mecab-ipadic-2.7.0-xxxx
    % ./configure --with-charset=utf8
    % make

    另外, 使用 mecab-dict-index 的 -t 选项可以重新生成不同文字编码的词典。 -f 选项为原始文本格式词典的文字编码.

    % cd mecab-ipadic-2.7.0-xxxx
    % /usr/local/libexec/mecab/mecab-dict-index -f euc-jp -t utf-8
    # make install

    UTF-8 only mode

    如果指定了 configure option 中 –enable-utf8-only 选项, 则 MeCab 固定使用 utf8 编码。在支持 euc-jp, shift-jis 编码的时候, MeCab 程序内部需要生成编码转换表; 指定–enable-utf8-only 选项后, 不生成该编码转换表, 由此可以减小最后生成的二进制程序的大小。

    未登陆词猜测

    MeCab 遇到未登陆词的时候会对其词性进行适当的猜测 .

    ホリエモン市
    ホリエモン 名詞,固有名詞,地域,一般,*,*,*
    市 名詞,接尾,地域,*,*,*,市,シ,シ
    EOS
    ホリエモンさん
    ホリエモン 名詞,固有名詞,人名,一般,*,*,*
    さん 名詞,接尾,人名,*,*,*,さん,サン,サン

    但是不能保证猜测的正确率。 要关闭词性猜测的功能,把未登陆词词性标定为 “未登陆词”, 可以使用 -x (–unk-feature) 选项, 该选项指定的字符串将被标定为未登陆词的词性.

    %mecab --unk-feature "未知語" 
    ホリエモンさん
    ホリエモン 未知語
    さん 名詞,接尾,人名,*,*,*,さん,サン,サン

    N-Best 解输出

    使用 -N #NUM 选项, 将输出最可能的前 #NUM 个结果, 理论上可以输出所有可能的解析结果, 由于输出缓存大小的限制, -N 的最大值限制为 512 .

    % mecab -N2
    今日もしないとね。
    今日 名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
    も 助詞,係助詞,*,*,*,*,も,モ,モ
    し 動詞,自立,*,*,サ変?スル,未然形,する,シ,シ
    ない 助動詞,*,*,*,特殊?ナイ,基本形,ない,ナイ,ナイ
    と 助詞,接続助詞,*,*,*,*,と,ト,ト
    ね 助詞,終助詞,*,*,*,*,ね,ネ,ネ
    。 記号,句点,*,*,*,*,。,。,。
    EOS
    今日 名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
    もし 副詞,一般,*,*,*,*,もし,モシ,モシ
    ない 形容詞,自立,*,*,形容詞?アウオ段,基本形,ない,ナイ,ナイ
    と 助詞,接続助詞,*,*,*,*,と,ト,ト
    ね 助詞,終助詞,*,*,*,*,ね,ネ,ネ
    。 記号,句点,*,*,*,*,。,。,。
    EOS

    致谢

    CRF 的参数估计使用了 Jorge Nocedal 发现的 L-BFGS 方法以及他的 FORTRAN 实现, 在此表示感谢。

    http://www.ece.northwestern.edu/~nocedal/lbfgs.html

    • J. Nocedal. Updating Quasi-Newton Matrices with Limited Storage (1980), Mathematics of Computation 35, pp. 773-782.
    • D.C. Liu and J. Nocedal. On the Limited Memory Method for Large Scale Optimization (1989), Mathematical Programming B, 45, 3, pp. 503-528.

    libmecab.html

    三、MeCab 库函数接口

    C 库函数说明

    以下提供了 C 的函数接口.

    mecab_t *mecab_new (int argc, char **argv)
    生成 mecab 的实例.
    参数为 main 函数风格的参数, argc, argv. 这些参数的处理方式和 mecab 命令行 的处理方式是相同给定。
    调用成功时, 返回 mecab_t 类型的指针, 使用该指针进行词法解析。 调用失败返回 NULL. 
    mecab_t *mecab_new2 (const char *arg)
    生成 mecab 的实例.
    函数参数为字符串格式。 调用成功时, 返回 mecab_t 类型的指针, 使用该指针进行词法解析。 
    const char *mecab_version()
    取得 mecab 的 version 字符串.
    const char *mecab_strerror (mecab_t* m)
    取得错误的内容(字符串格式). mecab_sparse_tostr 等函数返回 NULL 的时候,
    可以调用 mecab_strerror 函数获取 错误的内用。 获取 mecab_new,mecab_new2 时, m 指定为 NULL . 
    const char *mecab_sparse_tostr (mecab_t *m, const char *str)
    实行词法解析。参数m为 mecab_new 返回的 mecab_t 类型的指针,
    待解析的字符串通过 char 型指针指定. 解析结果通过 char 型指针 返回, 解析失败返回 NULL.
    返回指针所指向的内存无需调用者管理, 每次调用 mecab_sparse_tostr 的时候会重写这块内存,
    调用 mecab_destroy 的时候这块内存会被释放。
    const char *mecab_sparse_tostr2 (mecab_t *m, const char *str, size_t len)
    和 mecab_sparse_tostr 函数相当, len 指定需要解析的句子的长度。 
    char *mecab_sparse_tostr3 (mecab_t *m, const char *istr,size_t ilen char *ostr, size_t olen)
    类似于 mecab_sparse_tostr2 , 但可以指定输出 buffer(ostr) 及其长度 (olen).
    ostr 内存由调用方管理。 函数调用成功的时候,返回 char 型的指针,
    该返回指针 等同于 ostr. 如果解析结果的长度超过 olen, 解析失败, 返回 NULL. 
    const char *mecab_nbest_sparse_tostr (mecab_t *m, size_t N, const char *str)
    mecab_sparse_tostr () 的 N-Best 版本。N 为解析结果的个数.
    使用 N-Best 机能的时候, mecab_new 必须指定 -l 1 选项。
    const char *mecab_nbest_sparse_tostr2 (mecab_t *m, size_t N, const char *str, size_t len)
    mecab_sparse_tostr2 () 的输出 N-Best 解的版本. N 为解析结果的个数. 
    char *mecab_nbest_sparse_tostr3 (mecab_t *m, size_t N, const char *str, size_t len, char *ostr, size_t olen)
    mecab_sparse_tostr3 () 的输出 N-Best 解的版本. N 为解析结果的个数. 
    int mecab_nbest_init (mecab_t* m, const char* str);
    按顺序获取近似正确的N-Best 解析结果的时候, 先要调用该函数进行初始化. str 指定待解析的句子.
    初始化成功返回1, 失败返回0, 失败的原因通过 mecab_strerror 获取。 
    int mecab_nbest_init2 (mecab_t* m, const char* str, len);
    类似于 mecab_nbest_init () , len 指定句子的长度。
    const char *mecab_nbest_next_tostr (mecab_t* m)
    mecab_nbest_init() 调用之后,调用该函数按顺序获取近似正确的 N-Best 结果。
    调用失败时(例如, 所有解都获取完了)返回 NULL, 失败原因由 mecab_strerror 获取。 
    char *mecab_nbest_next_tostr2 (mecab_t *m , char *ostr, size_t olen)
    类似于 mecab_nbest_next_tostr(), ostr, olen 用于指定输出 buffer。
    调用失败时返回 NULL, 失败原因由 mecab_strerror 获取。
    void mecab_destroy(mecab_t *m)
    释放 mecab_t 型指针.

    要获取词条信息时, 使用 mecab_node_t 结果体 和 mecab_sparse_tonode 函数

    #define MECAB_NOR_NODE  0
    #define MECAB_UNK_NODE 1
    #define MECAB_BOS_NODE 2
    #define MECAB_EOS_NODE 3

    struct mecab_node_t {
    struct mecab_node_t *prev; // 前一个词条的指针
    struct mecab_node_t *next; // 后一个词条的指针

    struct mecab_node_t *enext; // 同一位置结束的词条的指针
    struct mecab_node_t *bnext; // 同一位置开始的词条的指针

    char *surface; // 词条的表面字符串
    // 没有以 NUL 结束. 因此要获取字符串, 需要使用
    // strncpy(buf, node->feature, node->length)

    char *feature; // CSV 格式的特征
    unsigned int length; // 词条的长度
    unsigned int rlength; // 词条的长度(包括开始处的空格)
    unsigned int id; // 词条的唯一标识 ID
    unsigned short rcAttr; // 下文语境 idid
    unsigned short lcAttr; // 上文语境 id
    unsigned short posid; // 词条词性特征 ID
    unsigned char char_type; // 字符类别信息
    unsigned char stat; // 词条类别: 可用以下几个宏
    // #define MECAB_NOR_NODE 0
    // #define MECAB_UNK_NODE 1
    // #define MECAB_BOS_NODE 2
    // #define MECAB_EOS_NODE 3
    unsigned char isbest; // 最优解场合为 1, 其他为 0

    float alpha; // forward backward 的 forward log 概率
    float beta; // forward backward 的 backward log 概率
    float prob; // 周边概率
    // alpha, beta, prob 在 -l 2 选项指定的时候定义

    short wcost; // 词条生成 cost
    long cost; // 累计 cost
    };
    const mecab_node_t *mecab_sparse_tonode (mecab_t *m, const char *str)
    执行解析操作, 参数 m 为 mecab_new 中得到的 mecab_t 类型的指针。
    待解析的句子为 char 型的字符串。函数调用成功时,返回句首词条(mecab_node_t 类型)对应的指针;失败时返回 NULL.
    mecab_node_t 为双向链表,可以使用 next, prev 按序访问所有的此条。
    函数返回指针所对应的内存无须调用方管理, mecab_sparse_tonode 函数被调用时会覆盖重写这块内存,
    mecab_destroy 函数调用时释放对应内存。 
    const mecab_node_t *mecab_sparse_tonode2 (mecab_t *m, const char *str, size_t len)
    类似于 mecab_sparse_tonode , len 指定待解析的句子长度. 
    const mecab_node_t *mecab_next_tonode (mecab_t* m)
    类似于 mecab_next_tostr [1] , 只是不返回字符串, 返回 mecab_node_t 类型的词条信息。

    要读取词典的信息时, 使用 mecab_dictionary_t 结构体和 mecab_dictionary_info() 函数。

    #define MECAB_USR_DIC   1
    #define MECAB_SYS_DIC 0
    #define MECAB_UNK_DIC 2

    struct mecab_dictionary_info_t {
    const char *filename; // 词典文件名
    const char *charset; // 词典编码
    unsigned int size; // 词条书目
    int type; // 词典类型, 可选值为 MECAB_(USR|SYS|UNK)_DIC
    unsigned int lsize; // 上文语境 ID 大小
    unsigned int rsize; // 下文语境 ID 大小
    unsigned short version; // 版本
    struct mecab_dictionary_info_t *next;   // 指向下一个词典的指针
    };
    const mecab_dictionary_info_t *mecab_dictionary_info(mecab_t *m)
    获取词典信息, 参数 m 为 mecab_new 得到的 mecab_t 类型的指针。
    mecab_dictoinary_info_t 为单向链表, 包含多个词典的时候, 可以使用 next 访问到所有的词典信息。
    mecab_dictionary_info() 函数返回的内存指针由 mecab 自己管理,调用者无须释放。

    以下API 用于修改解析时的参数设置。

    int mecab_get_partial(mecab_t *m)
    取得当前的部分解析模式。(0: off, 1:on)
    void mecab_set_partial(mecab_t *m)
    设定当前的部分解析模式。(0: off, 1:on)
    float mecab_get_theta(mecab_t *m)
    软性逐词分隔输出的温度参数的获取。
    void mecab_set_theta(mecab_t *m, float theta)
    软性逐词分隔输出的温度参数的设定。
    int mecab_get_lattice_level(mecab_t *m)
    取得 lattice-level(解析时生成哪个层级的 lattice 信息) 的值

    • 0: 可以输出最优解 (缺省, 高速)
    • 1: 可以输出 N-best 解 (中速)
    • 2: 软性逐词分隔输出(译者注: 类似于全切分) (低速)
    void mecab_set_lattice_level(mecab_t *m, int lattice_level)
    设定 lattice 层级。
    int mecab_get_all_morphs(mecab_t *m)
    取得输出模式。(0: 最优解, 1:全切分)
    void mecab_set_all_morphs(mecab_t *m, int all_mophrs)
    设定输出模式。(0: 最优解, 1:全切分)

    C 调用样例

    example/example.c

    #include <mecab.h>
    #include <stdio.h>

    #define CHECK(eval) if (! eval) {
    fprintf (stderr, "Exception:%sn", mecab_strerror (mecab));
    mecab_destroy(mecab);
    return -1; }

    int main (int argc, char **argv) {
    char input[1024] = "太郎は次郎が持っている本を花子に渡した。";
    mecab_t *mecab;
    mecab_node_t *node;
    const char *result;
    int i;

    mecab = mecab_new (argc, argv);
    CHECK(mecab);

    result = mecab_sparse_tostr(mecab, input);
    CHECK(result)
    printf ("INPUT: %sn", input);
    printf ("RESULT:n%s", result);

    result = mecab_nbest_sparse_tostr (mecab, 3, input);
    CHECK(result);
    fprintf (stdout, "NBEST:n%s", result);

    CHECK(mecab_nbest_init(mecab, input));
    for (i = 0; i < 3; ++i) {
    printf ("%d:n%s", i, mecab_nbest_next_tostr (mecab));
    }

    node = mecab_sparse_tonode(mecab, input);
    CHECK(node);
    for (; node; node = node->next) {
    fwrite (node->surface, sizeof(char), node->length, stdout);
    printf("t%sn", node->feature);
    }

    node = mecab_sparse_tonode(mecab, input);
    CHECK(node);
    for (; node; node = node->next) {
    printf("%d ", node->id);

    if (node->stat == MECAB_BOS_NODE)
    printf("BOS");
    else if (node->stat == MECAB_EOS_NODE)
    printf("EOS");
    else
    fwrite (node->surface, sizeof(char), node->length, stdout);

    printf(" %s %d %d %d %d %d %d %d %d %f %f %f %dn",
    node->feature,
    (int)(node->surface - input),
    (int)(node->surface - input + node->length),
    node->rcAttr,
    node->lcAttr,
    node->posid,
    (int)node->char_type,
    (int)node->stat,
    (int)node->isbest,
    node->alpha,
    node->beta,
    node->prob,
    node->cost);
    }

    mecab_destroy(mecab);

    return 0;
    }

    C++ 库函数说明

    以下为 C++ API 接口, 基本上同 C 的接口相同。

    • mecab_t 对应于 MeCab::Tagger
    • mecab_node_t 对应于 MeCab::Node
    • mecab_new() 对应于 MeCab::createTagger() 工厂函数
    • mecab_destroy () 使用 delete 释放内存
    namespace MeCab {
    typedef struct mecab_node_t Node;
    typedef struct mecab_dictionary_info_t DictionaryInfo;

    class Tagger {
    public:
    virtual const char* parse(const char*, size_t, char*, size_t) = 0;

    virtual const char* parse(const char*, size_t = 0) = 0;
    virtual Node* parseToNode(const char*, size_t = 0) = 0;

    virtual const char* parseNBest(size_t, const char*, size_t = 0) = 0;
    virtual bool parseNBestInit(const char*, size_t = 0) = 0;
    virtual Node* nextNode() = 0;
    virtual const char* next() = 0;
    virtual const char* formatNode(Node *) = 0;

    virtual const char* next(char*, size_t) = 0;
    virtual const char* parseNBest(size_t, const char*,
    size_t, char *, size_t) = 0;
    virtual const char* formatNode(Node *, char *, size_t) = 0;

    virtual bool partial() const = 0;
    virtual void set_partial(bool partial) = 0;
    virtual float theta() const = 0;
    virtual void set_theta(float theta) = 0;
    virtual int lattice_level() const = 0;
    virtual void set_lattice_level(int level) = 0;
    virtual bool all_morphs() const = 0;
    virtual void set_all_morphs(bool all_morphs) = 0;

    virtual const char* what() = 0;

    virtual const DictionaryInfo* dictionary_info() const = 0;

    virtual ~Tagger() {};

    static const char *version();

    static Tagger* create(int, char**);
    static Tagger* create(const char*);
    };

    /* factory method */
    Tagger *createTagger (int, char**);
    Tagger *createTagger (const char*);
    const char* getTaggerError ();
    }

    C++ 样例

    #include <iostream>
    #include <mecab.h>

    #define CHECK(eval) if (! eval) {
    const char *e = tagger ? tagger->what() : MeCab::getTaggerError();
    std::cerr << "Exception:" << e << std::endl;
    delete tagger;
    return -1; }

    int main (int argc, char **argv) {
    char input[1024] = "太郎は次郎が持っている本を花子に渡した。";

    MeCab::Tagger *tagger = MeCab::createTagger (argc, argv);
    CHECK(tagger);

    const char *result = tagger->parse(input);
    CHECK(result);
    std::cout << "INPUT: " << input << std::endl;
    std::cout << "RESULT: " << result << std::endl;

    result = tagger->parseNBest(3, input);
    CHECK(result);
    std::cout << "NBEST: " << std::endl << result;

    CHECK(tagger->parseNBestInit(input));
    for (int i = 0; i < 3; ++i) {
    std::cout << i << ":" << std::endl << tagger->next();
    }

    MeCab::Node* node = tagger->parseToNode(input);
    CHECK(node);
    for (; node; node = node->next) {
    std::cout.write(node->surface, node->length);
    }

    node = tagger->parseToNode(input);
    CHECK(node);

    for (; node; node = node->next) {
    std::cout << node->id << ' ';
    if (node->stat == MECAB_BOS_NODE)
    std::cout << "BOS";
    else if (node->stat == MECAB_EOS_NODE)
    std::cout << "EOS";
    else
    std::cout.write (node->surface, node->length);

    std::cout << ' ' << node->feature
    << ' ' << (int)(node->surface - input)
    << ' ' << (int)(node->surface - input + node->length)
    << ' ' << node->rcAttr
    << ' ' << node->lcAttr
    << ' ' << node->posid
    << ' ' << (int)node->char_type
    << ' ' << (int)node->stat
    << ' ' << (int)node->isbest
    << ' ' << node->alpha
    << ' ' << node->beta
    << ' ' << node->prob
    << ' ' << node->cost << std::endl;
    }

    delete tagger;

    return 0;
    }

    编译方法

      • UNIX 场合
    % cc -O2 `mecab-config --cflags` example.c -o example 
    `mecab-config --libs`
      • Windows 场合

    首先, 把 includemecab.h, binlibmecab.dll liblibmecab.lib 复制到执行编译的目录中, 后面的操作依不同的编译器有所不同。

        • cygwin/mingw 环境
    % gcc -DDLL_IMPORT -I. example.c -o example.exe libmecab.dll
        • VC++ 环境
    % cl -DDLL_IMPORT -I. example.c libmecab.lib

    有关多线程

    MeCab 支持多线程, 一个线程使用一个 (mecab_t *) 实例的时候是线程安全的。 另外,多个线程共享同一个词典, 词典是可以再利用的资源, 生成多个实例的时候无需使用过多内存。

    一个实例在多个线程上使用的时候需要适当的加锁控制, 由于会导致较差的性能, 所以不推荐使用。

    译者注

    [1] 原文为 mecab_next_tostr, 但是本文件的 API 中不存在该函数, 估计为笔误

     dic.html

    三、词条追加方法

    概要

    有两种方法可以往词典中追加词条.

    • 在系统词典中追加
    • 在用户词典中追加

    在系统词典中追加

    词典更新不频繁, 同时不想降低解析速度时,最好直接修改系统词典.

    • 进入包含文件 mecab-ipadic 的目录
    • 创建文件 foo.csv (扩展名不用 .csv 也可以)
    • foo.csv 文件中添加词条
    • 重新编译安装词典
      % /usr/local/libexec/mecab/mecab-dict-index -f euc-jp -t euc-jp
      % su
      # make install
      • -f charset: CSV 文件的编码
      • -t charset: 生成的二进制词典的编码

    例: 生成 utf-8 编码词典的例子

    % /usr/local/libexec/mecab/mecab-dict-index -f euc-jp -t utf8

    在用户词典中追加

    更新系统词典比较耗时; 词典更新频繁, 或者没有权限变更系统词典的时候, 也可以使用用户词典。

    • 进入适当的目录 (例: /home/foo/bar)
    • 创建 foo.csv 这种文件
    • 在 foo.csv 中添加词条
    • 编译词典
      % /usr/local/libexec/mecab/mecab-dict-index -d/usr/local/lib/mecab/dic/ipadic 
      -u foo.dic -f euc-jp -t euc-jp foo.csv
      • -d DIR: 包含系统词典的目录
      • -u FILE: FILE 生成的用户词典文件
      • -f charset: CSV 文件的编码
      • -t charset: 生成的二进制词典的编码
    • 确认生成了词典文件 /home/foo/bar/foo.dic
    • 在 /usr/local/lib/mecab/dic/ipadic/dicrc 或者 /usr/local/etc/mecabrc 中追加如下行
      userdic = /home/foo/bar/foo.dic
    • 没有权限修改文件 /usr/local/etc/mecabrc 的时候,把 /usr/local/etc/mecabrc 复制为 ~/.mecabrc 后, 添加如上的行
    • userdic 可以按照 CSV 格式指定多个
       userdic = /home/foo/bar/foo.dic,/home/foo/bar2/usr.dic,/home/foo/bar3/bar.dic

    词条的格式 (没有活用的词条)

    系统词典, 用户词典中词条的格式是相同的.

    每个词条, 按如下的 CSV 格式添加,如名词等没有活用的词条, 记录很简单 .

    工藤,1223,1223,6058,名詞,固有名詞,人名,名,*,*,くどう,クドウ,クドウ

    从左开始依次为,

    表层形, 上文语境ID, 下文语境ID, cost, 词性,词性细分类1,词性细分类2,词性细分类3,活用形,活用型,原形,读音,发音

    cost 值用于表示词条出现的容易程度,cost 值小表示词条容易出现. コストは,その単語がどれだけ出現しやすいかを示しています. 小さいほど, 出現しやすいという意味になります. 似たような単語と 同じスコアを割り振り, その単位で切り出せない場合は, 徐々に小さくしていけばいいと思います.

    上文语境 ID 是从该词条左边开始的语境的内部状态 ID, 从文件 left-id.def 中选择这些ID, 该文件通常在系统词典所在的目录中. 如果文件中只有 ID -1, mecab-dict-index 将自动的对 ID 赋值.

    下文语境 ID 是从该词条右边开始的语境的内部状态 ID, 从文件 right-id.def 中选择这些ID, 该文件通常在系统词典所在的目录中. 如果文件中只有 ID -1, mecab-dict-index 将自动的对 ID 赋值.

    另外,用户可以按 CSV 格式添加自己喜欢的信息 .

    ユーザ設定,-1,-1,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ
    运行例子:
    % mecab
    ユーザ設定が必要です。
    ユーザ設定 名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ
    が 助詞,格助詞,一般,*,*,*,が,ガ,ガ
    必要 名詞,形容動詞語幹,*,*,*,*,必要,ヒツヨウ,ヒツヨー
    です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
    。 記号,句点,*,*,*,*,。,。,。
    EOS

    词条的格式 (活用的词条)

    可以活用的词条, 用户必须自己把所有的活用情形展开, 比较麻烦。以下是 “いそがしい” 这个词条所有的活用词展开的情形 .

    いそがしい,120,120,6078,形容詞,自立,*,*,形容詞・イ段,基本形,いそがしい,イソガシイ,イソガシイ
    いそがし,128,128,6080,形容詞,自立,*,*,形容詞・イ段,文語基本形,いそがしい,イソガシ,イソガシ
    いそがしから,136,136,6079,形容詞,自立,*,*,形容詞・イ段,未然ヌ接続,いそがしい,イソガシカラ,イソガシカラ
    いそがしかろ,132,132,6079,形容詞,自立,*,*,形容詞・イ段,未然ウ接続,いそがしい,イソガシカロ,イソガシカロ
    いそがしかっ,148,148,6078,形容詞,自立,*,*,形容詞・イ段,連用タ接続,いそがしい,イソガシカッ,イソガシカッ
    いそがしく,152,152,6078,形容詞,自立,*,*,形容詞・イ段,連用テ接続,いそがしい,イソガシク,イソガシク
    いそがしくっ,152,152,6079,形容詞,自立,*,*,形容詞・イ段,連用テ接続,いそがしい,イソガシクッ,イソガシクッ
    いそがしゅう,144,144,6079,形容詞,自立,*,*,形容詞・イ段,連用ゴザイ接続,いそがしい,イソガシュウ,イソガシュウ
    いそがしゅぅ,144,144,6079,形容詞,自立,*,*,形容詞・イ段,連用ゴザイ接続,いそがしい,イソガシュゥ,イソガシュゥ
    いそがしき,124,124,6079,形容詞,自立,*,*,形容詞・イ段,体言接続,いそがしい,イソガシキ,イソガシキ
    いそがしけれ,108,108,6079,形容詞,自立,*,*,形容詞・イ段,仮定形,いそがしい,イソガシケレ,イソガシケレ
    いそがしかれ,140,140,6079,形容詞,自立,*,*,形容詞・イ段,命令e,いそがしい,イソガシカレ,イソガシカレ
    いそがしけりゃ,112,112,6079,形容詞,自立,*,*,形容詞・イ段,仮定縮約1,いそがしい,イソガシケリャ,イソガシケリャ
    いそがしきゃ,116,116,6079,形容詞,自立,*,*,形容詞・イ段,仮定縮約2,いそがしい,イソガシキャ,イソガシキャ
    いそがし,104,104,6080,形容詞,自立,*,*,形容詞・イ段,ガル接続,いそがしい,イソガシ,イソガシ

    chasen 在 grammar.cha cforms.char 文件中描述词法, 解析的时候展开. 这是对词条的活用动态展开, 因此, chasen 中只要添加词条的原形(基本型)即可。

    mecab 无法在解析中展开, 生成词典的时候使用静态展开的策略(静态活用展开). 这样做的理由和计算机的速度及资源相关联。 chasen 开发的时候, 内存大小受限,难以使用静态展开的方法。 现在, 由于内存和硬盘的空间都很充裕, 所以使用静态展开的策略, 可以提升解析的速度。

    将来会考虑加入如下框架: 自动从词法描述中把活用静态展开; 目前,活用的展开完全交给用户自己完成。

    format.html

    四、输出格式

    概要

    MeCab 和 ChaSen 一样, 可以比较自由的定义输出格式. Mecab 在配置文件中可以定义多种输出格式, 运行的时候可以切换不同的输出格式, 这是 MeCab 独有的功能。

    输出格式的指定

    可以修改以下4种输出格式.

    • node: 输出一个词语,缺省为空
    • unk: 输出一个未登陆词, 缺省使用 node 输出格式
    • bos: 句首的输出 , 缺省为空
    • eos: 句尾的输出, 缺省为 “EOSn”

    没有显示指定输出格式的时候, 将使用缺省的格式 .

    可以使用两种方式指定输出格式.

    • 通过命令行指定
      % mecab --node-format=STR --bos-format=STR --eos-format=STR --unk-format=STR
    • 通过 mecabrc 配置文件指定使用任意的字符串 KEY, 用户可以在 mecabrc 中定义相应的输出格式.
      node-format-KEY = STR
      unk-format-KEY = STR
      eos-format-KEY = STR
      bos-format-KEY = STR

      在命令行中可以指定使用 KEY 对应的输出格式.

      % mecab -Okey

    输出格式

    %s词条种类(0: 普通, 1: 未登陆词, 2:句首, 3:句尾)
    %S输入的句子
    %L输入句子的长度
    %m词条的表层字符串
    %M词条的表层字符串, 但其中包含的空白文字也会输出 (参照 %pS )
    %h素性的内部 ID
    %%百分号 %
    %c单语的 cost
    %H素性 (词性, 活用, 读音み) 字符串,CSV 格式
    %t字符类型 id
    %P周边概率 (仅在 -l2 选项指定的时候有效)
    %pi形態素に付与されるユニークなID
    %pSもし形態素が空白文字列で始まる場合は, その空白文字列を表示 %pS%m と %M は同一
    %ps开始位置
    %pe结束位置
    %pC同前一个词条的连接 cost
    %pw等同于 %c
    %pc连接 cost + 单语生成 cost (从句首累加)
    %pn连接 cost + 单语生成 cost ( 该词条独自的, %pw + %pC)
    %pb最优路径时输出为 *, 其他路径为 ‘ ‘
    %pP周边概率 (仅在 -l2 选项指定的时候有效) )
    %pAalpha, forward log 概率(仅在 -l2 选项指定的时候有效)
    %pBbeta, backward log 概率(仅在 -l2 选项指定的时候有效)
    %pl词条的表层字符串长度, 等同于 strlen (%m)
    %pL词条的表层字符串长度,但包括空白字符串, 等同于strlen(%M)
    %phl上文 id
    %phr下文 id
    %f[N]csv 格式的素性中第 N 个要素
    %f[N1,N2,N3...]第N1,N2,N3个素性, 用”,” 分隔
    %FC[N1,N2,N3...]第N1,N2,N3个素性, 用C 分隔 .
    只是ただし, 要素为空的时候, 以后的省略. (例)F-[0,1,2]
    a b t n v f r \普通的转义字符
    s‘ ‘ (半角空格)
    設定ファイルに記述するときに使用

    从 dicrc 中选择的例子

    ; yomi
    node-format-yomi = %pS%f[7]
    unk-format-yomi = %M
    eos-format-yomi = n

    ; simple
    node-format-simple = %mt%F-[0,1,2,3]n
    eos-format-simple = EOSn

    ; csv
    node-format-csv = %m,%f[7],%f[8],%f[6],%F-[0,1,2,3],%f[4],%f[5]n
    unk-format-csv = %m,%m,%m,%f[6],%F-[0,1,2,3],,n
    eos-format-csv = EOS,,,,,,n

    ; ChaSen
    node-format-chasen = %mt%f[7]t%f[6]t%F-[0,1,2,3]t%f[4]t%f[5]n
    unk-format-chasen = %mt%mt%mt%F-[0,1,2,3]ttn
    eos-format-chasen = EOSn

    五、词性 ID 的定义

    posid.html

    概要

    MeCab 对于输出的特征(词性)可以对应到任意的数值 ID. 通常, 特征表现为字符串形式, 不是面向机器处理的,转换为数值ID后, 便于机器处理。

    一个特征对应于哪个 ID, 用户可以自由的定义。

    配置文件

    修改发布词典的目录中的 pos-id.def 文件.

    每行对应于一个映射规则,每个模式按如下格式书写.

    匹配模式  ID

    按这种形式书写后, 从文件头开始查找映射规则,第一个匹配的规则将被使用.

    匹配模式使用简单的正则表达式,

    • *: 匹配所有的字符串
    • (AB|CD|EF): 匹配 AB 或 CD 或 EF
    • AB: 只匹配字符串 AB

    pos-id 修改后, 需要重新编译生成词典.

    /usr/local/libexec/mecab/mecab-dict-index

    词性 ID 参照

    可以使用输出格式中的宏 %h 来引用词性的 id .

    % mecab -F"%mt%hn" -E"EOSn" 
    今日もしないとね。
    今日 67
    も 16
    し 31
    ない 25
    と 18
    ね 17

    EOS

    另外, 库函数中可以使用 mecab_node_t::posid 引用词性的 id.

    mecab_t *mecab;
    mecab_node_t *node;

    mecab = mecab_new2("");
    node = mecab_sparse_tonode(mecab, "今日もしないとね");
    for (; node; node = node->next) {
    fwrite (node->surface, sizeof(char), node->length, stdout);
    printf("%dn", node->posid)
    }

    pos-id.def 的例子

    简单的例子

    名詞 1
    動詞 2
    形容詞 3
    副詞 4
    助詞 5
    接続詞 6
    助動詞 7
    連体詞 8
    感動詞 9
    * 10

    稍微复杂的例子

    名詞 1
    (助詞|助動詞) 2
    (副詞|形容詞|連体詞) 3
    * 4

    更复杂的例子

    その他,間投,*,* 0
    フィラー,*,*,* 1
    感動詞,*,*,* 2
    記号,アルファベット,*,* 3
    記号,一般,*,* 4
    記号,括弧開,*,* 5
    記号,括弧閉,*,* 6
    記号,句点,*,* 7
    記号,空白,*,* 8
    記号,読点,*,* 9
    形容詞,自立,*,* 10
    形容詞,接尾,*,* 11
    形容詞,非自立,*,* 12
    助詞,格助詞,一般,* 13
    助詞,格助詞,引用,* 14
    助詞,格助詞,連語,* 15
    助詞,係助詞,*,* 16
    助詞,終助詞,*,* 17
    助詞,接続助詞,*,* 18
    助詞,特殊,*,* 19
    助詞,副詞化,*,* 20
    助詞,副助詞,*,* 21
    助詞,副助詞/並立助詞/終助詞,*,* 22
    助詞,並立助詞,*,* 23
    助詞,連体化,*,* 24
    助動詞,*,*,* 25
    接続詞,*,*,* 26
    接頭詞,形容詞接続,*,* 27
    接頭詞,数接続,*,* 28
    接頭詞,動詞接続,*,* 29
    接頭詞,名詞接続,*,* 30
    動詞,自立,*,* 31
    動詞,接尾,*,* 32
    動詞,非自立,*,* 33
    副詞,一般,*,* 34
    副詞,助詞類接続,*,* 35
    名詞,サ変接続,*,* 36
    名詞,ナイ形容詞語幹,*,* 37
    名詞,一般,*,* 38
    名詞,引用文字列,*,* 39
    名詞,形容動詞語幹,*,* 40
    名詞,固有名詞,一般,* 41
    名詞,固有名詞,人名,一般 42
    名詞,固有名詞,人名,姓 43
    名詞,固有名詞,人名,名 44
    名詞,固有名詞,組織,* 45
    名詞,固有名詞,地域,一般 46
    名詞,固有名詞,地域,国 47
    名詞,数,*,* 48
    名詞,接続詞的,*,* 49
    名詞,接尾,サ変接続,* 50
    名詞,接尾,一般,* 51
    名詞,接尾,形容動詞語幹,* 52
    名詞,接尾,助数詞,* 53
    名詞,接尾,助動詞語幹,* 54
    名詞,接尾,人名,* 55
    名詞,接尾,地域,* 56
    名詞,接尾,特殊,* 57
    名詞,接尾,副詞可能,* 58
    名詞,代名詞,一般,* 59
    名詞,代名詞,縮約,* 60
    名詞,動詞非自立的,*,* 61
    名詞,特殊,助動詞語幹,* 62
    名詞,非自立,一般,* 63
    名詞,非自立,形容動詞語幹,* 64
    名詞,非自立,助動詞語幹,* 65
    名詞,非自立,副詞可能,* 66
    名詞,副詞可能,*,* 67
    連体詞,*,*,* 68

    六、软性的逐词分隔输出

    soft.html

    概要

    MeCab 从0.90 开始带有软性的逐词分隔输出的功能. 软性的逐词分隔提供了输出全切分中所有词条的周边概率的功能. 在全文检索的索引中使用该功能,可以解决复合词切分歧义的问题。

    ソフトわかち書き 的详细说明请参考这篇 论文.

    全切分的输出

    MeCab 缺省只输出最优解. 指定 -a 选项将不再输出最优解, 而是输出全切分 .

    % mecab -a
    東京都庁
    東京 名詞,固有名詞,地域,一般,*,*,東京,トウキョウ,トーキョー
    東 名詞,固有名詞,一般,*,*,*,東,ヒガシ,ヒガシ
    東 名詞,固有名詞,地域,一般,*,*,東,ヒガシ,ヒガシ
    東 名詞,固有名詞,人名,名,*,*,東,ヒガシ,ヒガシ
    東 名詞,固有名詞,人名,姓,*,*,東,アズマ,アズマ
    東 名詞,一般,*,*,*,*,東,ヒガシ,ヒガシ
    京都 名詞,固有名詞,一般,*,*,*,京都,キョウト,キョート
    京都 名詞,固有名詞,地域,一般,*,*,京都,キョウト,キョート
    京 名詞,固有名詞,地域,一般,*,*,京,キョウ,キョー
    京 名詞,固有名詞,人名,名,*,*,京,ミヤコ,ミヤコ
    京 名詞,固有名詞,人名,姓,*,*,京,キョウ,キョー
    都庁 名詞,一般,*,*,*,*,都庁,トチョウ,トチョー
    都 名詞,接尾,地域,*,*,*,都,ト,ト
    都 名詞,固有名詞,地域,一般,*,*,都,ミヤコ,ミヤコ
    都 名詞,固有名詞,人名,姓,*,*,都,ミヤコ,ミヤコ
    都 名詞,固有名詞,人名,名,*,*,都,ミヤコ,ミヤコ
    都 名詞,一般,*,*,*,*,都,ト,ト
    庁 名詞,接尾,一般,*,*,*,庁,チョウ,チョー
    庁 名詞,固有名詞,地域,一般,*,*,庁,チョウ,チョー
    庁 名詞,一般,*,*,*,*,庁,チョウ,チョー
    EOS

    周边概率的计算和输出

    各词条的周边概率(即该词条在输入的句子中以多大的概率出现)的计算, -a 和 -l2 选项同时使用。 -l 选项指定构建 word-lattice 的信息的级别程度, -l2 表示使用 forwardbackward 算法计算周边概率。 -l 选项可以指定如下级别:

    • -l 0: 只输出最优解 (缺省, 高速)
    • -l 1: 输出 N-best 解 (中速)
    • -l 2: ソフトわかち書きが可能なレベル (低速)

    -l2 选项由于引入了浮点数计算, 比 -l0 要慢8倍.

    各词条的周边概率的输出, 可以使用 -F 选项指定特定的输出格式, 通常使用 %pP %pb 即可。 输出格式的指定方法请参考 这里.

    • %pP: 周边概率
    • %pb: 最优解标上 “*”, 其他为空
    % mecab -l2 -a -F"%m %H %pP %pbn" -E"EOSn"
    京都大学
    京都大学 名詞,固有名詞,組織,*,*,*,京都大学,キョウトダイガク,キョートダイガク 0.559944 *
    京都大 名詞,固有名詞,組織,*,*,*,京都大,キョウトダイ,キョートダイ 0.073824
    京都 名詞,固有名詞,一般,*,*,*,京都,キョウト,キョート 0.004990
    京都 名詞,固有名詞,地域,一般,*,*,京都,キョウト,キョート 0.360982
    京 名詞,固有名詞,地域,一般,*,*,京,キョウ,キョー 0.000161
    京 名詞,固有名詞,人名,名,*,*,京,ミヤコ,ミヤコ 0.000003
    京 名詞,固有名詞,人名,姓,*,*,京,キョウ,キョー 0.000096
    都 名詞,接尾,地域,*,*,*,都,ト,ト 0.000166
    都 名詞,固有名詞,地域,一般,*,*,都,ミヤコ,ミヤコ 0.000001
    都 名詞,固有名詞,人名,姓,*,*,都,ミヤコ,ミヤコ 0.000006
    都 名詞,固有名詞,人名,名,*,*,都,ミヤコ,ミヤコ 0.000072
    都 名詞,一般,*,*,*,*,都,ト,ト 0.000015
    大学 名詞,固有名詞,地域,一般,*,*,大学,ダイガク,ダイガク 0.004919
    大学 名詞,固有名詞,人名,名,*,*,大学,ダイガク,ダイガク 0.004441
    大学 名詞,一般,*,*,*,*,大学,ダイガク,ダイガク 0.350523
    大 名詞,接尾,一般,*,*,*,大,ダイ,ダイ 0.003603
    大 接頭詞,名詞接続,*,*,*,*,大,ダイ,ダイ 0.001123
    大 接頭詞,動詞接続,*,*,*,*,大,オオ,オー 0.000011
    大 名詞,固有名詞,地域,一般,*,*,大,オオ,オー 0.000171
    大 名詞,固有名詞,人名,名,*,*,大,マサル,マサル 0.000016
    大 名詞,一般,*,*,*,*,大,ダイ,ダイ 0.001424
    学 名詞,接尾,一般,*,*,*,学,ガク,ガク 0.067828
    学 名詞,固有名詞,地域,一般,*,*,学,ガク,ガク 0.001092
    学 名詞,固有名詞,人名,名,*,*,学,マナブ,マナブ 0.004203
    学 名詞,一般,*,*,*,*,学,ガク,ガク 0.007051
    EOS

    通过指定 -t 数値 选项, 可以修改概率的平滑程度。小的数值在平滑概率的时候, 短的词条概率值会变大。 使用大的数值时, 最优解的概率变大。 缺省值为 0.75.

    % mecab -l2 -a -F"%m %H %pP %pbn" -t0.1 -E"EOSn"
    京都大学
    京都大学 名詞,固有名詞,組織,*,*,*,京都大学,キョウトダイガク,キョートダイガク 0.023617 *
    京都大 名詞,固有名詞,組織,*,*,*,京都大,キョウトダイ,キョートダイ 0.052790
    京都 名詞,固有名詞,一般,*,*,*,京都,キョウト,キョート 0.113576
    京都 名詞,固有名詞,地域,一般,*,*,京都,キョウト,キョート 0.200919
    京 名詞,固有名詞,地域,一般,*,*,京,キョウ,キョー 0.206514
    京 名詞,固有名詞,人名,名,*,*,京,ミヤコ,ミヤコ 0.157030
    京 名詞,固有名詞,人名,姓,*,*,京,キョウ,キョー 0.245554
    都 名詞,接尾,地域,*,*,*,都,ト,ト 0.168921
    都 名詞,固有名詞,地域,一般,*,*,都,ミヤコ,ミヤコ 0.090030
    都 名詞,固有名詞,人名,姓,*,*,都,ミヤコ,ミヤコ 0.098721
    都 名詞,固有名詞,人名,名,*,*,都,ミヤコ,ミヤコ 0.120077
    都 名詞,一般,*,*,*,*,都,ト,ト 0.131348
    大学 名詞,固有名詞,地域,一般,*,*,大学,ダイガク,ダイガク 0.056029
    大学 名詞,固有名詞,人名,名,*,*,大学,ダイガク,ダイガク 0.063926
    大学 名詞,一般,*,*,*,*,大学,ダイガク,ダイガク 0.097919
    大 名詞,接尾,一般,*,*,*,大,ダイ,ダイ 0.150510
    大 接頭詞,名詞接続,*,*,*,*,大,ダイ,ダイ 0.151888
    大 接頭詞,動詞接続,*,*,*,*,大,オオ,オー 0.083163
    大 名詞,固有名詞,地域,一般,*,*,大,オオ,オー 0.101090
    大 名詞,固有名詞,人名,名,*,*,大,マサル,マサル 0.090363
    大 名詞,一般,*,*,*,*,大,ダイ,ダイ 0.128706
    学 名詞,接尾,一般,*,*,*,学,ガク,ガク 0.233658
    学 名詞,固有名詞,地域,一般,*,*,学,ガク,ガク 0.150100
    学 名詞,固有名詞,人名,名,*,*,学,マナブ,マナブ 0.174424
    学 名詞,一般,*,*,*,*,学,ガク,ガク 0.200327
    EOS

    库函数调用

    -a 选项被指定的时候, mecab_sparse_tonode 返回的 node 节点是包含全切分的链表, -l2 指定后, mecab_node_t::prob 将被赋值为周边概率.

    mecab_t *mecab;
    mecab_node_t *node;

    mecab = mecab_new2("-l2 -a");

    node = mecab_sparse_tonode(mecab, input);
    for (; node; node = node->next) {
    /* 最適解もしくは確率が 0.05 以上のとき出力 */
    if (node->isbest || node->prob >= 0.05) {
    fwrite (node->surface, sizeof(char), node->length, stdout);
    printf("t%st%fn", node->feature, node->prob);
    }
    }

    七、未登陆词处理的定义

    unk.html

    概要

    关于未登陆词处理(词典中不包含的词条的词法解析处理)的重定义

    配置文件

    发布词典的目录中包含 char.def 和 unk.def 文件, 修改这两个文件进行配置 .

    char.def

    未登陆词处理的规则. 请参看这里.

    unk.def

    未登陆词对应的词性表. 请参看这里.

    案例研究

    把连续的数字处理为一个词条

    • 词典 (*.csv 文件)中删除数字词条。 ipadic 的场合, 从Noun.number.csv 中删除罗马数字的词条。
    • 如下修改 char.def, 把连续的数字处理为一个未登陆词数。
      ..
      NUMERIC 1 1 0
      ..
    • 修改 unk.def , 把数字的 cost 值 改为小值。 如下, 把第4个字段的 cost 值设置为小于0的小值。
      NUMERIC,1204,1204,0,名詞,数,*,*,*,*,*
    • 编译生成词典.
      % /usr/local/libexec/mecab/mecab-dict-index

    ASCII 字符串, 仅在空格/制表符处切分 (和kakasi相同)

    • 从词典 (*.csv 文件)中把 包含ASCII 字符串的词条删除
    • 修改 char.def, 把除去空格, 符号的字符映射为同一类。同时检查其他的定义条目, 确保 0×0021..0x007E 这个范围中的字符不要映射到其他字符种类。
      ASCII       1 1 0

      0x0021..0x007E ASCII
    • 修改 unk.def, 把 ASCII 的 cost 值改小。 把第4个字段的 cost 值设置为小于0的小值。
      ASCII,1192,1192,0,名詞,サ変接続,*,*,*,*,*
    • 编译生成词典.
      % /usr/local/libexec/mecab/mecab-dict-index

    八、从原始词典/语料库做参数估计

    learn.html

    概要

    Mecab 可以从训练语料库中训练模型的参数(cost 值). MeCab 自身不依赖于某一个具体的词性体系的, 能够从特定的的词性体系,词典和语料库生成解析器. 参数估计使用 Conditinoal Random Fields (CRF) .

    处理流程

    下图按数据流排序.

    mecab2

    参数估计中包括以下子任务.

    以下按顺序逐个介绍.

    准备Seed 词典

    MeCab 的词典是 CSV 格式的. Seed 词典和用于发布的词典的格式基本上是相同的 .

    以下是词典的词条条目的例子 .

    進学校,0,0,0,名詞,一般,*,*,*,*,進学校,シンガクコウ,シンガクコー
    梅暦,0,0,0,名詞,一般,*,*,*,*,梅暦,ウメゴヨミ,ウメゴヨミ
    気圧,0,0,0,名詞,一般,*,*,*,*,気圧,キアツ,キアツ
    水中翼船,0,0,0,名詞,一般,*,*,*,*,水中翼船,スイチュウヨクセン,スイチューヨクセン

    前面4个字段是必须的,

    • 表层形(词条本身)
    • 左连接状态号
    • 右连接状态号
    • cost

    左连接状态号, 右连接状态号, cost 这三个字段在seed词典中无需使用, 因此全设为值0.

    第5个字段以后称为 “特征” . MeCab 为了提高通用性, 把”词性”, “活用”, “读音”, “发音” 等和词条相关的信息无区别的都处理成 “特征”. 用户可以指定多个特征, 但是特征的排列必须是固定的(例如, 第5个字段为词性, 第6个字段为词性细分类等). 通常, 特征按排列的顺序进行编号。

    特征内部使用数组的方式实现, 特征引用的时候分别称为第0个特征, 第一个特征, … 特征的编号和内部表现(词性, 读音等) 由用户自行管理。

    以上的例子为 ipadic 中的例子, 特征列表如下定义,

    • 词性
    • 词性细分类1
    • 词性细分类2
    • 词性细分类3
    • 活用型
    • 活用形
    • 基本形
    • 读音
    • 发音

    MeCab 没有对词语的活用进行处理. 对于活用的词条, 用户必须事先逐个展开添加.

    連れ出す,0,0,0,動詞,自立,*,*,五段・サ行,基本形,連れ出す,ツレダス,ツレダス
    連れ出さ,0,0,0,動詞,自立,*,*,五段・サ行,未然形,連れ出す,ツレダサ,ツレダサ
    連れ出そ,0,0,0,動詞,自立,*,*,五段・サ行,未然ウ接続,連れ出す,ツレダソ,ツレダソ
    連れ出し,0,0,0,動詞,自立,*,*,五段・サ行,連用形,連れ出す,ツレダシ,ツレダシ
    連れ出せ,0,0,0,動詞,自立,*,*,五段・サ行,仮定形,連れ出す,ツレダセ,ツレダセ
    連れ出せ,0,0,0,動詞,自立,*,*,五段・サ行,命令e,連れ出す,ツレダセ,ツレダセ
    連れ出しゃ,0,0,0,動詞,自立,*,*,五段・サ行,仮定縮約1,連れ出す,ツレダシャ,ツレダシャ

    准备配置文件

    dicrc

    该文件中设定词典的各种动作的,以下为最小配置 .

    cost-factor = 800
    bos-feature = BOS/EOS,*,*,*,*,*,*,*,*
    eval-size = 6
    unk-eval-size = 4
    config-charset = EUC-JP
    • cost-factor: 变换为cost 值的时候的比例因子, 设置为700~800 之间是没问题的.
    • bos-feature: 句首,句尾的特征, CSV 格式.
    • eval-size: 对于已登陆词, 特征组从左开始,有eval-size 个是匹配的时候, 就认为特征标注是正确的. 通常, 已登陆词的词性、活用等信息标注正确即可,”读音”、”发音” 等特征忽略. 上面的例子中, eval-size 为6, 表示参与性能评价的包括 IPA 词性体系的词性,词性细分类 1,2,3, 活用型, 活用形这6个特征。
    • unk-eval-size: 对于未登陆词, 特征组从左开始,有unk-eval-size 个是匹配的时候, 就认为特征标注是正确的.
    • config-charset: dicrc, char.def, unk.def, pos-id.def 这几个文件的编码.
    char.def

    定义未登陆词处理的文件. 通常日语的词法分析是基于字符的种类处理未登陆词, Mecab 中哪个文字属于哪个字符种类, 用户可以进行细致的指定; 对于每个字符类别, 需要采用哪种未登陆词的识别处理,也可以进行详细的定义。

    文件的最开始是类别名的定义, 以及每个类别所采取的未登陆词识别的动作的定义.

    类别名      动作 Timing(0/1)  Grouping(0/1)  长度(0,1, 2... n)
    • 类别名: 字符类别名.
      HIRANA, KATAKANA.. 等类别的定义. DEFAULT 和 SPACE 两个类别是必须的.
    • 动作 Timing :
      在该类别中, 何时启动未登陆词处理.
    • 0: 包含已登陆词的时候, 不启动未登陆词处理
    • 1: 总是启动未登陆词处理
    • Grouping: 未登陆词候选的生成方法.
      • 0: 不合并同类型的字符.
      • 1: 合并同类型的字符.
    • 长度: 未登陆词候选的生成方法.
      • 1: 长度不超过1的字符串设置为未登陆词.
      • 2: 长度不超过2的字符串设置为未登陆词.
      • n: 长度不超过n的字符串设置为未登陆词.

    可以同时设定 Grouping 和 “长度”.

    KANJI          0 0 2
    SYMBOL 1 1 0
    NUMERIC 1 1 0
    ALPHA 1 1 0
    HIRAGANA 0 1 2

    下面定义每个字符种类包含 UCS2 编码中的哪些码点(codepoint) .

    codepoint 缺省类型名 互换类型名1  互换类型名2 ..
    low_codepoint..high_codepoint  缺省类型名 互换类型名1  互换类型名2 ..

    0x0009 SPACE
    0x30A1..0x30FF KATAKANA
    0x30FC KATAKANA HIRAGANA # ー

    每个码点为 UCS2(Unicode) 中以 0x 开始的16进制数.

    第一个类别是该码点的缺省字符类别, 同时, 可以在随后列举可转换的类别. 上例中, 长音几号”ー”的缺省类别是片假名,平假名为可互换类别。做 Grouping 操作的时候互换类别可当作同一群组处理.

    以下为 char.def 的具体例子.

    DEFAULT        0 1 0  # DEFAULT is a mandatory category!
    SPACE 0 1 0
    KANJI 0 0 2
    SYMBOL 1 1 0
    NUMERIC 1 1 0
    ALPHA 1 1 0
    HIRAGANA 0 1 2
    KATAKANA 1 1 0
    KANJINUMERIC 1 1 0
    GREEK 1 1 0
    CYRILLIC 1 1 0

    # SPACE
    0x0020 SPACE # DO NOT REMOVE THIS LINE, 0x0020 is reserved for SPACE
    0x00D0 SPACE
    0x0009 SPACE
    0x000B SPACE
    0x000A SPACE

    # ASCII
    0x0021..0x002F SYMBOL
    0x0030..0x0039 NUMERIC

    ...

    # KATAKANA
    0x30A1..0x30FF KATAKANA
    0x31F0..0x31FF KATAKANA # Small KU .. Small RO
    0x30FC KATAKANA HIRAGANA # ー
    unk.def

    用于未登陆词的词典.

    DEFAULT,0,0,0,記号,一般,*,*,*,*,*
    SPACE,0,0,0,記号,空白,*,*,*,*,*
    KANJI,0,0,0,名詞,一般,*,*,*,*,*
    KANJI,0,0,0,名詞,サ変接続,*,*,*,*,*
    HIRAGANA,0,0,名詞,一般,*,*,*,*,*
    HIRAGANA,0,0,0,名詞,サ変接続,*,*,*,*,*
    HIRAGANA,0,0,0,名詞,固有名詞,地域,一般,*,*,*
    ...

    该词典的词条的表层部分为 char.def 中定义的各个字符类别, 文件中定义了各类别所能指定的特征列, 为一个字符类别定义多个特征列是没问题的, 使用语料训练之后, 将自动补上适当的 cost 值。

    rewrite.def

    定义从特征列到内部状态特征列的转换映射.

    CRF使用 unigram, 上文 bigram, 下文 bigram 3个信息进行统计计算.例如, 以”美しい川”(意思:美丽的河流)为例, 使用了unigram特征(特征列来自词典的定义), 上文特征(该词条左侧开始的特征), 下文特征(该词条右侧开始的特征), rewrite.def 定义了从词典的特征到内部使用特征的映射。

    mecab1

    具体来说,是要实现类似以下功能的映射函数

    • “来る”,”くる” 这两个词归一化为 “来る”后,进行统计算数.
    • 计算连接 cost 的时候, 该定义指明使用特征列中的哪些部分(例如, 只使用词性, 进行词汇化操作(lexicalize) 等等)

    rewrite.def 包括3个部分.

    • [unigram rewrite]: Unigram 内部状态的映射
    • [left rewrite]: 上文bigram 映射
    • [right rewrite]: 下文bigram 映射

    每个部分后包行的每行都是一个映射规则, 映射规则结构如下

    匹配模式  变换结果

    映射规则从头开始按顺序查找, 首个匹配的规则将被使用.

    匹配模式使用简单的正则表达式,

    • *: 匹配所有的字符串
    • (AB|CD|EF): 匹配 AB 或 CD 或 EF
    • AB: 只匹配字符串 AB

    变换结果中可以使用宏 $1 $2, $3.. 表示特征中的各要素(特征的要素以 CSV 格式表示)。

    [unigram rewrite]
    # 除去发音, 使用词性1,2,3,4,活用形,活用型,原形,读音
    *,*,*,*,*,*,*,* $1,$2,$3,$4,$5,$6,$7,$8
    # 没有读音的时候忽略
    *,*,*,*,*,*,* $1,$2,$3,$4,$5,$6,$7,*

    [left rewrite]
    (助詞|助動詞),*,*,*,*,*,(ない|無い) $1,$2,$3,$4,$5,$6,無い
    (助詞|助動詞),終助詞,*,*,*,*,(よ|ヨ) $1,$2,$3,$4,$5,$6,よ
    ...

    [right rewrite]
    (助詞|助動詞),*,*,*,*,*,(ない|無い) $1,$2,$3,$4,$5,$6,無い
    (助詞|助動詞),終助詞,*,*,*,*,(よ|ヨ) $1,$2,$3,$4,$5,$6,よ
    ..
    feature.def

    该文件中定义了从内部状态的素生列中抽取 CRF的素生列的模板

    每行对应一个模板, 以 UNIGRAM 开头的行表示用于 UNIGRAM 的模板, 以 BIGRAM 开头的行是用于连接的模板

    每个模板中可以使用如下的宏,

    • %F[n]: 展开unigram 的第n个特征
    • %F?[n] :展开unigram 的第n个特征, 如果未定义,则该模板不使用该特征
    • %t: 展开字符类别信息. 字符类别在 char.def 文件中定义.(%t 仅在 unigram 特征的时候有效)
    • %L[n]: 展开上文语境的第 n 个特征
    • %L?[n]: 展开上文语境的第 n 个特征, 如果未定义,则该模板不使用该特征
    • %R[n]: 展开下文语境的第 n 个特征
    • %R?[n]: 展开下文语境的第 n 个特征, 如果未定义,则该模板不使用该特征

    UNIGRAM W0:%F[6]
    UNIGRAM W1:%F[0]/%F[6]
    UNIGRAM W2:%F[0],%F?[1]/%F[6]
    UNIGRAM W3:%F[0],%F[1],%F?[2]/%F[6]
    UNIGRAM W4:%F[0],%F[1],%F[2],%F?[3]/%F[6]

    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

    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]
    ...

    准备训练语料

    用于训练的数据, 和 MeCab 的输出是相同格式的,

    太郎    名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー
    は 助詞,係助詞,*,*,*,*,は,ハ,ワ
    花子 名詞,固有名詞,人名,名,*,*,花子,ハナコ,ハナコ
    が 助詞,格助詞,一般,*,*,*, が,ガ,ガ
    好き 名詞,形容動詞語幹,*,*,*,*, 好き,スキ,スキ
    だ 助動詞,*,*,*, 特殊・ダ,基本形,だ,ダ,ダ
    . 記号,句点,*,*,*,*, . , . , .
    EOS
    焼酎 名詞,一般,*,*,*,*,焼酎,ショウチュウ,ショーチュー
    好き 名詞,形容動詞語幹,*,*,*,*,好き,スキ,スキ
    の 助詞,連体化,*,*,*,*, の,ノ,ノ
    親父 名詞,一般,*,*,*,*,親父,オヤジ,オヤジ
    . 記号,句点,*,*,*,*, . , . , .
    EOS
    ...

    Tab 键分隔的第一个部分为词条表层文字, 随后是CSV 格式的特征列, 句子结束标志为 只包行EOS的行.

    生成训练用的二进制词典

    当前的共走目录为 WORK, 在该目录中创建子目录 seed, final

    cd $WORK
    mkdir seed final

    seed 目录中复制先前描述过的如下文件内容,

    • seed 词典(CSV 格式文件集合)
    • 所有的配置文件 (char.def, unk.def, rewrite.def, feature.def)
    • 训练用的数据 (文件名: corpus)

    % cd $WORK/seed
    % ls
    Adj.csv Interjection.csv Noun.name.csv Noun.verbal.csv Symbol.csv rewrite.def
    Adnominal.csv Noun.adjv.csv Noun.number.csv Others.csv Verb.csv unk.def
    Adverb.csv Noun.adverbal.csv Noun.org.csv Postp-col.csv char.def
    Auxil.csv Noun.csv Noun.others.csv Postp.csv corpus
    Conjunction.csv Noun.demonst.csv Noun.place.csv Prefix.csv dicrc
    Filler.csv Noun.nai.csv Noun.proper.csv Suffix.csv feature.def

    运行以下命令, 生成学习用的二进制词典,

    % cd $WORK/seed
    % /usr/local/libexec/mecab/mecab-dict-index

    也可以通过 -d, -o 选项指定输入输出目录来运行该命令
    % /usr/local/libexec/mecab/mecab-dict-index -d $WORK/seed -o $WORK/seed
    • -d: 包含seed 词典和配置文件的目录(缺省为当前目录)
    • -o: 训练用二进制词典的输出目录(缺省为当前目录)

    CRF 参数训练

    % cd $WORK/seed
    % /usr/local/libexec/mecab/mecab-cost-train -c 1.0 corpus model

    可以使用 -d 参数指定使用的词典
    % /usr/local/libexec/mecab/mecab-cost-train -d $WORK/seed -c 1.0 $WORK/seed/corpus $WORK/seed/model
    • -d: 包含训练用二进制词典的目录(缺省为当前目录)
    • -c: CRF的超参数(hyper-parameter)
    • -f: 特征频率的阈值
    • -p NUM: 实行NUM个并行训练 (缺省为1)
    • corpus: 训练数据文件名
    • model: 输出CRF参数文件名

    mecab-cost-train 在生成二进制词典的时候要消耗大量内存, 如下,使用另一个进程来生成二进制词典,可以降低内存消耗

    % /usr/local/libexec/mecab/mecab-cost-train -y -c 1.0 corpus model
    % /usr/local/libexec/mecab/mecab-cost-train -b model.txt model

    超参数 C 用于控制训练过程中学习的强度,增大 C 值, 会加强模型和训练数据的拟合,有可能产生过学习。 减小 C 值, 可以避免过学习, 但有可能学习不充分. 合适的 C 值, 只能通过交叉验证等模型选择方法来发现, 缺省值设置为 1.0。

    -f 可以用来指定特征频率的阈值,例如, -f3 表示只使用训练数据中频率高于3 的特征。合适的 C 值需要通过交叉验证等模型选择方法来发现.

    训练过程中, 将输出如下信息,

    reading corpus ... adding virtual node: 名詞,固有名詞,地域,一般,*,*,東日,トウニチ,トウニチ
    adding virtual node: 副詞,助詞類接続,*,*,*,*,かなり,カナリ,カナリ

    Number of sentences: 32
    Number of features: 47547
    eta: 0.00010
    freq: 1
    C(sigma^2): 1.00000

    iter=0 err=1.00000 F=0.41186 target=1691.68869 diff=1.00000
    iter=1 err=1.00000 F=0.68727 target=1077.14848 diff=0.36327
    iter=2 err=0.87500 F=0.81904 target=621.20311 diff=0.42329
    iter=3 err=0.81250 F=0.86354 target=384.72432 diff=0.38068
    iter=4 err=0.68750 F=0.93685 target=233.72722 diff=0.39248
    ..
    • adding virtual node: 未知語処理を行なっても処理できなかった 形態素で, 学習の際便宜的に追加される形態素です.
    • iter: 训练次数
    • err: 句子级别的正确率
    • F: F値(正确率和召回率的调和平均)
    • target: 目标函数的值. 该值收敛的时候,训练结束
    • diff: 目标函数的相对差值, 该值小于 0.0001 的时候, 训练结束 す.

    生成用于发布的词典

    % cd $WORK/seed
    % /usr/local/libexec/mecab/mecab-dict-gen -o ../final -m model

    如下,可以使用 -d -o 选项指定词典
    % /usr/local/libexec/mecab/mecab-dict-gen -o $WORK/final -d $WORK/seed -m $WORK/seed/model
    • -d: 包含seed 词典和配置文件的目录(缺省为当前目录)
    • -o: 用于发布的词典的输出目录
    • -m: CRF 的参数文件

    用于发布的词典, 必须输出到和 seed 词典不同的目录,通常把包含发布词典的 final 目录打包之后用于发布 .

    生成用于解析器的词典

    % cd $WORK/final
    % /usr/local/libexec/mecab/mecab-dict-index

    如下,可以使用 -d -o 选项指定词典
    % /usr/local/libexec/mecab/mecab-dict-index -d $WORK/final -o $WORK/final
    • -d: 包含seed 词典和配置文件的目录(缺省为当前目录)
    • -o: 用于解析器的二进制词典的输出目录(缺省为当前目录)

    使用生成的词典进行实际的词法解析如下.

    % mecab -d $WORK/final
    焼酎好きの親父.
    焼酎 名詞,一般,*,*,*,*,焼酎,ショウチュウ,ショーチュー
    好き 名詞,形容動詞語幹,*,*,*,*,好き, スキ, スキ
    の 助詞,連体化,*,*,*,*,の,ノ,ノ
    親父 名詞,一般,*,*,*,*,親父, オヤジ, オヤジ
    . 記号,句点,*,*,*,*,.,.,.
    EOS

    评价

    准备测试数据, 测试数据格式和 MeCab 的输出格式相同 .

    首先, 使用 mecab-test-gen 从测试语料(test) 中生成用于测试的句子,

    % /usr/local/libexec/mecab/mecab-test-gen < test > test.sen

    用先前生成的词典解析 test.sen .

    % mecab -d $WORK/final test.sen > test.result

    运行评价脚本 mecab-system-eval , 第一个参数为系统运行的结果, 第二个参数为正确的结果

    % /usr/local/libexec/mecab/mecab-system-eval test.result test
    precision recall F
    LEVEL 0: 98.6887(647112/655710) 98.9793(647112/653785) 98.8338
    LEVEL 1: 98.2163(644014/655710) 98.5055(644014/653785) 98.3607
    LEVEL 2: 97.2230(637501/655710) 97.5093(637501/653785) 97.3659
    LEVEL 4: 96.8367(634968/655710) 97.1218(634968/653785) 96.9791

    使用 -l 选项可以指定基于哪些级别的特征进行性能评价.

    • -l 0: 只基于第0个特征进行评价
    • -l 4: 基于第0~4 个特征进行评价
    • -l -1: 基于所有的特征进行评价
    • -l “0 1 4″ 分别基于第0个, 第0~1个, 0~4个特征, 进行3次评价.
    • -l “0 1 -1″ 分别基于第0个, 第0~1个, 以及所有的特征, 进行3次评价.

    九、脚本语言绑定

    bindings.html

    概要

    Mecab 可以为以下脚本语言 (perlrubypythonJava) 提供调用接口. 这些语言的接口绑定都是通过 SWIG 自动生成的。 SWIG 支持的其他语言的接口也是可以生成的, 目前, 作者只为以上4种语言生成了调用接口。

    安装

    各种语言的绑定的安装方法参见 perl/README, ruby/README, python/README, java/README .

    生成 MeCab::Tagger 类的实例, 调用 parse(或者 parseToString) 方法, 解析结果以字符串形式获取。 Mecab::Tagger 的构造函数的参数,和基本的 mecab 命令运行的时候的参数时一样的, 都以字符串形式提供。

    perl
    use MeCab;
    $m = new MeCab::Tagger ("-Ochasen");
    print $m->parse ("今日もしないとね");
    ruby
    require 'MeCab'
    m = MeCab::Tagger.new ("-Ochasen")
    print m.parse ("今日もしないとね")
    python
    import sys
    import MeCab
    m = MeCab.Tagger ("-Ochasen")
    print m.parse ("今日もしないとね")
    Java
    import org.chasen.mecab.Tagger;
    import org.chasen.mecab.Node
    public static void main(String[] argv) {
    Tagger tagger = new Tagger ("-Ochasen");
    System.out.println (tagger.parse ("太郎は二郎にこの本を渡した."));
    }

    各词条详细信息的获取

    调用 MeCab::Tagger 类的 parseToNode 方法, 可以获取到句首这个特别词条 (为 Mecab::Node 类的实例).

    MeCab::Node 为双向链表, 可以通过 next, prev 访问下一个和前一个词条, 前后词条也都是 Mecab::Node 类型的实例。 逐次调用 next 就可以获得句子中所有的词条。

    Mecab::Node 对应的 C 语言的接口为 mecba_node_t, mecab_node_t 中包含的几乎所有成员变量都可以被访问, 但是, 通过 surface 成员返回词条的字符串时需要修改。

    以下为 perl 的例子. 该例中, 各个词条顺次访问,输出各词条的表层字符串, 词性,到该词条为止累计的 cost 值.

    use MeCab;
    my $m = new MeCab::Tagger ("");

    for (my $n = $m->parseToNode ("今日もしないとね"); $n ; $n = $n->{next}) {
    printf ("%st%st%dn",
    $n->{surface}, # 表层
    $n->{feature}, # 当前词性現在の品詞
    $n->{cost} # 到当前词累计的 cost 值
    );
    }

    错误处理

    如果在构造函数和解析途中发生错误,将抛出异常 RuntimeError, 关于异常的处理, 请参看各语言的参考手册。 以下以 python 为例说明,

    try:
    m = MeCab.Tagger ("-d .")
    print m.parse ("今日もしないとね")
    except RuntimeError, e:
    print "RuntimeError:", e;

    注意事项

    句首,句尾词条

    parseToNode 的返回值为”句首”这个特殊的词条节点, 为 Mecab::Node 类的实例, 另外请注意, “句尾”这一特殊节点也是存在的. 如果想忽视这些个节点, 如下使用 next 可以略过.

    my $n = $m->parseToNode ("今日もしないとね"); 
    $n = $n->{next}; # 丢弃 "句首"

    while ($n->{next}) { # 检查 next
    printf ("%sn", $n->{surface});
    $n = $n->{next}; # 下一节点
    }
    所有方法

    以下是 SWIG用的接口文件的一部分。使用C++ 语法描述, 用其他语言实现的时候,请相应的转换。 请参考下例添加各个方法.

    namespace MeCab {

    class Tagger {

    // 解析str, 以字符串返回结果. len 为 str 的长度(可省略)
    string parse(string str, int len);

    // 等同于 parse
    string parseToString(string str, int len);

    // 解析 str, 返回 MeCab::Node 类型的词条节点.
    // 该词条为句首节点, 使用 next 顺序访问所有的词条节点
    Node parseToNode(string str, int len);

    // parse 的 Nbest 版. N 指定 nbest 的个数
    // 要使用该功能, 启动时需要指定 -l 1 选项
    string parseNBest(int N, string str, int len);

    // 解析结果中, 按顺序取得n-best 中近似正确的结果的时候,需要调用该函数进行初始化.
    bool parseNBestInit(string str, int len);

    // parseNbestInit() 函数调用之后, 顺序调用该函数取得n-best 中近似正确的结果
    string next();

    // 和 next() 相同, 指示返回的是 MeCab::Node 类型
    Node nextNode();
    };

    #define MECAB_NOR_NODE 0
    #define MECAB_UNK_NODE 1
    #define MECAB_BOS_NODE 2
    #define MECAB_EOS_NODE 3

    struct Node {

    struct Node prev; // 前一个词条节点的指针
    struct Node next; // 后一个词条节点的指针

    struct Node enext; // 同一位置结束的词条的指针
    struct Node bnext; // 同一位置开始的词条的指针

    string surface; // 词条对应的字符串内容

    string feature; // CSV 格式的特征
    unsigned int length; // 词条的长度
    unsigned int rlength; // 词条的长度(包含开头的空白字符)
    unsigned int id; // 词条被赋予的唯一 ID
    unsigned short rcAttr; // 上文语境 id
    unsigned short lcAttr; // 下文语境 id
    unsigned short posid; // 词条 ID (未使用)
    unsigned char char_type; // 字符类别信息
    unsigned char stat; // 词条的种类, 可取以下值
    // #define MECAB_NOR_NODE 0
    // #define MECAB_UNK_NODE 1
    // #define MECAB_BOS_NODE 2
    // #define MECAB_EOS_NODE 3
    unsigned char isbest; // 最有解为 1, 其他为 0

    float alpha; // forward backward 的 forward log 概率
    float beta; // forward backward 的 backward log 概率
    float prob; // 周边概率
    // alpha, beta, prob 只有在 -l 2 指定的时候才有定义

    short wcost; // 词条生成 cost
    long cost; // 累计 cost
    };
    }

    样例程序

    请参考这些语言的样例程序 perl/test.pl, ruby/test.rb, python/test.py, java/test.java


    十、文档翻译

    Rick JIN <zhihuijin@gmail.com >

    日语水平有限, 翻译不准确之处请多谅解。



网友评论已有0条评论, 我也要评论

发表评论

*

* (保密)

Ctrl+Enter 快捷回复