論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
コサイン類似度
Cosine Similarity
類似度・距離
別称: cos類似度 / コサイン距離

🔖 キーワード索引

このページ内のセクションへ素早く飛べます(クリックで該当箇所へジャンプ):

💡 30秒結論📍 文脈🎨 直感📐 数式・定義🔬 数式を言葉で読み解く🧮 SSDSE実値計算🐍 Python実装⚠️ 落とし穴🌐 関連手法🔗 関連用語📚 関連グループ❓ FAQ

🔖 キーワード索引(深掘り)

コサイン類似度 (Cosine Similarity) は 2 つのベクトルの角度の余弦で類似度を測る指標。 値域 $-1$〜$1$、 ベクトルの長さに依存せず方向だけを比べるので、 TF-IDF や埋め込みベクトルの類似度測定に最適です。

💡 30 秒結論 📍 文脈ボックス 🎨 直感で掴む 📐 数式・定義 🔬 数式を言葉で読み解く 🧮 実値で計算 🐍 Python 実装 ⚠️ 落とし穴 🌐 関連手法 🔗 関連用語 📚 グループ教材

💡 30秒で分かる結論 — コサイン類似度

🍰 まずはやさしく

向きの似具合を測る定規のようなものです。

2つのデータの方向が近いか調べます。

おすすめの商品を探すときに使われます。

まずは結論と使い道を読みましょう。

💡 30秒で分かる結論

2 つのベクトルの向きの近さを $-1$〜$+1$ で表す指標

💡 30 秒で分かる結論(深掘り版)

📍 あなたが今見ているもの

🍰 まずはやさしく

ベクトルの角度で似ているかを見る指標です。

データの大きさに惑わされずに比較します。

長い記事と短い記事の似具合を測れます。

他の指標との違いについて読みましょう。

2 つのベクトル間の 角度の余弦 で類似度を測る指標。 値は $-1$ から $1$。 ベクトルの長さ(大きさ)に依存せず 方向だけ を比べるので、 文書の TF-IDF ベクトルや埋め込みベクトルの類似度測定に最適。

本ページは コサイン類似度(Cosine Similarity) を、 ジャストインタイム型データサイエンス教育の文脈で 12 のセクションに分けて解説します。 上から順に読まなくても、 「🔖 キーワード索引」から必要箇所だけ拾い読みすることもできます。

📍 文脈ボックス(あなたが今見ているもの)

コサイン類似度は類似度・距離指標の家族に属し、 ユークリッド距離ピアソン相関 と並列の関係にあります。 「規模を見るか × 方向を見るか」の 2×2 表で位置づけが掴めます。

方向 (角度) を見る規模 (大きさ) を見る
生のベクトルコサイン類似度ユークリッド距離
中心化したベクトルピアソン相関 ($r = \cos\theta$)マハラノビス距離

文書検索に当てはめると、 「短い記事」と「長い記事」は語数 (規模) が大きく異なるため Euclidean では遠く判定されてしまうが、 cosine なら登場語の構成比 (方向) が似ていれば近いと判定できます。 推薦システム・テキストマイニング・埋め込み近傍探索では cosine が事実上の標準です。

🎨 直感で掴む — コサイン類似度とは何者か

🍰 まずはやさしく

方向がどれだけ同じかを数値にしたものです。

データのパターンが似ているか調べます。

人口の違う都市同士を比べる時に便利です。

直感的なイメージについて読みましょう。

コサイン類似度は「2 つのベクトルがどれだけ 同じ方向を向いているかを -1〜+1 で表す指標」。 ベクトルの長さ (規模) は無視し、 角度の近さだけを見るため、 「大都市と地方都市で人口の絶対値は違うが、 総人口・出生数・高齢化率の パターン は似ているか」を比較できる。 47 都道府県を $z$-スコアでベクトル化したとき、 cos が 1 に近い県ペアは「規模を除けば似たプロファイル」を持つ。

コサイン類似度(Cosine Similarity)は、 ベクトル空間で「方向の近さ」を測る道具。 たとえば SSDSE-B-2026 で 47 都道府県を $z$-スコアベクトル化(総人口・出生数・高齢化率…)すると、 「東京と大阪は方向が近い」「沖縄は特異な方向」といったプロファイル比較が直感的にできる。 文書検索・推薦システム・word2vec/BERT 埋め込みの基盤指標。

場面コサイン類似度が登場する例何が分かるか
論文の Methods 節「コサイン類似度を用いて分析した」手法の前提と限界が文脈に乗る
実務レポート「コサイン類似度の観点で評価」意思決定の根拠が明確化
教育・学習SSDSE-B-2026 を題材に演習実データで本物の感覚が得られる
政策・社会類似度・距離 分野で標準的に登場EBPM や DX の議論に直結

本ページではこのあと、 数式(または定義)・SSDSE 実データ計算・Python実装・落とし穴 を順番に追いかけて、 用語を「使える知識」にしていきます。

🎨 直感で掴む(要点)

「2 つのベクトルの向きが同じか」を判定する道具です。 長さ (規模) を割り消すため、 「東京 (人口 1400 万) と高知 (約 70 万)」のように規模が違う対象どうしでも、 プロファイルの形だけ取り出して比較できます。

以下では、 内積とノルムによる定義 $\cos\theta = \mathbf{a}\cdot\mathbf{b} / (\|\mathbf{a}\|\|\mathbf{b}\|)$ を確認したあと、 SSDSE-B-2026 の 47 都道府県の年齢構成ベクトルで「東京と沖縄の向きはどれだけ近いか」を実値計算し、 階層クラスタリングや TF-IDF 推薦への接続、 「すべて正のベクトルでは類似度が下がりにくい」「ノルム情報を捨てるため大小は表現できない」といった落とし穴まで順に辿ります。

🎨 直感で掴む(深掘り)

2 次元平面で 2 本の矢印を頭に描いてください。 ベクトル $\mathbf{a}$ と $\mathbf{b}$ のなす角度を $\theta$ とすると、 内積 $\mathbf{a}\cdot\mathbf{b} = \|\mathbf{a}\|\|\mathbf{b}\|\cos\theta$。 この式を「長さの積」で割れば、 残るのは $\cos\theta$ だけ —— これがコサイン類似度の本体です。 このとき:

$z$-スコア化したベクトル同士の cos は、 実はピアソン相関係数 $r$ と一致します ($r = \cos\theta$ when centered)。 つまりコサイン類似度は、 中心化を省いた一般化 (規模に左右されない) と理解できます。 高次元 (TF-IDF で 1 万次元、 BERT で 768 次元) になっても定義はそのまま使え、 計算量は $O(n)$ で軽い。

