2019年9月19日木曜日

Ruby でジャロ・ウィンクラー距離を求めてみる

概要

ジャロ・ウィンクラー距離は異なる 2 つの単語の類似度を計算することができる手法です
Ruby に簡単にライブラリがあるので使ってみました

環境

  • macOS 10.14.6
  • Ruby 2.6.2p47
    • jaro_winkler 1.5.3

サンプルコード

  • bundle init
  • vim Gemfile
gem "jaro_winkler"
  • bundle install --path vendor
  • vim app.rb
# coding: utf-8
require 'jaro_winkler'

p "ignore_case"
p JaroWinkler.distance "hakwsnowlog", "HAWKSNOWLOG"
p JaroWinkler.distance "hakwsnowlog", "HAWKSNOWLOG", :ignore_case => true
p "weight"
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog"
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog", :weight => 0.15
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog", :weight => 0.25
p "adj_table"
p JaroWinkler.distance "HAWKSNOWLOG", "HAWKSN0WL0G", :adj_table => false
p JaroWinkler.distance "HAWKSNOWLOG", "HAWKSN0WL0G", :adj_table => true
p "multi-bytes"
p JaroWinkler.distance "今日はいい天気です", "今日は晴れています"
  • bundle exec ruby app.rb
"ignore_case" 0.0 0.9757575757575758 "weight" 0.9535353535353536 0.9593434343434344 0.970959595959596 "adj_table" 0.9272727272727274 0.949090909090909 "multi-bytes" 0.7925925925925926

少し解説

数字は 0 から 1 の間で計算されます
1 に近ければ近いほど類似度は高いということになります

普通に計算する場合は JaroWinkler.distance を使えば OK です
オプションがいくつかあるので紹介します

まず ignore_case ですがこれは比較するの大文字小文字を無視して比較します
サンプルにある大文字 (HAWKSNOWLOG) と小文字 (hawksnowlog) を比較したときに :ignore_case => true を指定しないと結果が 0 になっているのがわかると思います

次に weight ですがこれを付与すると結果が上方修正されます
デフォルトが 0.1 で最大 0.25 まで設定できます
weight と同時に使えるオプションで threshold があります
これは指定した threshold を超えた場合にだけ weight の値を適用することができるというオプションになります

最後に adj_table ですがこれは表記ゆれを解消するための機能です
例えば数字の「0」と英文字の「O」を同じ文字としてみなす場合には :adj_table => true にします
デフォルトでは false になっています
サンプルの結果を見ると表記ゆれがある場合には true に設定したほうが類似度が高くなるのがわかると思います
また adj_table は現状だとカスタムできないようです

マルチバイト文字にも対応しているので日本語の比較も可能です

最後に

ジャロ・ウィンクラー距離を Ruby で計算してみました
基本はデフォルトで使うのが良いかなと思います
基本は単語同士の比較に使うのが良いかなと思います
短いのであれば文章にも適用できると思います

コサイン類似度などを使っても算出できますが複雑な計算が必要なのでそういった意味ではジャロ・ウィンクラー距離は簡単に計算できるので良いのかなと思います

0 件のコメント:

コメントを投稿