Pythonで文章の近さを計算しよう3(cos類似度)
Pythonで文章の近さを計算しよう2の続き。今回はベクトル化された文章の類似度を測る。
文章の類似度を計算する
通常、2次元ベクトルや3次元ベクトルの距離や近さを測るには、ユークリッド距離等が使われる。しかし、文章のベクトルの次元は単語数なので、多い文章になると次元が10000を超えることもしばしばある。また、文章のベクトルは0が非常に多い。(スパースなデータという。)このようなデータは、ユークリッド距離で計算するには向いていない。そこで、次元が多く、スパースなデータにとっておきのcos類似度の計算方法を紹介する。
cos類似度
を次元数とすると、、のcos類似度は次で表される。
式で書くと難しそうに思えるので、実際に計算して文章AとBのcos類似度を求めてみる。
文章
私
リンゴ
食べる
バナナ
買う
長さ
A. 私はリンゴを食べる。
1
1
1
0
0
B. 私はバナナを食べる。
1
0
1
1
0
文章A × 文章B
1
0
1
0
0
cos類似度は、文章A×文章Bの和をとって、長さで割ることで算出できる。
これと同じように、3つの文章のbag-of-wordsからcos類似度を計算してみる。
文章1
文章2
cos類似度
私はリンゴを食べる。
私はバナナを食べる。
0.66
私はリンゴを食べる。
私はリンゴを買う。
0.66
私はバナナを食べる。
私はリンゴを買う。
0.33
bag-of-wordsでベクトル化した後のcos類似度は、共起している度合いを計算しているイメージである。共通している単語が多ければ、cos類似度が上がり、似ていると判断される。
Pythonでの実装
bag-of-wordsでベクトル化さえできていれば、cos類似度の計算は簡単だ。vector_bowは前回の記事で作成したものを使用する。
import numpy as np
def cos_sim(v1,v2):
return
np.dot(v1,v2)/
np.linalg.norm(v1)/
np.linalg.norm(v2) v1,v2,v3=vector_bow
print("v1={},v2={},v3={}".format(v1,v2,v3))
print("v1とv2のcos類似度:{:.03f}".format(cos_sim(v1,v2)))
print("v1とv3のcos類似度:{:.03f}".format(cos_sim(v1,v3)))
print("v2とv3のcos類似度:{:.03f}".format(cos_sim(v2,v3)))
実行結果
v1=[1. 1. 1. 0. 0.],v2=[0. 1. 1. 1. 0.],v3=[1. 1. 0. 0. 1.] v1とv2のcos類似度:0.667 v1とv3のcos類似度:0.667 v2とv3のcos類似度:0.333
まとめと今後の課題
いったんテキストから類似度の算出までを記載した。シンプルではあるが、そこそこ直感と合っていて、理解もしやすい。
類似度を算出できれば、次のことができる。
- 単語が似た文章の検索
- 文章のクラスタリング
ここら辺はできると思うので、ぜひ試していただきたい。
しかし、bag-of-wordsを使用したcos類似度は以下の欠点も存在する。
-
次元数が多いため、計算量が膨大。
-
表記揺れで、同じ意味の単語でも別の単語として区別する。(「楽しい」、「たのしい」等)
-
別の単語を同じ単語として認識する。(「うまい(美味い、上手い)等」)
-
文章の並び順を考慮していない。
* 「〜ない」等の否定語の考慮(否定しているのに類似度が高いと出てしまう。)
上3つはSVD、LDAなどの次元削減によって解決できる。筆者の余裕があれば今後ブログを書いていく予定。
下2つは並び順を考慮しなければならないので、構文解析や、ディープラーニング等をして解決する。こちらもできれば書いていきたい。
Comments
Loading comments...