実務的なメタファー: 「電車の進行方向が同じか」を測る感覚。 速度 (ベクトル長) は無視し、 方角だけ比較する。 文書検索で「短い質問文と長い記事を同じ尺度で比べたい」場面に最適で、 これがコサイン類似度が情報検索の主流になった理由です。

🎮 触って理解する

下の図で、 2 本の矢印(ベクトル $\mathbf{a}$・$\mathbf{b}$)の先端の丸をドラッグ(スマホは指でスワイプ)してみてください。 なす角 $\theta$ と コサイン類似度 $\cos\theta = (\mathbf{a}\cdot\mathbf{b})/(\|\mathbf{a}\|\,\|\mathbf{b}\|)$ がリアルタイムに計算されます。 同じ向き=1、 直交=0、 逆向き=-1 を手で確かめられます。

a b
ベクトル a(3.0, 1.0)
ベクトル b(1.0, 3.0)
長さ |a|3.16
長さ |b|3.16
内積 a·b6.00
なす角 θ53.13°
コサイン類似度 cos θ
0.600
-1 逆向き0 直交+1 同向き
参考: ユークリッド距離 |a−b|
2.828
距離は「位置の隔たり」。 コサインは「向きのズレ」。 別物です。
2 つのベクトルは中くらいの角度。 向きはやや近い(正の類似度)。
プリセット:
大きさ非依存の確認:

↑ a の長さだけを変えても、 向きが同じなら cos θ は変わりません(コサイン類似度は大きさに依存しない)。 一方でユークリッド距離は変化します。 ここが両者の決定的な違いです。

🔍 この体験から読み取れること

📐 数式・定義

🍰 まずはやさしく

向きの近さを計算で出すルールです。

正確な数値として似具合を表します。

計算結果を-1から1の範囲で出します。

具体的な数式と定義について読みましょう。

2 つのベクトル $\mathbf{a}, \mathbf{b}$ のコサイン類似度:

$$ \cos\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \, \|\mathbf{b}\|} = \frac{\sum_{i=1}^n a_i b_i}{\sqrt{\sum_{i=1}^n a_i^2} \sqrt{\sum_{i=1}^n b_i^2}} $$

分子は内積、 分母はベクトル長(ユークリッドノルム)の積。 値域は $-1 \le \cos\theta \le 1$。 $1$ は同方向、 $0$ は直交、 $-1$ は反対方向。 コサイン距離は $1 - \cos\theta$ で定義され、 距離指標として使う。

📐 定義

2 つのベクトル $\mathbf{a}, \mathbf{b}$ の方向の近さを、 内積を 2 本の長さの積で正規化して -1〜+1 に押し込めた指標。

英語名 Cosine Similarity。 同義・関連語:Cosine distance ($1 - \cos\theta$)、 角度距離、 中心化すればピアソン相関係数 $r$ と一致する。

🎯 いつ・どこで使うか

📋 前提条件・適用範囲

この用語を理解・使用するときは、 次のような前提を意識してください:

📐 数式・定義(深掘り)

2 つのベクトル $\mathbf{a} = (a_1, ..., a_n)$ と $\mathbf{b} = (b_1, ..., b_n)$ について、 内積を 2 本のノルムの積で正規化した値がコサイン類似度です:

$$\cos\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\|\,\|\mathbf{b}\|} = \frac{\sum_{i=1}^n a_i b_i}{\sqrt{\sum_{i=1}^n a_i^2}\,\sqrt{\sum_{i=1}^n b_i^2}}$$

コサイン距離は類似度を距離に変換したもの ($1 - \cos\theta \in [0, 2]$):

$$d_{\cos}(\mathbf{a}, \mathbf{b}) = 1 - \cos\theta$$

ベクトルを中心化 (平均を引く) すると、 cosine 類似度はピアソン相関係数 $r$ と一致します:

$$r = \frac{\sum_i (a_i - \bar{a})(b_i - \bar{b})}{\sqrt{\sum_i (a_i - \bar{a})^2}\,\sqrt{\sum_i (b_i - \bar{b})^2}} = \cos\theta_{\text{centered}}$$

単位ベクトル化 ($\hat{\mathbf{a}} = \mathbf{a}/\|\mathbf{a}\|$) すれば、 cosine 類似度とユークリッド距離は単調変換で結ばれます:

$$\|\hat{\mathbf{a}} - \hat{\mathbf{b}}\|^2 = 2(1 - \cos\theta)$$

📐 コサイン類似度 vs Euclidean 距離 — 「向き」と「大きさ」のどちらを見るか

2 つの都道府県を「総人口」と「65 歳以上人口」の 2 次元ベクトルとみなすと、 大都市と小規模県は Euclidean 距離では大きく離れる(規模が桁違い)一方で、 高齢化のプロファイル(構成比)が近ければ 原点からの方向 (角度) はほぼ同じになる。 コサイン類似度は後者の「向き」だけを測る:

$$\cos\theta = \dfrac{\mathbf{x}\cdot \mathbf{y}}{\|\mathbf{x}\|\,\|\mathbf{y}\|}, \qquad d_E(\mathbf{x},\mathbf{y}) = \|\mathbf{x}-\mathbf{y}\|$$

使い分けの原則: 文書ベクトル (単語頻度) や利用者プロファイル (好み比率) のように絶対量より構成比が重要な場面 → cosine。 物理座標・人口の絶対値そのものを比較したい → Euclidean。 都道府県データでは「規模を捨てて構成比の似ている県を探す」用途に cosine が最適。

このコードでやること: 3 つの特徴ベクトルを用意し、 cosine 類似度と Euclidean 距離の両方を計算して、 「最も近い相手」が指標によって入れ替わる様子を確認する。 SSDSE のような実データに移す前に、 小さな合成ベクトルで挙動を掴むのが狙い。

📥 入力データ: 3 語の出現回数とみなした 3 次元ベクトル 3 本

A = [10, 20, 30] 基準 B = [ 1, 2, 3] A と同じ向き・規模だけ小さい C = [30, 20, 10] A と同規模・向きが違う
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances

# 3 つの特徴ベクトル(例: 3 語の出現回数)
A = np.array([10, 20, 30])   # 基準
B = np.array([ 1,  2,  3])   # A と同じ「向き」・規模だけ小さい
C = np.array([30, 20, 10])   # A と規模は同程度・「向き」が違う

M = np.vstack([A, B, C]).astype(float)
cos = cosine_similarity(M)     # コサイン類似度(向き)
euc = euclidean_distances(M)   # ユークリッド距離(規模込み)

print(f"cos(A,B)={cos[0,1]:.3f}  cos(A,C)={cos[0,2]:.3f}")
print(f"Euc(A,B)={euc[0,1]:.1f}   Euc(A,C)={euc[0,2]:.1f}")

