プログラミングと機械学習のメモ
日付: カテゴリ: 自然言語処理
Pythonで文章の近さを計算しよう2の続き。今回はベクトル化された文章の類似度を測る。
通常、2次元ベクトルや3次元ベクトルの距離や近さを測るには、ユークリッド距離等が使われる。しかし、文章のベクトルの次元は単語数なので、多い文章になると次元が10000を超えることもしばしばある。また、文章のベクトルは0が非常に多い。(スパースなデータという。)このようなデータは、ユークリッド距離で計算するには向いていない。そこで、次元が多く、スパースなデータにとっておきのcos類似度の計算方法を紹介する。
式で書くと難しそうに思えるので、実際に計算して文章AとBのcos類似度を求めてみる。
文章 | 私 | リンゴ | 食べる | バナナ | 買う | 長さ |
---|---|---|---|---|---|---|
A. 私はリンゴを食べる。 | 1 | 1 | 1 | 0 | 0 | $\sqrt{3}$ |
B. 私はバナナを食べる。 | 1 | 0 | 1 | 1 | 0 | $\sqrt{3}$ |
文章A × 文章B | 1 | 0 | 1 | 0 | 0 |
cos類似度は、文章A×文章Bの和をとって、長さで割ることで算出できる。
\[ 文章Aと文章Bのcos類似度=\frac{1+0+1+0+0}{\sqrt{3} \times \sqrt{3}}=\frac{2}{3} \]これと同じように、3つの文章のbag-of-wordsからcos類似度を計算してみる。
文章1 | 文章2 | cos類似度 |
---|---|---|
私はリンゴを食べる。 | 私はバナナを食べる。 | 0.66 |
私はリンゴを食べる。 | 私はリンゴを買う。 | 0.66 |
私はバナナを食べる。 | 私はリンゴを買う。 | 0.33 |
bag-of-wordsでベクトル化した後のcos類似度は、共起している度合いを計算しているイメージである。共通している単語が多ければ、cos類似度が上がり、似ていると判断される。
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つは並び順を考慮しなければならないので、構文解析や、ディープラーニング等をして解決する。こちらもできれば書いていきたい。