Phonetic Algorithms
あまり使う機会がないかもしれませんが、個人的に面白いと思ったライブラリを紹介したいと思います.説明に多々間違いがあるかもしれませんのでご指摘いただけると幸いです.
今回紹介するのは Fuzzy というライブラリです.Fuzzyは文字列(例えばsing)を特定のルールに従って変換する以下のアルゴリズムが実装してあります.
- Soundex
- NYSIIS
- Double Metaphone
それぞれの説明はこちらをご覧いただくか、wikiなどで確認をお願いします.
なぜこのような変換を行うかですが、非常に大さっぱに言えば字面からどんな音声になるのかを_近似的_に知りたいという動機があるようです(文献によっては名前の比較に使うとかいてあるものもありました).英語に限った話ではないと思いますが、字面と発音には結構な乖離があります. 字面が同じでも発音が微妙に違うなんてこともありますし....
そのため、上記のようなアルゴリズムは字面(文字列)を特定のルールに従って、文字列と発音の乖離なんかを考慮しながら音声を表す記号列(この記号列はアルゴリズムによって異なります)に変換してあげましょうというものです.ここで注意していただきたいのは変換後の記号列は発音記号ではなく、あくまで発音(音声)っぽいものを表す擬似的な文字列であるということです.
もちろんこの変換を機会学習で行うという研究も存在します.
FuzzyはこのようなアルゴリズムをC拡張モジュールの形で提供し、高速に動作するという点が売りらしいです.ただし、使用できるのは2系のみで開発も止まっているようです.
インストール
インストールはpipで行うことができます. ちなみに私はAnacondaの2系最新版を使用しています.
$ pip install Fuzzy
これでインストールは完了です!
使ってみる
package indexに書いてるサンプルを動かしてみましょう.
import fuzzy
dmeta = fuzzy.DMetaphone()
print dmeta('fuzzy')
Double Metaphoneを使ってみました. Double Metaphoneは['FS', None]
こんな出力をすると思います.変換後にできる記号列が2パターンになる可能性がある場合はNoneにも記号列が入ってきます.Double Metaphoneの特徴として_先頭以外の母音を除外している_ことが挙げられます.試しに日本語を入れるとなんだこれ状態になります.
print dmeta('suzuki') # ['SSK', 'STSK']
print dmeta('tarou') # ['TR', None]
アルゴリズムが対応できる言語も限られています(自分は英語しか使ったことがありませんすみません).
文字列の比較
Fuzzyが使えるようになったところで文字列同士の距離を測ってみます.ここでの_距離_は発音した時にどのくらい似ているのかと捉えることもできます.ただしあくまで擬似的なものですので距離が近いといっても、雰囲気が似ている程度に考えたほうが良いかもしれません.距離の解釈がどうなるのかは使用目的で変わると思いますので参考程度でお願いします.
距離の計算
文字列同士の距離計算にも多くの手法が存在しますが、Fuzzyの説明によるとPython-Levenshteinがおすすめと書いてあるので使ってみます. こちらも実装はCベースになっているので高速だよ!とのことです. こちらもpipでインストールできます.
pip install Python-Levenshtein
Python-Levenshteinのインストールもこれで終了です. 試しにpythonの英語版wikiの文を適当に使って"Python"と各単語との距離を測ってみることにします.使ったのは以下の文です.
CPython, the reference implementation of Python, is free and open-source software and has a community-based development model, as do nearly all of its alternative implementations. CPython is managed by the non-profit Python Software Foundation.
# -*- coding: utf-8 -*-
import fuzzy
from Levenshtein import distance
dmeta = fuzzy.DMetaphone()
f = open('python_wiki.txt')
txt = f.read()
words = txt.rstrip("\n").split(" ")
words = [w.rstrip(",") for w in words]
words = set(words)
d = {}
for w in words:
d[w] = dmeta(w)[0]
# Python という文字列との距離を測る
# まず"Python"をDouble Metaphoneを使って変換する
p = dmeta("Python")[0]
for k, v in d.items():
# distanceに距離を測りたい文字列を渡す
print "Python : ", k, distance(p, v)
出力
$ python distance.py
Python : and 3
Python : the 2
Python : all 3
Python : managed 4
Python : community-based 3
Python : is 3
Python : as 3
Python : alternative 4
Python : its 3
Python : reference 3
Python : CPython 1
Python : implementation 4
Python : non-profit 4
Python : has 3
Python : development 4
Python : do 3
Python : free 3
Python : nearly 3
Python : by 2
Python : Software 4
Python : a 3
Python : Foundation. 4
Python : open-source 3
Python : of 3
Python : Python 0
Python : model 3
Python : implementations. 4
Python : software 4
右端の数字がレーベンシュタイン距離です.PythonとPythonの距離は全く同じ文字列なので0になっていますね.
今回はDouble Metaphoneしか扱っていませんが、他のアルゴリズムも機会があれば試してみようと思います.
以上Fuzzyの紹介でした.