📤 実行結果:

cos(A,B)=1.000 cos(A,C)=0.714 Euc(A,B)=33.7 Euc(A,C)=28.3

💬 結果の読み方: cosine では A に最も近いのは B(向きが完全に一致し 1.000)。 ところが Euclidean では A に最も近いのは C(28.3 < 33.7)。 同じ 3 本のベクトルでも、 「向き」を見るか「規模」を見るかで最近傍が入れ替わる — これが cosine 類似度と距離指標の本質的な違いです。

🔬 数式・定義を「言葉」で読み解く

コサイン類似度の式 $\cos\theta = \dfrac{\mathbf{a}\cdot\mathbf{b}}{\|\mathbf{a}\|\,\|\mathbf{b}\|} = \dfrac{\sum_{i=1}^n a_i b_i}{\sqrt{\sum_{i=1}^n a_i^2}\sqrt{\sum_{i=1}^n b_i^2}}$ に登場する記号を 1 つずつ確認します。 ここでは 2 本の 3 次元ベクトル $\mathbf{a}=(2,3,6)$, $\mathbf{b}=(6,3,2)$ を例に具体化します。

記号読み方意味具体例 $\mathbf{a}=(2,3,6),\ \mathbf{b}=(6,3,2)$
$\mathbf{a}, \mathbf{b}$ベクトル a・b (太字)比較したい 2 本の $n$ 次元ベクトル$\mathbf{a}=(2,3,6)$ と $\mathbf{b}=(6,3,2)$
$a_i, b_i$a の i 番目要素ベクトルの第 $i$ 成分 (実数)$a_1=2,\ a_2=3,\ a_3=6$ の各成分
$\mathbf{a}\cdot\mathbf{b}$内積 (ドット積)$\sum_i a_i b_i$。 2 本のベクトルの「重なり」を測る$2\times6 + 3\times3 + 6\times2 = 33$
$\|\mathbf{a}\|$a のノルム (大きさ)$\sqrt{\sum_i a_i^2}$、 原点からベクトル先端までの距離$\|\mathbf{a}\| = \sqrt{2^2 + 3^2 + 6^2} = 7$
$\theta$シータ (角度)2 本のベクトルが成す角度 ($0 \le \theta \le \pi$)$\theta = \arccos(0.673) \approx 47.7°$
$\cos\theta$類似度の値$-1 \le \cos\theta \le 1$。 1 は同方向、 0 は直交、 -1 は反対方向$\cos\theta = 33/(7\times7) \approx 0.673$
$n$次元数ベクトルの成分数。 文書なら語彙サイズ、 都道府県なら指標数$n=3$ (3 つの成分)

コサイン類似度の文脈では、 とくに $\mathbf{a}\cdot\mathbf{b}$ (内積) と $\mathbf{a}\times\mathbf{b}$ (外積) の混同に注意。 また内積はスカラー値であり、 ベクトルではない。 ノルム $\|\cdot\|$ は通常 L2 (ユークリッドノルム) を指すが、 L1 (マンハッタン) を採用すれば別の類似度になる。

🔬 数式を言葉で読み解く

分子 $\mathbf{a}\cdot\mathbf{b} = \sum_i a_i b_i$ の読み方: 「2 本のベクトルの同じ成分どうしを掛けて足し合わせた値」。 両方が大きい (両方が小さい) 成分があれば内積は増え、 一方が正で他方が負なら内積は減る。 すべての成分が非負 (頻度・人口など) なら内積は必ず非負。

分母 $\|\mathbf{a}\|\,\|\mathbf{b}\|$ の読み方: 「2 本のベクトルの長さ (大きさ) の積」。 これで割ることで規模 (絶対値) の影響を打ち消し、 純粋に「向き」だけを取り出す。 一方のベクトルが他方の 2 倍の長さでも、 各成分の比率が同じなら cos は 1 になる。

$\cos\theta$ の値の読み方: 内積を長さの積で割った量は、 ベクトル間の角度の余弦と一致する (これが「コサイン」類似度の名の由来)。 $\cos 0° = 1$ (完全一致)、 $\cos 90° = 0$ (直交=無関係)、 $\cos 180° = -1$ (反対)。 文書ベクトル (非負成分) では値域は $[0, 1]$ に限定される。

中心化後の cos = ピアソン相関: $\mathbf{a}, \mathbf{b}$ から平均を引いてからコサイン類似度を取ると、 ピアソン相関係数 $r$ に一致する ($\cos(\mathbf{a}-\bar{a},\, \mathbf{b}-\bar{b}) = r$)。 つまり相関係数はコサイン類似度の特殊形。 これが「相関とコサインは双子の指標」と呼ばれる理由です。

🧮 SSDSE-B 実値で計算してみる

SSDSE-B-2026(47都道府県・2023 年・112 項目)を題材に、 コサイン類似度 に関係する変数を実値で確認します。 とくに東京・大阪・沖縄・秋田 など特徴ある県を比較すると、 用語の重みが体感できます。

都道府県総人口(千人)高齢化率(%)TFR消費支出(円/月)
東京14,08622.80.99341,320
大阪8,76327.71.19271,246
沖縄1,46823.81.60251,222
秋田91439.11.10272,086
全国(総人口・高齢化率・TFR は全国値、 消費支出は 47 県平均)124,35329.11.20295,856

これらの値を コサイン類似度 の観点で読み解くと、 都道府県間の格差・特徴・関係性が浮かび上がります。 具体的な計算手順は次の「🐍 Python 実装」セクションで実演します。

🧮 数式に値を入れて手で計算する

合成ベクトル $\mathbf{A}=[2,3,4]$, $\mathbf{B}=[1,5,2]$ をコサイン類似度の数式に代入し、 内積・ノルム・cos 値の順に Step 1〜3 で手計算する。 同じ計算を Python (numpy / sklearn) で再現し、 結果が一致することを確認する。

📐 コサイン類似度 (再掲)

$$ \cos\theta = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\|\,\|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2}\,\sqrt{\sum_{i=1}^{n} B_i^2}} $$

Step 1: データ準備 (合成、 多様な整数)

次元 i$A_i$$B_i$$A_i B_i$$A_i^2$$B_i^2$
121241
23515925
3428164
合計252930

Step 2: 内積とノルム

項目計算結果
内積 $\mathbf{A}\cdot\mathbf{B}$$2\cdot1 + 3\cdot5 + 4\cdot2 = 2+15+8$25
$\|\mathbf{A}\|$$\sqrt{4+9+16}=\sqrt{29}$5.3852
$\|\mathbf{B}\|$$\sqrt{1+25+4}=\sqrt{30}$5.4772
分母 $\|\mathbf{A}\|\,\|\mathbf{B}\|$$\sqrt{29}\cdot\sqrt{30}=\sqrt{870}$29.4958

