

お世話になっております。

日本語の文章を分割する際にMeCabを使っています。ここで非常によく似た2つの文を入力します。

  1. 私たちは寿司屋に行った
  2. 私達はすし屋に行った

結果

  1. 私 たち は 寿司 屋 に 行っ た
  2. 私 達 は すし 屋 に 行っ た

使用した辞書はIPADICです。この2つは声に出して日本語話者が聞いたところ同じ文ですが、単純に文字列単位での比較をすると違いが2箇所出てきます。

また

  3. 本の書き出し
  4. 本の書きだし

この場合は

  3. 本 の 書き出し
  4. 本 の 書き だし

分割の結果まで異なってしまいます。

目的は声に出して読み上げたところ、これらの2つのペアが同じ文章であると判断させたいのですが、よい方法はないでしょうか？

よろしくお願いします。

# 2017年8月17日改変

追記に書いていた部分が回答としても成り立つので、回答に移しました。


CC BY-SA 3.0
2017-08-12T23:37:12.447
37148
2017-09-20T08:44:59.260
2017-09-20T08:44:59.260
14631
question
日本語 自然言語処理 mecab
日本語のステミング（「よい」と「良い」が同じであるか判定する）方法


まだ完璧とは言えませんが、一定の進歩はありましたので、追記部分をこちらに移すとともに、再編集します。

UniDicにはIPADICにない素性があります。「語彙素・語形・書字形・発音形の階層構造を持ち，表記の揺れや語形の変異にかかわらず同一の見出しを与えることができます」とのことです。

辞書のCSVファイルを見てみると

[code]

    すし屋,5142,5142,9609,名詞,普通名詞,一般,*,*,*,スシヤ,寿司屋,すし屋,スシヤ,すし屋,スシヤ,和,*,*,*,*
    寿司屋,5142,5142,10432,名詞,普通名詞,一般,*,*,*,スシヤ,寿司屋,寿司屋,スシヤ,寿司屋,スシヤ,和,*,*,*,*
    鮨屋,5142,5142,8402,名詞,普通名詞,一般,*,*,*,スシヤ,寿司屋,鮨屋,スシヤ,鮨屋,スシヤ,和,*,*,*,*
    
[/code]

上手く寿司屋にまとめることができそうです。

ただしこれは活用を伴わない品詞（名詞など）に限ります。動詞などの場合は

[code]

    あるきつかれ,1272,1272,14547,動詞,一般,*,*,下一段-ラ行,未然形-一般,アルキツカレル,歩き疲れる,あるきつかれ,アルキツカレ,あるきつかれる,アルキツカレル,和,*,*,*,*
    歩き疲れ,1272,1272,12668,動詞,一般,*,*,下一段-ラ行,未然形-一般,アルキツカレル,歩き疲れる,歩き疲れ,アルキツカレ,歩き疲れる,アルキツカレル,和,*,*,*,*
    
[/code]

となりますので

文章1: 歩き疲れて眠った -> 歩き疲れ て 眠っ た  
文章2: あるきつかれて眠った -> あるきつかれ て 眠っ た

この2つの文が同じものであると判断したいのですが、語彙素に置き換えて出力した場合

文章1: 歩き疲れて眠った -> 歩き疲れる て 眠る た  
文章2: あるきつかれて眠った -> 歩き疲れる て 眠る た

と日本語としておかしなことになってしまいます。

これを以下の2つの方法で改善します。

# Step1. 文字列間の距離を使う方法

  1. 語彙素: #{elements[11]}をキー、「表層型と発音」のsetを値にしたmapを作成
  2. 辞書のCSVを1行読み、語彙素キーでmapを探索し、同じ語彙素に属する「表層型と発音」を列挙
  3. その行の発音と、列挙したsetの発音が一致していたら候補に追加
  4. 候補の中から、語彙素に一番近いものを素性に追加

寿司屋の例ですと「すし屋」「寿司屋」「鮨屋」は共通の「寿司屋」を語彙素に持ちます。これを

  * 寿司屋 -> [すし屋, スシヤ]
  * 寿司屋 -> [寿司屋, スシヤ]
  * 寿司屋 -> [鮨屋, スシヤ]

にまとめます。「すし屋」の行を処理する場合は、発音が同じ「スシヤ」の中から一番語彙素に類似している寿司屋を選びます。こうすると3つある「寿司屋」を1つにまとめることができます。

文字列が似ているかは安直にレーベンシュタイン距離を利用してみました。

動詞の場合も同様で、

「あるきつかれ」と「歩き疲れ」は共通の語彙素「歩き疲れる」を持ちます。「あるきつかれ」の行を処理する際に共通の語彙素「歩き疲れる」を持つ語のうち、発音が「アルキツカレ」のものを残し、語彙素と比較すると「歩き疲れ」を得ます。

単語分割の際には

  1. トークンに分割します
  2. 素性の中から今回追加した素性を選びます
  3. 連結します（複数の入力文が同じ文が同じ形になる）
  4. 再び単語分割します

例  
入力

  * 本の書き出しを読んだ
  * 本の書きだしを読んだ
  * 歩き疲れて休んだ
  * あるきつかれて休んだ
  * 今日は寿司屋に行く
  * 今日はすし屋に行く
  * 今日は鮨屋に行く

出力

  * [本, の, 書き出し, を, 読ん, だ]
  * [本, の, 書き出し, を, 読ん, だ]
  * [歩き疲れ, て, 休ん, だ]
  * [歩き疲れ, て, 休ん, だ]
  * [今日, は, 寿司, 屋, に, 行く]
  * [今日, は, 寿司, 屋, に, 行く]
  * [今日, は, 寿司, 屋, に, 行く]

# Step2. 簡易unigram言語モデルを作る

Step1だけではいくつか問題が残ります。

  1. 東京の語彙素が「トウキョウ」であるため、語彙素にそのまま置き換えると文章が不自然になる
  2. 「その」とか「する」の語彙素が「其の」とか「為る」なので不自然である

これを解決するために、WikipediaダンプをUniDicで分割し、単語の頻度を計算しました。

Wikipediaに一度も出現しない単語もあるため、Step1を適用したのちに、同じ語彙素と品詞と読みを持つ単語を、Wikipediaで一番多く出現した表現の（たとえば）「標準型」という素性を与えます。

一例としてトウキョウの場合は

[code]

    東京,名詞,固有名詞,地名,一般,トウキョウ  306123
    とうきょう,名詞,固有名詞,地名,一般,トウキョウ  3467
    トウキョウ,名詞,固有名詞,地名,一般,トウキョウ  356
    トーキョー,名詞,固有名詞,地名,一般,トウキョウ  758
    ＴＯＫＹＯ,名詞,固有名詞,地名,一般,トウキョウ  6
    Ｔｏｋｙｏ,名詞,固有名詞,地名,一般,トウキョウ  2
    とーきょー,名詞,固有名詞,地名,一般,トウキョウ  3
    
[/code]

となりましたので「東京」を標準型として採用します。

この方法も完璧ではなく、いくつか問題点があります。例えば「蛇」が

[code]

    蛇,名詞,普通名詞,一般,*,蛇  3854
    ジャ,名詞,普通名詞,一般,*,蛇  4091
    へび,名詞,普通名詞,一般,*,蛇  407
    
[/code]

となぜか「ジャ」が一番多いため、これで置き換えると

  * 私は蛇が苦手です -> 私はジャが苦手です

となるなど、まだまだ課題を残しています。


CC BY-SA 3.0
2017-08-18T22:23:09.163
37323
2017-08-18T22:23:09.163
14631
37148
answer