Skip to contents

制約付き解析(部分解析)について

MeCabのやや発展的な使い方のひとつとして、制約付き解析があります。

入力文の一部の形態素情報が既知である、あるいは境界がわかっているときに、 それを満たすように解析する機能です。

たとえば、「にわにはにわにわとりがいる。」という文に対して、 「はにわ」の部分が名詞であるとか、「にわとり」の部分が一つの形態素 であるというように指定した上で解析することができます。このとき、 制約に反する4文字目の「は」が単独で形態素となったり、「にわとり」が「にわ」と「とり」 に分割されるような解析候補は排除されます。

制約付き解析を利用するには、解析させたい文を「文断片」や「形態素断片」に分けながら与えます。

それぞれの文断片や形態素断片は、改行(\n)によって分けられます。文断片については通常と同じように形態素解析がおこなわれますが、文断片や形態素断片の間をまたぐような解析結果は抑制されます。また、形態素断片は表層形\t素性パターンのようなかたちで与えることができます。形態素断片についてはそれ以上分割されず、与えられた断片がそのままのかたちで出力されます。

IPA辞書による素の解析の場合

一例として、ここではIPA辞書を使って、「月ノ美兎」という語彙を含む文を解析してみます。posDebugRcppは、与えられた文字列について、MeCabの-aオプションに相当する解析結果(解析結果になりえるすべての形態素の組み合わせ)を出力する関数です。ここでの最適解(is_best == "01")である結果について確認すると、「月ノ美兎」という語彙は次のように複数の形態素に分割されてしまっていることがわかります。

gibasa::posDebugRcpp("月ノ美兎は箱の中") |>
  dplyr::filter(is_best == "01")
#>    doc_id pos_id surface                                 feature stat lcAttr
#> 1       1      0                         BOS/EOS,*,*,*,*,*,*,*,*   02      0
#> 2       1     38      月          名詞,一般,*,*,*,*,月,ツキ,ツキ   00   1285
#> 3       1      4      ノ              記号,一般,*,*,*,*,ノ,ノ,ノ   00      5
#> 4       1     44      美  名詞,固有名詞,人名,名,*,*,美,ヨシ,ヨシ   00   1291
#> 5       1     38      兎      名詞,一般,*,*,*,*,兎,ウサギ,ウサギ   00   1285
#> 6       1     16      は            助詞,係助詞,*,*,*,*,は,ハ,ワ   00    261
#> 7       1     38      箱          名詞,一般,*,*,*,*,箱,ハコ,ハコ   00   1285
#> 8       1     24      の            助詞,連体化,*,*,*,*,の,ノ,ノ   00    368
#> 9       1     66      中 名詞,非自立,副詞可能,*,*,*,中,ナカ,ナカ   00   1313
#> 10      1      0                         BOS/EOS,*,*,*,*,*,*,*,*   03      0
#>    rcAttr     alpha      beta is_best prob wcost  cost
#> 1       0      0.00 -22144.50      01    0     0     0
#> 2    1285  -6190.50 -15954.00      01    1  8537  8254
#> 3       5  -8874.75 -13269.75      01    1  4929 11833
#> 4    1291 -13974.00  -8170.50      01    1  7885 18632
#> 5    1285 -18080.25  -4064.25      01    1  5290 24107
#> 6     261 -18095.25  -4049.25      01    1  3865 24127
#> 7    1285 -22729.50    585.00      01    1  6142 30306
#> 8     368 -23010.00    865.50      01    1  4816 30680
#> 9    1313 -24007.50   1863.00      01    1  6528 32010
#> 10      0 -22144.50      0.00      01    1     0 29526

制約付き解析(部分解析)の場合

そこで、「月ノ美兎」という語彙を形態素断片として与えてみます。なお、posDebugRcppでは、partial=TRUEにすると-aに相当するオプションは無効になり、最適解のみが出力されます。