Step 3: コサイン類似度

項目計算結果
$\cos\theta$$25 / \sqrt{870}$0.8475
コサイン距離 $1-\cos\theta$$1 - 0.8475$0.1525
角度 $\theta$ (参考)$\arccos(0.8475)$32.07°

🐍 同じ計算を Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# Step 1: 合成ベクトル (多様な整数)
A = np.array([2, 3, 4])
B = np.array([1, 5, 2])

# Step 2: 内積とノルム
dot = np.dot(A, B)
norm_A = np.linalg.norm(A)
norm_B = np.linalg.norm(B)

# Step 3: コサイン類似度 (手計算式) と sklearn 版
cos_manual = dot / (norm_A * norm_B)
cos_sklearn = cosine_similarity(A.reshape(1, -1), B.reshape(1, -1))[0, 0]

print(f"内積 A.B       = {dot}")
print(f"||A||          = {norm_A:.4f}")
print(f"||B||          = {norm_B:.4f}")
print(f"cos (手計算式) = {cos_manual:.4f}")
print(f"cos (sklearn)  = {cos_sklearn:.4f}")
print(f"コサイン距離   = {1 - cos_manual:.4f}")

📤 実行結果

内積 A.B = 25 ||A|| = 5.3852 ||B|| = 5.4772 cos (手計算式) = 0.8475 cos (sklearn) = 0.8475 コサイン距離 = 0.1525

💬 手計算 (Step 3 の 0.8475) と Python 出力 (numpy 手計算式・sklearn のいずれも 0.8475) が完全一致。 コサイン類似度 0.8475 は「向きがかなり揃っている (角度約 32°)」ことを示し、 2 ベクトルは同じ傾向にある成分構成と読める。

🧮 3 次元プロファイルで手計算してみる

説明用の合成データとして、 2 つの対象を 3 指標でベクトル化し、 コサイン類似度を 1 ステップずつ手計算します。 数値の絶対値ではなく 3 指標のバランスがどれだけ似ているかを測る用途です。

対象 2 つの 3 次元ベクトル(規模の大きい対象 T と中規模の対象 O):

T = (14.0, 110.0, 19.0)
O = (8.8, 41.0, 9.5)

Step 1〜3 で内積・ノルム・cos を求める:

Step 1 内積 T·O = 14.0×8.8 + 110.0×41.0 + 19.0×9.5 = 123.2 + 4510.0 + 180.5 = 4813.7
Step 2 ‖T‖ = √(14.0² + 110.0² + 19.0²) = √(196 + 12100 + 361) = √12657 ≈ 112.50
Step 2 ‖O‖ = √(8.8² + 41.0² + 9.5²) = √(77.44 + 1681 + 90.25) = √1848.69 ≈ 42.99
Step 3 cos(T,O) = 4813.7 / (112.50 × 42.99) = 4813.7 / 4836.4 ≈ 0.9953

→ cos ≈ 0.995 は「2 つの対象の 3 指標バランスが極めて近い」ことを意味します。 規模 (ノルム) は T が O の約 2.6 倍ですが、 構成比は同形。 さらに小規模な対象 R = (0.55, 1.9, 0.55) を加えると ‖R‖ ≈ 2.06、 T·R = 7.7+209+10.45 ≈ 227.15、 cos(T,R) ≈ 227.15 / (112.50×2.06) ≈ 0.980。 規模が桁違いでも cos は 1 に近く、 「向きの類似」を測る指標であることが直感できます。

🐍 Python 実装

以下は コサイン類似度 を SSDSE-B-2026 で扱うときの典型コード。 encoding='cp932' は政府統計の Shift-JIS 対応。 skiprows=[1] は 2 行目の日本語ヘッダ行だけをスキップして列コード(A1101 等)を列名に使う定石(skiprows=1 だと 1 行目の列コード行が消え、 日本語ラベルが列名になる)。

① 基本パターン(読み込み・確認・主要列抽出)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) Prefecture(都道府県) 北海道 5,092,000 北海道 東京都 14,086,000 東京都 沖縄県 1,468,000 沖縄県 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import pandas as pd

# コサイン類似度 に関連する SSDSE-B-2026 分析の基本パターン
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1).query('年度 == 2023')   # 日本語読みなので列名は 年度
print(df.shape)            # (47, 112)
print(df.dtypes.head(10))
print(df.describe().T.head(10))

# 主要列にエイリアス
df['総人口']   = df.iloc[:, 3]
df['65歳以上'] = df.iloc[:, 15]
df['高齢化率'] = df['65歳以上'] / df['総人口'] * 100
print(df[['都道府県','総人口','高齢化率']].head())   # 日本語読みなので '都道府県'
📤 実行例(実測) (47, 112) 年度 int64 地域コード object 都道府県 object 総人口 int64 総人口(男) int64 総人口(女) int64 日本人人口 int64 日本人人口(男) int64 日本人人口(女) int64 15歳未満人口 int64 dtype: object count mean std ... 50% 75% max 年度 47.0 2.023000e+03 0.000000e+00 ... 2023.0 2023.0 2023.0 総人口 47.0 2.645809e+06 2.797551e+06 ... 1549000.0 2636500.0 14086000.0 総人口(男) 47.0 1.287085e+06 1.373649e+06 ... 732000.0 1269500.0 6914000.0 総人口(女) 47.0 1.358723e+06 1.424664e+06 ... 817000.0 1367000.0 7172000.0 日本人人口 47.0 2.578617e+06 2.691343e+06 ... 1533000.0 …(以下略)

② 可視化テンプレ(matplotlib / seaborn)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# コサイン類似度 の探索的データ分析(EDA)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1).query('年度 == 2023')

# 主要変数を取り出して名前を分かりやすく
df['総人口']    = df.iloc[:, 3]
df['65歳以上']  = df.iloc[:, 15]
df['高齢化率']  = df['65歳以上'] / df['総人口'] * 100
df['TFR']      = df.iloc[:, 21]

# ヒストグラム
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
sns.histplot(df['高齢化率'], kde=True, ax=axes[0])
axes[0].set_title('高齢化率の分布(47都道府県)')
sns.histplot(df['TFR'], kde=True, ax=axes[1])
axes[1].set_title('TFRの分布')
plt.tight_layout()
plt.savefig('eda_distribution.png', dpi=120)

③ 前処理:欠損・外れ値・型変換

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import pandas as pd
import numpy as np

