似ている商品の抽出
ECサイトなどで「似ている商品」をユーザーにレコメンドする機能は、売上の向上に直結します。本稿では、その核となるロジックとしてコサイン類似度(Cosine Similarity)を取り上げ、その数学的な意味から SQL を使った具体的な実装方法までを解説します。
コサイン類似度の定義と計算式
本稿では「似ている」指標として「コサイン類似度」(cosine similarity) というものを使っていきます。コサイン類似度とは、2つのベクトルがどの程度同じ方向を向いているかを示す指標で、2つのベクトルのなす角の余弦 (cosine)の値です。
この指標は、ベクトルの大きさ(絶対値)には依存せず、純粋に方向の一致度(なす角)を測ります。値は $1$ (完全に一致) から $-1$ (完全に反対) の範囲を取ります。
ベクトルの内積は、以下のように表せますので、
\vec{a} \cdot \vec{b} = \lvert \vec{a} \rvert \lvert \vec{b} \rvert \cos \theta
$\cos \theta$ を左辺に持っていくと、以下のようになります。
\cos \theta = \frac{\vec{a} \cdot \vec{b}}{\lvert \vec{a} \rvert \lvert \vec{b} \rvert}
$n$次元ベクトル $\vec{a}$ の成分表示を、
$(a_1, a_2, ... a_n)$ とするならば上式は、以下のように表されます。
\cos \theta = \frac{a_1 b_1 + a_2 b_2 + ... a_n b_n}
{\sqrt{a_1^2 + a_2^2 + ... a_n^2} \enspace \sqrt{b_1^2 + b_2^2 + ... b_n^2}}
シグマ記号を用いて書くと、こんな感じ。
\cos \theta = \frac{\displaystyle \sum_{i = 1}^n{a_i b_i}}
{\sqrt{\displaystyle \sum_{i = 1}^n a_i^2} \enspace \sqrt{\displaystyle \sum_{i = 1}^n b_i^2}}
実際のデータでコサイン類似度を計算
サンプルとして、ECサイトの商品の類似度を計算してみたいと思います。
商品の特徴を以下のような軸に従って点数をつけるとします。点数はいずれも -10 から 10 までの 20段階評価にします。
| axis_id | 評価軸 | 範囲 |
|---|---|---|
| 1 | コスト | お手軽: -10 〜 高級: 10 |
| 2 | 機能性 | シンプル: -10 〜 多機能: 10 |
| 3 | ジェンダー | 男性向け: -10 〜 女性向け: 10 |
| 4 | 世代 | 若者向け: -10 〜 シニア向け: 10 |
| 5 | 和風・洋風 | 和風: -10 〜 洋風: 10 |
以下のようなテーブルに評価ポイントを格納します。
create table evaluations
(
product_id int not null comment '商品ID',
axis_id int not null comment '評価軸ID',
`point` int not null comment '評価点',
constraint unique_product_axis
unique (product_id, axis_id),
constraint check_range
check ((`point` >= -(10)) and (`point` <= 10))
)
comment '評価';
このテーブルに、サンプルとして以下のような 20種類の商品の評価データを入れてみました。
| 商品ID\評価軸ID | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 1 | -9 | -3 | 0 | -6 | -6 |
| 2 | 5 | 1 | 7 | -8 | 8 |
| 3 | -10 | -9 | 6 | 0 | 0 |
| 4 | 4 | 2 | 0 | -6 | -4 |
| 5 | -9 | -5 | 7 | 9 | 8 |
| 6 | -1 | 4 | 4 | -5 | -8 |
| 7 | 7 | -6 | 0 | -5 | 3 |
| 8 | 0 | -2 | -1 | -3 | -8 |
| 9 | -4 | 5 | -5 | 2 | 4 |
| 10 | -1 | -3 | -7 | 2 | 2 |
| 11 | -6 | 2 | 5 | -6 | -9 |
| 12 | 9 | -8 | 9 | -8 | -5 |
| 13 | 5 | 1 | -2 | 0 | -8 |
| 14 | 0 | 2 | -3 | 2 | 5 |
| 15 | 8 | 7 | 10 | -2 | -6 |
| 16 | 6 | -3 | -7 | 7 | -9 |
| 17 | -5 | 9 | 2 | -5 | 2 |
| 18 | 4 | 4 | -8 | -4 | -7 |
| 19 | -8 | -8 | -1 | 7 | -2 |
| 20 | 0 | 4 | -6 | 4 | 9 |
以下の SQL で、各商品を対にしたコサイン類似度が計算されます。
SELECT
e1.product_id, -- 比較元商品ID
e2.product_id, -- 比較先商品ID
SUM(e1.point * e2.point) -- 二つの商品ベクトルの内積 (分子)
/ ( SQRT(SUM(POW(e1.point,2))) -- 比較元商品ベクトルの絶対値 (分母1)
* SQRT(SUM(POW(e2.point,2))) -- 比較先商品ベクトルの絶対値 (分母2)
) cosine_similarity -- コサイン類似度
FROM evaluations e1 -- 比較元商品の評価
JOIN evaluations e2 -- 比較先商品の評価
ON e1.axis_id = e2.axis_id -- 評価軸を合わせてクロスジョイン
WHERE e1.product_id <> e2.product_id -- 自分自身とは比較しない
GROUP BY e1.product_id, e2.product_id
上記 SQL の末尾に以下の ORDER BY 句を付けて、コサイン類似度の降順で SELECT すると、これらの商品の中で最も似通った商品の対を確認することができます。
ORDER BY cosine_similarity DESC
| e1.product_id | e2.product_id | cosine_similarity |
|---|---|---|
| 20 | 14 | 0.9986408148825328 |
| 14 | 20 | 0.9986408148825328 |
| 6 | 11 | 0.9126900144689101 |
| 11 | 6 | 0.9126900144689101 |
| 20 | 9 | 0.8303964689316616 |
| 9 | 20 | 0.8303964689316616 |
| 14 | 9 | 0.8153089489086591 |
| 9 | 14 | 0.8153089489086591 |
| ... | ... | ... |
上記の結果から 商品ID:14 と 商品ID:20 がよく似ている(と判断されている)ことがわかります。
これら二つの商品の各評価軸の評価点を比べると、商品ID:20 は 商品ID:14 のほぼ倍の評価点になっています。コサイン類似度は、ベクトルの方向性だけで類似度を見ているので、ベクトルの大きさが異なっていても近いと判断されていることがわかります。
この特性は、レコメンドシステムにおいて、商品の絶対的な価格やサイズ(ベクトルの大きさ)ではなく、特徴の傾向(方向)が似ている商品を抽出できるという、コサイン類似度の大きなメリットを示しています。
指定した商品に似た商品をリストアップするときは、比較元の商品IDを固定して、コサイン類似度の降順に検索します。
例えば 商品ID:1 に似た商品を似ている順に 5つ抽出する場合は以下のような SELECT 文を実行します。
SELECT
e1.product_id, -- 比較元商品ID
e2.product_id, -- 比較先商品ID
SUM(e1.point * e2.point) -- 二つの商品ベクトルの内積
/ ( SQRT(SUM(POW(e1.point,2))) -- 比較元商品ベクトルの絶対値(長さ)
* SQRT(SUM(POW(e2.point,2))) -- 比較先商品ベクトルの絶対値(長さ)
) cosine_similarity -- コサイン類似度
FROM evaluations e1 -- 比較元商品の評価
JOIN evaluations e2 -- 比較先商品の評価
ON e1.axis_id = e2.axis_id -- 評価軸を合わせてクロスジョイン
WHERE e1.product_id <> e2.product_id -- 自分自身とは比較しない
-- 商品ID:1 に似た商品
AND e1.product_id = 1
GROUP BY e1.product_id, e2.product_id
ORDER BY cosine_similarity DESC
LIMIT 5 -- 上位5件
| e1.product_id | e2.product_id | cosine_similarity |
|---|---|---|
| 1 | 11 | 0.803685041486804 |
| 1 | 8 | 0.6405126152203484 |
| 1 | 3 | 0.6240199689585152 |
| 1 | 6 | 0.5334869997203998 |
| 1 | 19 | 0.3843711067980367 |
まとめ
各アイテムの特徴を数値化することができれば、コサイン類似度を使って、似ている度合いを計算することができます。
コサイン類似度は、単純なデータベース操作でありながら、ユーザーの潜在的な興味を捉える強力なロジックとなりえます。ぜひ、このロジックを応用して、効果的なレコメンド機能を実装してみてください。