はじめに
単語や文章の類似度を測るには様々な手法があります。その中でも、意味的な類似度ではなく、文字列としてどれだけ似ているかを測る編集距離を求めてみましょう。
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) # かんじへんかん
こちらで変換したひらがなで編集距離を測るのも良いかと思います。
おわりに
今回は編集距離でしたけど、意味的な類似度とかも色々あるので調べてみると面白いかもしれません。
まあ、でも日本語で自然言語処理とか本当にやりたくないですよね。