# コサイン類似度 に関わる前処理の典型パターン
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])

# ① 欠損値の確認
print('欠損数:')
print(df.isna().sum().sort_values(ascending=False).head(10))

# ② 数値変換(カンマ・%除去 など。 変換できない文字列はそのまま返す)
def to_num(s):
    if isinstance(s, str):
        try:
            return float(s.replace(',', '').replace('%', ''))
        except ValueError:
            return s
    return s
df = df.applymap(to_num)

# ③ 外れ値検出(IQR、 数値列のみ対象)
num = df.select_dtypes(include='number')
q1 = num.quantile(0.25)
q3 = num.quantile(0.75)
iqr = q3 - q1
outlier_mask = ((num < q1 - 1.5*iqr) | (num > q3 + 1.5*iqr)).any(axis=1)
print('外れ値を含む行数:', outlier_mask.sum())
📤 実行例(実測) 欠損数: SSDSE-B-2026 0 Code 0 H1800 0 G7102 0 G7101 0 G5105 0 F3105 0 F3104 0 F3103 0 F3102 0 dtype: int64 外れ値を含む行数: 239

④ 検定・推定の最小例(scipy.stats)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) 北海道 5,092,000 1,681,000 東京都 14,086,000 3,205,000 沖縄県 1,468,000 350,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import pandas as pd
from scipy import stats

# コサイン類似度 文脈での基本的な仮説検定
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]).query('`SSDSE-B-2026` == 2023')
df['aging']  = df['A1303'] / df['A1101'] * 100
df['region'] = df['Prefecture'].apply(lambda p: '東日本' if p in ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県','茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県','新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県'] else '西日本')

east = df.loc[df['region']=='東日本', 'aging']
west = df.loc[df['region']=='西日本', 'aging']

t, p = stats.ttest_ind(east, west, equal_var=False)
print(f'東日本 平均高齢化率: {east.mean():.2f}%')
print(f'西日本 平均高齢化率: {west.mean():.2f}%')
print(f't = {t:.3f}, p = {p:.4f}')
print('判定:', '有意差あり' if p < 0.05 else '有意差なし')
📤 実行例(実測) 東日本 平均高齢化率: 31.18% 西日本 平均高齢化率: 31.97% t = -0.804, p = 0.4259 判定: 有意差なし

※ より高度な例(クロス集計、 機械学習、 ベイズ推定)は text-similarity のグループ教材を参照。

🐍 Python での扱い

SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd
import numpy as np

# データ読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
print(df.shape)
print(df.dtypes)
print(df.describe())

# 「コサイン類似度」の文脈で扱う場合の例:
# 分野: 類似度・距離指標
# 関連手法は同カテゴリの他用語を参照してください。
📤 実行例(実測) (564, 112) 年度 int64 地域コード object 都道府県 object 総人口 int64 総人口(男) int64 ... 保健医療費(二人以上の世帯) int64 交通・通信費(二人以上の世帯) int64 教育費(二人以上の世帯) int64 教養娯楽費(二人以上の世帯) int64 その他の消費支出(二人以上の世帯) int64 Length: 112, dtype: object 年度 総人口 ... 教養娯楽費(二人以上の世帯) その他の消費支出(二人以上の世帯) count 564.000000 5.640000e+02 ... 564.000000 564.000000 mean 2017.500000 2.690688e+06 ... 26931.026596 59784.718085 std 3.455117 2.730951e+06 ... 4219.487086 8813.812956 min 2012.000000 5.370000e+05 ... 14661.000000 35 …(以下略)

具体的なコードは テキスト類似度グループ教材 を参照してください。

📝 レポートでの報告

分析結果を報告するときに含めるべき情報:

✅ チェックリスト

🔗 同カテゴリの他用語

相関係数ユークリッド距離マンハッタン距離マハラノビス距離Jaccard 係数類似度埋め込みword2vecTF-IDFベクトル空間モデルk-近傍法クラスタリング推薦システム内積

🐍 Python 実装(深掘り) — コサイン類似度に固有の論点

① SSDSE-B-2026 で 47 県を「人口プロファイル」ベクトル化して類似度を測る

🎯 このコードでやること:各県を「総人口・出生数・65 歳以上人口」の 3 次元ベクトルとして表現し、 全 47 県ペアのコサイン類似度行列を構築する。 人口構成 (構成比) が近い県ほど cos が 1 に近づく。

📥 入力データ:SSDSE-B-2026 の実在列コード 3 本。 規模 (絶対人数) ではなく「方向 (構成比)」を測る点が cos の本質。

列コード 指標 A1101 総人口 A4101 出生数 A1303 65歳以上人口
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# skiprows=[1] で日本語見出し行を飛ばし、 列コードをそのまま使う
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]).query('`SSDSE-B-2026` == 2023')
# 各県を「総人口 A1101・出生数 A4101・65歳以上人口 A1303」の 3 次元プロファイルに
X = df[['A1101', 'A4101', 'A1303']].values.astype(float)
sim = cosine_similarity(X)                 # 全 47 県ペアの cos
print('類似度行列 shape =', sim.shape)      # (47, 47)
print('自己類似度(対角) =', round(sim[0, 0], 4))

📤 実行すると次の出力が得られる

類似度行列 shape = (47, 47) 自己類似度(対角) = 1.0

💬 結果の読み方:出力は 47×47 の行列で、 対角成分は必ず 1.0(自分自身とは同方向)。 3 指標がすべて非負なので値は 0〜1 に収まり、 人口構成の近い県ペアほど 1 に近づく。 具体的な県ペアの cos は手元のデータで実行して確かめよう。 規模差そのものを見たい場合は cos ではなくユークリッド距離を使う。

② L2 正規化 → 内積 = cos の同値性を確認

🎯 このコードでやること:ベクトルを L2 正規化(単位ベクトル化)してから内積を取ると、 cosine_similarity と一致することを示す。 大規模検索 (FAISS 等) ではこの等価性を利用して内積検索だけを実装する。

📥 入力データ:① の 47 県 × 3 指標の行列 X。

1
2
3
4
5
6
7
from sklearn.preprocessing import normalize

Xn = normalize(X, norm='l2')          # 各行を単位ベクトルへ
sim_dot = Xn @ Xn.T                  # 単純な内積
sim_cos = cosine_similarity(X)          # scikit-learn
diff = np.abs(sim_dot - sim_cos).max()
print(f'最大差分 = {diff:.2e}  (≒0 で同値)')

📤 実行すると次の出力が得られる

最大差分 = 0.00e+00 (≒0 で同値)

