Shingoの数学ノート

プログラミングと機械学習のメモ

Pythonで文章の近さを計算しよう3(cos類似度)

Pythonで文章の近さを計算しよう2の続き。今回はベクトル化された文章の類似度を測る。

文章の類似度を計算する

通常、2次元ベクトルや3次元ベクトルの距離や近さを測るには、ユークリッド距離等が使われる。しかし、文章のベクトルの次元は単語数なので、多い文章になると次元が10000を超えることもしばしばある。また、文章のベクトルは0が非常に多い。(スパースなデータという。)このようなデータは、ユークリッド距離で計算するには向いていない。そこで、次元が多く、スパースなデータにとっておきのcos類似度の計算方法を紹介する。

cos類似度

nnを次元数とすると、u=(u1,,un)u=(u_1,\cdots,u_n)v=(v1,,vn)v=(v_1,\cdots,v_n)のcos類似度は次で表される。

cossim(u,v)=uvuv=u1v1++unvnu12++un2v12++vn2cossim(u,v)=\frac{u \cdot v}{|u||v|}=\frac{u_1v_1+\cdots+u_nv_n}{\sqrt{u_1^2+ \cdots + u_n^2 }\sqrt{v_1^2+ \cdots + v_n^2 }}

式で書くと難しそうに思えるので、実際に計算して文章AとBのcos類似度を求めてみる。

文章

リンゴ

食べる

バナナ

買う

長さ

A. 私はリンゴを食べる。

1

1

1

0

0

3\sqrt{3}

B. 私はバナナを食べる。

1

0

1

1

0

3\sqrt{3}

文章A × 文章B

1

0

1

0

0

cos類似度は、文章A×文章Bの和をとって、長さで割ることで算出できる。

文章Aと文章Bcos類似度=1+0+1+0+03×3=23文章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類似度が上がり、似ていると判断される。

Pythonでの実装

bag-of-wordsでベクトル化さえできていれば、cos類似度の計算は簡単だ。vector_bowは前回の記事で作成したものを使用する。

python
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)))

実行結果

text
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...