03.4.4 高校生向け
コサイン類似度(高校生向け)
こんな場面を想像してみよう #
音楽アプリで、A さん・B さん・C さんの 1 か月の再生回数を「ロック・ポップ・ジャズ」の順に並べました。
| ロック | ポップ | ジャズ | |
|---|---|---|---|
| A さん | 10 | 2 | 0 |
| B さん | 100 | 20 | 0 |
| C さん | 0 | 0 | 30 |
A さんと好みが似ているのは、B さんと C さんのどちらでしょうか(10 倍聴く人か、ジャズだけの人か)。B さんは A さんの 10 倍聴いていますが、ロックとポップの比率は同じ「5 : 1」。C さんはジャズしか聴きません。直感的には A さんと B さん(比率 5 : 1 が同じ 2 人)が似ているはずです。
ところが 2 点間の距離で測ると、A と B は \(\sqrt{90^2+18^2} \approx 92\)、A と C は \(\sqrt{10^2+2^2+30^2} \approx 32\) で、C のほうが近いことになってしまいます。再生回数の多さ(ベクトルの長さ)が距離を支配してしまうからです。「好みの傾向」を比べたいなら、長さではなく向きを見る必要があります。
角度はどうやって求める? #
3 人の再生回数を、ロック・ポップ・ジャズの 3 軸をもつ空間の矢印だと考えます。A と B の矢印は長さがちがうだけで同じ方向を指し、C の矢印はこの 2 本とほぼ直角の方向を指します。この「矢印のなす角」を数で出すのが次の手順です。
まず、数を並べてベクトルにします。A さんは \(\mathbf{a} = (10, 2, 0)\)、B さんは \(\mathbf{b} = (100, 20, 0)\)、C さんは \(\mathbf{c} = (0, 0, 30)\) です。次に内積を計算します。成分どうしをかけて足すので、\(\mathbf{a}\cdot\mathbf{b} = 10 \times 100 + 2 \times 20 + 0 \times 0 = 1040\)、\(\mathbf{a}\cdot\mathbf{c} = 0\) です。続いて長さを計算すると \(|\mathbf{a}| = \sqrt{10^2 + 2^2 + 0^2} = \sqrt{104}\)、\(|\mathbf{b}| = \sqrt{10400}\)、\(|\mathbf{c}| = 30\) になります。そして内積を長さの積で割ります。
$$ \cos\theta = \frac{\mathbf{a}\cdot\mathbf{b}}{|\mathbf{a}|\,|\mathbf{b}|} $$A と B は \(1040 / 1040 = 1\) で、なす角 0°、完全に同じ向きです。A と C は \(0 / (\sqrt{104} \times 30) = 0\) で、なす角 90°、共通点なしと判定されます。最後に距離に直すなら \(d = 1 - \cos\theta\) とすれば、A と B は 0、A と C は 1 になり、0 に近いほど似ている、という「距離」の向きにそろいます。
内積・長さ・割り算の 3 手順は短いコードで確かめられます。
| |
出力は cosine = 1.0 distance = 0.0。b を [0, 0, 30] に変えると cosine = 0.0 になります。
動かして見てみよう #
下の図で「再生」を押すと、説明した手順が 1 つずつ進みます。手順ごとの説明は図の下に出ます。
気をつけたいこと #
最初の注意は、コサイン類似度が長さの情報を捨てていることです。A さんと B さんは「同じ好み」と判定されますが、「どれくらい熱心か」は区別できません。熱心さも比べたいなら 2 点間の距離など別の指標が必要です。二つ目は、ゼロベクトルでは計算できないことです。1 曲も聴いていない人は \((0, 0, 0)\) で長さが 0 になり、割り算ができないので、そうしたデータは除くか別扱いにします。三つ目は、\(1 - \cos\theta\) が「ふつうの距離」の性質を一部満たさないことです。三角不等式が保証されないので、距離の性質を前提にしたアルゴリズムで使うときは注意が必要です。
やってみよう #
最初の課題は、\((3, 4)\) と \((4, 3)\) のコサイン類似度を内積と長さから手計算し、次に \((3, 4)\) と \((6, 8)\) で計算して 1 になることを確かめることです。二つ目は、自分と友だちの「好きな教科への気持ち」を 5 教科それぞれ 0〜10 で点数にしてベクトルを作り、コサイン類似度を計算して、合計点がちがっても似ていると判定されるペアを探すことです。三つ目は、\((1, -1)\) と \((-1, 1)\) のコサイン類似度を予想してから計算し、「反対向き」が何を意味するか言葉で説明することです。
つぎに読む #
scikit-learn の cosine_similarity / cosine_distances で行列ごと計算する方法と実務での注意点は 標準版のコサイン類似度と距離 で扱っています。他の距離・類似度の指標は 距離・類似度の評価 にまとめています。距離で「近い点同士をまとめる」例は k-means(高校生向け) と 階層型クラスタリング(高校生向け) へ。