💬 結果の読み方:差分は浮動小数の丸め誤差レベル ($10^{-16}$)。 「L2 正規化 → 内積」と「コサイン類似度」は数学的に同一であることが実証された。 検索エンジン・推薦システムが「Inner Product Search」と「Cosine Search」を同列に扱える理由がここにある。

③ ピアソン相関 = 中心化したベクトルのコサイン類似度

🎯 このコードでやること:ベクトルから平均を引いて中心化したあとに cos を計算すると、 ピアソン相関係数 $r$ と一致することを示す。 cos と相関の橋渡し。

📥 入力データ:説明用の合成データ(2 指標 × 5 サンプル)。 実データでは総人口 (A1101) と出生数 (A4101) のような 2 列を渡せばよい。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import numpy as np
from scipy.stats import pearsonr

# 説明用の合成データ(2 指標 × 5 サンプル)
x = np.array([2.0, 4.0, 6.0, 8.0, 11.0])
y = np.array([1.0, 3.0, 2.0, 5.0, 4.0])
xc, yc = x - x.mean(), y - y.mean()        # 中心化(平均を引く)
cos_centered = (xc @ yc) / (np.linalg.norm(xc) * np.linalg.norm(yc))
r, _ = pearsonr(x, y)
print(f'cos(中心化) = {cos_centered:.4f}   ピアソン r = {r:.4f}')

📤 実行すると次の出力が得られる

cos(中心化) = 0.7696 ピアソン r = 0.7696

💬 結果の読み方:両者は完全に一致。 これは「ピアソン相関 = 平均を抜いたあとのコサイン類似度」という関係を示す。 cos を中心化すると相関、 中心化しないと「方向の一致」になる。 推薦システムでユーザー平均評価を引いてから cos を取ると、 「絶対値の高低」ではなく「相対的な好み」が捉えられる理由。

④ 高次元の呪い — 次元数を上げたときの cos 分布

🎯 このコードでやること:SSDSE-B-2026 の連続列を $d$ = 3, 10, 30, 80 と段階的に増やしたとき、 全 47 県ペアの cos の中央値・最大値・最小値がどう動くかを観察する。 生の非負・規模列では、 どの $d$ でも大半のペアが cos ≈ 1 に張り付き、 判別力が乏しい(標準化が要る)ことが確認できる。

📥 入力データ:SSDSE-B-2026 の数値列を昇順に切り出した行列。

1
2
3
4
5
6
7
8
9
num_df = df.select_dtypes(include='number').dropna(axis=1)
for d in [3, 10, 30, 80]:
    Xd = num_df.iloc[:, :d].values
    if Xd.shape[1] < d: continue
    S = cosine_similarity(Xd)
    off = S[~np.eye(47, dtype=bool)]      # 対角線除去
    print(f'd={d:2}  median={np.median(off):.3f}  min={off.min():.3f}  max={off.max():.3f}')

📤 実行すると次の出力が得られる

d= 3 median=1.000 min=1.000 max=1.000 d=10 median=1.000 min=0.999 max=1.000 d=30 median=0.999 min=0.989 max=1.000 d=80 median=0.978 min=0.429 max=1.000

💬 結果の読み方:総人口・出生数のような SSDSE の生の非負・規模列は、 3〜80 次元のいずれでも cos の中央値が 0.98〜1.00 とほぼ 1 に張り付く(大きい成分が内積を支配するため)。 列を増やすと一部ペアで値が下がり始める($d$=80 で min が 0.429 まで低下)が、 中央値は依然 1 近くで、 全体として似すぎて判別力が乏しい。 実務では z-スコア標準化や TF-IDF / IDF 重み付け、 PCA / Truncated SVD による次元削減を挟んでから cos を測るのが定石。

⚠️ よくある落とし穴(7 件)

コサイン類似度 に取り組むときに、 学生・実務者・研究者がよく踏むワナをまとめました。 該当しそうな項目があれば、 自分の分析を見直してみてください。

❌ 1. 規模差を無視して「似ている」と誤判定
cos は「方向」だけを見るので、 北海道 (大規模) と沖縄 (小規模) の産業構造ベクトルが cos=0.99 でも、 規模は約 4 倍違う。 規模も含めて比べたい場合はユークリッド距離や正規化済みの絶対値比較を併用する。
❌ 2. 負の成分を含む埋め込みで「無関係」を見誤る
Word2Vec / GloVe のような負成分を含むベクトルでは cos ∈ [-1, 1]。 cos = 0 は「無関係」ではなく「直交 (互いに情報を共有しない)」を意味するだけ。 cos < 0 が出るのは「反対方向」で、 解釈には文脈知識が必要。
❌ 3. ゼロベクトル / 微小ノルムで分母 0
$\|\mathbf{a}\| \approx 0$ や $\|\mathbf{b}\| \approx 0$ では cos が定義できない、 または数値的に発散する。 TF-IDF で全項がストップワードの文書、 全ピクセルが背景の画像などで実際に発生する。 計算前に norm < eps をフィルタする。
❌ 4. スケーリング忘れで「大きい人」が常に似てしまう
推薦システムで「全アイテムに高評価をつける常連ユーザー」は誰とでも cos が高くなる。 平均評価を引いて中心化する (= 結局ピアソン相関にする)、 もしくは TF-IDF 重みで「珍しい行動」を重視する処理が必須。
❌ 5. 次元の呪い — 高次元で全ペアが直交
数千次元の埋め込みでは「ランダムベクトル同士はほぼ直交」になる性質があり、 cos の絶対値で似ているか判断できなくなる。 上位 k 近傍ランキングや IDF 重み付け、 次元削減 (PCA / Truncated SVD / UMAP) を併用する。
❌ 6. 「cos 高い = 類似」を機械的に解釈
cos は数値だけ。 「なぜ似ているか」は埋め込み空間の意味解釈に依存する。 BERT 埋め込みでは「同じ品詞だから cos が高い」ことがあり、 意味類似と勘違いされやすい。 上位類似結果を必ず人手でサンプリング確認する。
❌ 7. ユークリッド距離との混同
単位ベクトル同士なら $\|\hat{a}-\hat{b}\|^2 = 2(1-\cos\theta)$ が成り立ち、 cos と L2 距離は単調変換で対応する。 しかし非単位ベクトルでは別物。 FAISS / Annoy などライブラリで「inner product」と「L2」を切り替える時は L2 正規化済か必ず確認する。

🧭 詳細解説 — コサイン類似度 を一段深く掘り下げる

歴史的背景