gibasa::posDebugRcpp("月ノ美兎\t名詞,固有名詞,人名,*,*,*\nは箱の中", partial = TRUE)
#>   doc_id pos_id  surface                                 feature stat lcAttr
#> 1      1      0                          BOS/EOS,*,*,*,*,*,*,*,*   02      0
#> 2      1     42 月ノ美兎           名詞,固有名詞,人名,一般,*,*,*   01   1289
#> 3      1     16       は            助詞,係助詞,*,*,*,*,は,ハ,ワ   00    261
#> 4      1     38       箱          名詞,一般,*,*,*,*,箱,ハコ,ハコ   00   1285
#> 5      1     24       の            助詞,連体化,*,*,*,*,の,ノ,ノ   00    368
#> 6      1     66       中 名詞,非自立,副詞可能,*,*,*,中,ナカ,ナカ   00   1313
#> 7      1      0                          BOS/EOS,*,*,*,*,*,*,*,*   03      0
#>   rcAttr     alpha      beta is_best prob wcost  cost
#> 1      0      0.00 -16275.00      01    0     0     0
#> 2   1289 -12134.25  -4140.75      01    1 17340 16179
#> 3    261 -12225.75  -4049.25      01    1  3865 16301
#> 4   1285 -16860.00    585.00      01    1  6142 22480
#> 5    368 -17140.50    865.50      01    1  4816 22854
#> 6   1313 -18138.00   1863.00      01    1  6528 24184
#> 7      0 -16275.00      0.00      01    1     0 21700

これでひとまず期待どおりに解析することができました。こうした使い方のほかに、形態素断片の素性パターンにワイルドカード(*)を使うと、その単語を切り出しながら品詞については適当なものを付与させることができます。以下では「月ノ美兎」については常に単語として切り出しながら、品詞は適当なものを付与させています。

gibasa::posDebugRcpp("月ノ美兎\t*\nは箱の中", partial = TRUE)
#>   doc_id pos_id  surface                                 feature stat lcAttr
#> 1      1      0                          BOS/EOS,*,*,*,*,*,*,*,*   02      0
#> 2      1     38 月ノ美兎                     名詞,一般,*,*,*,*,*   01   1285
#> 3      1     16       は            助詞,係助詞,*,*,*,*,は,ハ,ワ   00    261
#> 4      1     38       箱          名詞,一般,*,*,*,*,箱,ハコ,ハコ   00   1285
#> 5      1     24       の            助詞,連体化,*,*,*,*,の,ノ,ノ   00    368
#> 6      1     66       中 名詞,非自立,副詞可能,*,*,*,中,ナカ,ナカ   00   1313
#> 7      1      0                          BOS/EOS,*,*,*,*,*,*,*,*   03      0
#>   rcAttr     alpha      beta is_best prob wcost  cost
#> 1      0      0.00 -12421.50      01    0     0     0
#> 2   1285  -8357.25  -4064.25      01    1 11426 11143
#> 3    261  -8372.25  -4049.25      01    1  3865 11163
#> 4   1285 -13006.50    585.00      01    1  6142 17342
#> 5    368 -13287.00    865.50      01    1  4816 17716
#> 6   1313 -14284.50   1863.00      01    1  6528 19046
#> 7      0 -12421.50      0.00      01    1     0 16562

具体的な使用例

partial引数はtokenizeにも実装されています。実用的には、たとえば次のように使えるかもしれません。

sentences <- c(
  "証券コードは4桁の銘柄識別コードです。",
  "たとえば、7777です。あるいは7777 JPや7777.Tというのもあります。",
  "また「7777JP」のような全角文字を使う表し方もあるかもしれません。"
)

sentences |>
  stringi::stri_replace_all_regex("(?<codes>[0-9\uFF10-\uFF19]{4}((\\s|\\.)+[a-zA-Z]{1,2}|[\uFF21-\uFF3A]{2}))", "\n${codes}\t*\n") |>
  gibasa::tokenize(partial = TRUE, mode = "wakati")
#> $`1`
#>  [1] "証券"   "コード" "は"     "4"     "桁"     "の"     "銘柄"   "識別"  
#>  [9] "コード" "です"   "。"    
#> 
#> $`2`
#>  [1] "たとえば" "、"       "7777"     "です"     "。"       "あるいは"
#>  [7] "7777 JP"  "や"       "7777.T"   "という"   "の"       "も"      
#> [13] "あり"     "ます"     "。"      
#> 
#> $`3`
#>  [1] "また"         "「"           "7777JP" "」"           "の"          
#>  [6] "よう"         "な"           "全角"         "文字"         "を"          
#> [11] "使う"         "表し"         "方"           "も"           "ある"        
#> [16] "かも"         "しれ"         "ませ"         "ん"           "。"

なお、この機能を利用時に、文断片や形態素断片の先頭や末尾に半角スペースが含まれていると、MeCab側でエラーが発生し、解析に失敗する場合があるので注意してください。