はじめに

単語や文章の類似度を測るには様々な手法があります。その中でも、意味的な類似度ではなく、文字列としてどれだけ似ているかを測る編集距離を求めてみましょう。

Pythonで。

編集距離とは

文字列に対して、

  • 挿入(1文字追加)
  • 削除(1文字消去)
  • 置換(1文字置き換え)

のどれかを行う編集処理に基づいて文字列同士が似ている、似ていないという距離を測るものとなっています。

有名なものとしてレーベンシュタイン距離ジャロ・ウィンクラー距離の2つがあります。

この2つは解説し始めると長いのでこちらを参考にしてください。図解されていてわかりやすい気がします。

Pythonで編集距離

ライブラリのインストール

Pythonでこのレーベンシュタイン距離とジャロ・ウィンクラー距離を測るにはpython-Levenshteinというライブラリが使えます。ドキュメントはこちらです。

こちらpipでインストールできるのでpip install python-Levenshteinで出来ます。ちなみに、こちら中身はCで書かれています。

使用する際はimport Levenshteinで使えるようになります。

レーベンシュタイン距離

使い方としてはLevenshtein.distance(string1, string2)です。

アルファベットはもちろん、日本語も出来ます。

例えばLevenshtein.distance('abcdfeg', 'abcdefg')とすれば2文字間違えてるため2と出力され、Levenshtein.distance('あいうえお', 'あいうえお')とすれば全く同じ文字列のため0とされます。

しかし、レーベンシュタイン距離は編集回数だけを見ていくので、文字列が長いと出力が大きくなってしまいがちです。そこで入力の長い方の文字列の文字数で割ることで[0, 1]に正規化することが出来ます。次に説明するジャロ・ウィンクラー距離と揃えたければ、正規化した値を1から引くことで1が一致、0が不一致で揃います。

ジャロ・ウィンクラー距離

使い方としてはLevenshtein.jaro_winkler(string1, string2[, prefix_weight])です。

例えばLevenshtein.jaro_winkler('abcdfeg', 'abcdefg')とすれば0.9714285714285714と出力され、Levenshtein.jaro_winkler('あいうえお', 'あいうえお')とすれば1.0とされます。

こちらは、アルゴリズムを見ればわかりますが、初めから[0, 1]に正規化された出力です。値は1が一致、0が不一致です。

日本語での前処理

日本語には漢字という面倒なやつがいますね。もちろん漢字のまま距離を測るのも1つの手ですが、「読み方が近い」といった評価を行うには漢字をひらがな化しないといけません。

Pythonにはpykakasiというライブラリがあり、こちらを使用することで漢字から仮名へ変換できます。インストールはpip install pykakasiです。

やり方はこちらです。

from pykakasi import kakasi

# 設定
kakasi = kakasi()
kakasi.setMode('J', 'H')
conv = kakasi.getConverter()

# 変換
string = '漢字へんかん'
kana = conv.do(string)  # かんじへんかん

こちらで変換したひらがなで編集距離を測るのも良いかと思います。

おわりに

今回は編集距離でしたけど、意味的な類似度とかも色々あるので調べてみると面白いかもしれません。

まあ、でも日本語で自然言語処理とか本当にやりたくないですよね。