コサイン類似度(Cosine Similarity)は、 1960 年代の情報検索分野で Gerard Salton らがベクトル空間モデル(VSM)を提案した際に文書類似度の標準的指標として確立されました。 1970 年代に SMART システム(Salton, 1971)で TF-IDF と組み合わされて以降、 文書クラスタリング・検索ランキング・テキスト分類の基盤となり、 2010 年代に Word2Vec / GloVe / BERT などの単語・文埋め込みが登場すると、 ベクトル空間内の意味的近接性を測る事実上の標準として再注目されました。 現在は推薦システム(協調フィルタリング)、 画像検索(CLIP embeddings)、 RAG(Retrieval-Augmented Generation)の文脈でも中核的役割を果たしています。

日本では総務省・経産省・内閣府の各種計画(Society 5.0、 デジタル田園都市国家構想、 統計改革基本計画)で繰り返し言及される基幹概念。 SSDSE(教育用標準データセット)も、 これらの教育普及を目的に整備されたデータです。

国際的な位置付け

OECD、 国連、 ISO、 IEC などの国際機関が、 コサイン類似度 に類する概念・標準を整備してきました。 たとえば:

日本の文脈での意味

コサイン類似度 を含むデータ分析の手法は、 日本では次の場面で使われています。 下の表は分野ごとの登場場面で、 この用語だけの話ではなくデータサイエンス全体の広がりを示します:

領域データサイエンスが使われる場面
高校・大学教育情報 I/II、 数学 B(統計)、 教養統計、 専門統計の中核概念として登場
行政・政策EBPM、 デジタル庁施策、 自治体 DX、 地方創生交付金の根拠資料
企業・産業DX 推進、 データ分析人材育成、 経営判断、 マーケティング・品質管理
学術研究公衆衛生、 教育学、 経済学、 社会学、 計算機科学などの分野横断研究
市民・メディア報道、 ファクトチェック、 行政情報の解釈、 民主主義の基盤

よく混同される概念

コサイン類似度 は、 隣接概念と混同されやすい用語の代表でもあります。 ここで違いを明確にしておきましょう:

混同される概念コサイン類似度 との違い
隣接する 類似度・距離 系の用語本ページの「🔗 関連用語」を参照。 並列カテゴリで対比すると明瞭
より広い上位概念text-similarity ページで包含関係を確認
類似名・別名英語名 (Cosine Similarity) を正式表記として参照

学習・教材としての位置付け

本サイト(用語解説)は「ジャストインタイム型データサイエンス教育」のリソースです。 つまり、 論文・実務・授業で その用語に出会ったタイミングで必要最低限の説明を得る、 という使い方を想定しています。 コサイン類似度 もその一例。

体系的に学びたい場合は、 まずグループ教材(text-similarity)から始め、 そこから コサイン類似度 のような個別用語にドリルダウンしていくのが効率的です。

参考文献・標準

⚠️ よくある落とし穴(コサイン類似度 固有)

❌ 標準化していない生スコアでの計算
人口(百万単位)と高齢化率(%)を混ぜたまま cos を取ると、 人口次元が支配的になる。 必ず z-score / min-max 正規化してから計算する。
❌ スパースな TF-IDF ベクトルで全ペア計算
数万次元 × 数万文書で全ペア cos は $O(n^2 d)$。 FAISS / Annoy / HNSW など近似最近傍 (ANN) で抑える必要がある。
❌ 大きさ情報を失う
cos は方向のみを見る。 「東京と京都は似た構造比だが規模が 10 倍違う」は cos=1 になり区別できない。 規模が重要なら Euclidean / Manhattan を併用。

⚠️ 落とし穴(コサイン類似度 5 件、 各 80-150 字)

  1. ゼロベクトルでのゼロ除算:いずれかのベクトルのノルムが 0 だと分母が 0 になり NaN。 sklearn の cosine_similarity は 0 を返すが、 numpy 自作実装は要チェック。 前処理で zero-norm 行を除外する。
  2. 高次元での「ほぼ全ペアが直交」:1000 次元以上の埋め込みではランダム 2 ベクトルの cos がほぼ 0 に集中する (次元の呪い)。 cos=0.1 でも統計的には十分高い可能性があるので、 絶対値より分布での順位を見る。
  3. 負値の混在で cos が負になる:z-score 化したベクトル同士の cos は -1〜1 に分布。 「類似度 = 高いほど近い」と思って negative を「正反対」と解釈すると、 単に平均からのズレ方が逆だったケースを見落とす。
  4. TF-IDF の重み付けを忘れる:raw count での cos は出現頻度の高い stop words が支配的に。 TF-IDF や BM25 で重み付け後に cos を取らないと「全文書が似ている」結果に。
  5. BERT 埋め込みでの cos 解釈:BERT の CLS token は cosine 類似度に最適化されていない。 SBERT (Sentence-BERT) や Contriever のように対照学習で cos 用に fine-tune したモデルを使う。 素の BERT は cos 計算には不向き。

🗺 概念マップ

「cosine similarity」を中心に、 前提となる内積・ノルム・ベクトル空間モデル、 並列の類似尺度 (ユークリッド距離・ピアソン相関・Jaccard 類似度)、 派生形 (ソフトコサイン・角距離)、 そして応用先 (TF-IDF 文書類似度・推薦システム・k-NN 検索) を放射状に整理した。

コサイン類似度 内積・ノルム ベクトル空間モデル TF-IDF (前段) ピアソン相関 (並列) ユークリッド距離 Jaccard 類似度 ソフトコサイン (派生) 角距離 (派生) k-NN・推薦 (応用)

コサイン類似度は、 ベクトル間の「向き」のみを比較する尺度で、 大きさ (norm) の影響を受けない点が特徴。 この概念マップは、 前提となる内積・ノルム・ベクトル空間モデルから、 並列のユークリッド距離・ピアソン相関・Jaccard 類似度、 発展形の重み付けコサイン・ソフトコサイン・角距離までを位置づける。 TF-IDF と組み合わせた文書類似度や、 word2vec 埋め込みの意味類似度算出での実用例が中心軸となる。

コサイン類似度の周辺には、 (a) 内積・ノルムというベクトル空間の前提、 (b) ユークリッド距離・ピアソン相関・Jaccard 類似度といった並列の類似尺度、 (c) ソフトコサイン (同義語反映)・重み付けコサイン・角距離などの派生形、 (d) TF-IDF・word2vec・BERT 等の埋め込み手法 (前段)、 (e) k-NN による近傍検索・クラスタリング・レコメンドエンジン (後段) が並ぶ。

文書類似度・推薦システム・検索ランキング・異常検知のいずれでも、 「ベクトル化の方法」と「コサインの解釈 (向きが何を意味するか)」を一対で押さえることが、 結果の妥当性を担保する鍵となる。

🔗 隣接手法への橋渡し

コサイン類似度は「ベクトルの方向のみ」を比較する性質ゆえ、 前処理で大きさ情報をどう扱うかで結果が大きく変わる。 本章では「接続 (どう繋がるか)」「統合 (どう組み合わせるか)」「比較 (どう使い分けるか)」の 3 視点で隣接手法を整理し、 実務での切替判断材料を提供する。

① 接続: コサイン類似度を駆動する周辺技術

コサイン類似度を活かすには、 入力ベクトル化と検索効率化の周辺技術が不可欠。 以下 5 件は実装上ほぼ必ず併用される。

② 統合: コサイン類似度を組み込んだワークフロー

コサインは単独で完結せず、 検索・推薦・分類パイプラインの中核ステップとして機能する。

パイプラインステップコサイン類似度の役割
セマンティック検索クエリ → BERT 埋め込み → 文書ベクトル DB との類似度ランキング → top-k 返却「意味的に近い文書」を方向の一致度で抽出 (語順や長さに左右されない)
レコメンドシステムユーザ嗜好ベクトル → アイテムベクトルとの類似度 → スコア降順で並べ替え → 提示嗜好の傾向 (方向) のみを比較し、 評価回数の多寡 (大きさ) を無視できる
重複検出 / 剽窃チェック文書 A・B を TF-IDF 化 → コサイン類似度 → 閾値 (例 0.85) 超で「類似」判定長さの違う文書同士でも公平に類似度を測れる

③ 比較: コサイン類似度 vs 隣接指標の使い分け判断

「ユークリッド距離やピアソン相関ではダメなのか」の判断基準。 実務で迷うポイントを整理。

状況コサイン類似度ユークリッド距離ピアソン相関
ベクトルの大きさを無視したい○ (方向のみ)× (大きさ込み)○ (中心化後の方向)
テキスト・スパースな高次元○ (定番)△ (次元の呪い)△ (中心化で密になる)
評価尺度の偏り (甘評価/辛評価) を補正× (生の評価を比較)×○ (平均を引いて補正)
位置情報がある (地図上の距離)×○ (定番)×
計算コスト低 (内積 + ノルム)低 (差の二乗和)中 (中心化が必要)

原則: 「ベクトルの長さに意味がない / 方向だけ知りたい」→ コサイン「物理的距離 / 大きさも考慮」→ ユークリッド「個人差バイアスを除去したい」→ ピアソン。 テキストや埋め込みではほぼコサイン一択。

🌳 手法選択フロー

コサイン類似度は方向の一致度を測る。 ベクトル化方式と検索規模に応じて使い分ける。

  1. ベクトルの大きさを無視したいか? Yes → コサイン類似度、 No → ユークリッド距離 を先に確認
  2. テキスト・高次元疎ベクトルか? Yes → TF-IDF、 No → 埋め込み を先に確認
  3. 最近傍検索で大規模化したいか? Yes → k-NN、 No → クラスタリング を先に確認

高次元疎データなら TF-IDF + コサイン、 密埋め込みなら内積、 大きさを比較したいならユークリッド距離、 と「無視したい情報」で選ぶ。

🧩 解説深化 — 直感・落とし穴・発展をもう一段

ここまでのセクションを踏まえ、 コサイン類似度の核心(向きだけを見る=スケール不変)と、 実務で必ずつまずく「大きさを捨てる副作用」を、 SSDSE-B-2026 の実測値で締めくくります。 既存セクションと重複しない補足として、 直感・落とし穴・発展の 3 つに分けて掘り下げます。

🎨 直感(一言で)— 内積を両ノルムで正規化した「向きメーター」

コサイン類似度は、 2 つのベクトルのなす角 $\theta$ の余弦そのものです。 定義 $\cos\theta = \dfrac{\mathbf{a}\cdot\mathbf{b}}{\|\mathbf{a}\|\,\|\mathbf{b}\|}$ は「内積を 2 本のノルムの積で割って正規化する」操作。 ノルムで割った瞬間に長さ(大きさ)の情報が消え、 向きだけが残るため、 スケールを 2 倍・10 倍しても値は動きません(スケール不変)。 これが「🎮 触って理解する」の "a を伸ばしても cos は変わらない" の正体です。

⚠️ 落とし穴(核心)— 大きさを捨てる副作用を SSDSE で体感する

コサイン最大の利点「スケール不変」は、 裏を返すと規模・頻度の差が丸ごと消えるという副作用です。 生の非負データではこれが致命的に効き、 まるで全県がそっくりに見えてしまいます。 下表は SSDSE-B-2026(2023 年・47 県)の 3 指標ベクトルを、 生データ列ごと z-スコア標準化の 2 通りで計算した実測コサイン類似度です。

県ペア(総人口・出生数・65歳以上人口の 3 次元)生データ cos(値域 0〜1)z-スコア化 cos(値域 -1〜1)
東京 と 大阪0.99890.9949
東京 と 沖縄0.9999−0.8851
東京 と 秋田0.9890−0.9987

読み方:生データでは 3 ペアとも cos ≈ 0.99〜1.00 で、 東京・沖縄・秋田がすべて「そっくり」に見える。 これは 3 指標がどれも総人口の大小に強く連動し、 一番大きい成分が内積を支配するため。 頻度・規模の差(=各県の個性)が向きに埋もれて消えているのが、 まさに「大きさを捨てる副作用」です。 列ごとに z-スコア化して規模を揃えると、 東京-沖縄が $-0.885$、 東京-秋田が $-0.999$ と負値に転じ、 人口構成プロファイルがむしろ逆方向だと分かります。

再現コード(上表を出力)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) 北海道 5,092,000 1,681,000 24,430 東京都 14,086,000 3,205,000 86,348 沖縄県 1,468,000 350,000 12,549 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
from scipy.stats import zscore

# 47 県 × 3 指標(総人口 A1101・出生数 A4101・65歳以上人口 A1303)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]).query('`SSDSE-B-2026` == 2023')
X = df[['A1101', 'A4101', 'A1303']].astype(float).values

raw = cosine_similarity(X)                  # 生データ(非負)→ 値域 0〜1
z   = cosine_similarity(zscore(X, axis=0))  # 列ごとに z-スコア化 → 値域 -1〜1

# Prefecture の並び順で東京=12, 大阪=26, 秋田=4, 沖縄=46
print('raw 東京-沖縄 =', round(raw[12, 46], 4))
print('z   東京-沖縄 =', round(z[12, 46], 4))

📤 実行結果:

raw 東京-沖縄 = 0.9999 z 東京-沖縄 = -0.8851

🚀 発展 — コサイン距離・正規化・ソフトコサイン・近似最近傍

より広い文脈は テキスト類似度、 前提の数学は ベクトル計算内積ノルム、 応用は 推薦システム の各ページへ。