このページ内のセクションへ素早く飛べます(クリックで該当箇所へジャンプ):
コサイン類似度 (Cosine Similarity) は 2 つのベクトルの角度の余弦で類似度を測る指標。 値域 $-1$〜$1$、 ベクトルの長さに依存せず方向だけを比べるので、 TF-IDF や埋め込みベクトルの類似度測定に最適です。
🍰 まずはやさしく
向きの似具合を測る定規のようなものです。
2つのデータの方向が近いか調べます。
おすすめの商品を探すときに使われます。
まずは結論と使い道を読みましょう。
2 つのベクトルの向きの近さを $-1$〜$+1$ で表す指標
🍰 まずはやさしく
ベクトルの角度で似ているかを見る指標です。
データの大きさに惑わされずに比較します。
長い記事と短い記事の似具合を測れます。
他の指標との違いについて読みましょう。
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 | (3.0, 1.0) |
| ベクトル b | (1.0, 3.0) |
| 長さ |a| | 3.16 |
| 長さ |b| | 3.16 |
| 内積 a·b | 6.00 |
| なす角 θ | 53.13° |
↑ 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)$$
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 本
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}") |
📤 実行結果:
💬 結果の読み方: 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-2026(47都道府県・2023 年・112 項目)を題材に、 コサイン類似度 に関係する変数を実値で確認します。 とくに東京・大阪・沖縄・秋田 など特徴ある県を比較すると、 用語の重みが体感できます。
| 都道府県 | 総人口(千人) | 高齢化率(%) | TFR | 消費支出(円/月) |
|---|---|---|---|---|
| 東京 | 14,086 | 22.8 | 0.99 | 341,320 |
| 大阪 | 8,763 | 27.7 | 1.19 | 271,246 |
| 沖縄 | 1,468 | 23.8 | 1.60 | 251,222 |
| 秋田 | 914 | 39.1 | 1.10 | 272,086 |
| 全国(総人口・高齢化率・TFR は全国値、 消費支出は 47 県平均) | 124,353 | 29.1 | 1.20 | 295,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}} $$
| 次元 i | $A_i$ | $B_i$ | $A_i B_i$ | $A_i^2$ | $B_i^2$ |
|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 4 | 1 |
| 2 | 3 | 5 | 15 | 9 | 25 |
| 3 | 4 | 2 | 8 | 16 | 4 |
| 合計 | — | — | 25 | 29 | 30 |
| 項目 | 計算 | 結果 |
|---|---|---|
| 内積 $\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 |
| 項目 | 計算 | 結果 |
|---|---|---|
| $\cos\theta$ | $25 / \sqrt{870}$ | 0.8475 |
| コサイン距離 $1-\cos\theta$ | $1 - 0.8475$ | 0.1525 |
| 角度 $\theta$ (参考) | $\arccos(0.8475)$ | 32.07° |
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}") |
💬 手計算 (Step 3 の 0.8475) と Python 出力 (numpy 手計算式・sklearn のいずれも 0.8475) が完全一致。 コサイン類似度 0.8475 は「向きがかなり揃っている (角度約 32°)」ことを示し、 2 ベクトルは同じ傾向にある成分構成と読める。
説明用の合成データとして、 2 つの対象を 3 指標でベクトル化し、 コサイン類似度を 1 ステップずつ手計算します。 数値の絶対値ではなく 3 指標のバランスがどれだけ似ているかを測る用途です。
対象 2 つの 3 次元ベクトル(規模の大きい対象 T と中規模の対象 O):
Step 1〜3 で内積・ノルム・cos を求める:
→ 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 に近く、 「向きの類似」を測る指標であることが直感できます。
以下は コサイン類似度 を SSDSE-B-2026 で扱うときの典型コード。 encoding='cp932' は政府統計の Shift-JIS 対応。 skiprows=[1] は 2 行目の日本語ヘッダ行だけをスキップして列コード(A1101 等)を列名に使う定石(skiprows=1 だと 1 行目の列コード行が消え、 日本語ラベルが列名になる)。
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()) # 日本語読みなので '都道府県' |
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) |
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()) |
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 '有意差なし') |
※ より高度な例(クロス集計、 機械学習、 ベイズ推定)は text-similarity のグループ教材を参照。
SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:
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()) # 「コサイン類似度」の文脈で扱う場合の例: # 分野: 類似度・距離指標 # 関連手法は同カテゴリの他用語を参照してください。 |
具体的なコードは テキスト類似度グループ教材 を参照してください。
分析結果を報告するときに含めるべき情報:
🎯 このコードでやること:各県を「総人口・出生数・65 歳以上人口」の 3 次元ベクトルとして表現し、 全 47 県ペアのコサイン類似度行列を構築する。 人口構成 (構成比) が近い県ほど cos が 1 に近づく。
📥 入力データ:SSDSE-B-2026 の実在列コード 3 本。 規模 (絶対人数) ではなく「方向 (構成比)」を測る点が cos の本質。
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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:出力は 47×47 の行列で、 対角成分は必ず 1.0(自分自身とは同方向)。 3 指標がすべて非負なので値は 0〜1 に収まり、 人口構成の近い県ペアほど 1 に近づく。 具体的な県ペアの cos は手元のデータで実行して確かめよう。 規模差そのものを見たい場合は 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 で同値)') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:差分は浮動小数の丸め誤差レベル ($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 を中心化すると相関、 中心化しないと「方向の一致」になる。 推薦システムでユーザー平均評価を引いてから 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}') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:総人口・出生数のような SSDSE の生の非負・規模列は、 3〜80 次元のいずれでも cos の中央値が 0.98〜1.00 とほぼ 1 に張り付く(大きい成分が内積を支配するため)。 列を増やすと一部ペアで値が下がり始める($d$=80 で min が 0.429 まで低下)が、 中央値は依然 1 近くで、 全体として似すぎて判別力が乏しい。 実務では z-スコア標準化や TF-IDF / IDF 重み付け、 PCA / Truncated SVD による次元削減を挟んでから cos を測るのが定石。
コサイン類似度 に取り組むときに、 学生・実務者・研究者がよく踏むワナをまとめました。 該当しそうな項目があれば、 自分の分析を見直してみてください。
norm < eps をフィルタする。コサイン類似度(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)から始め、 そこから コサイン類似度 のような個別用語にドリルダウンしていくのが効率的です。
cosine_similarity は 0 を返すが、 numpy 自作実装は要チェック。 前処理で zero-norm 行を除外する。「cosine similarity」を中心に、 前提となる内積・ノルム・ベクトル空間モデル、 並列の類似尺度 (ユークリッド距離・ピアソン相関・Jaccard 類似度)、 派生形 (ソフトコサイン・角距離)、 そして応用先 (TF-IDF 文書類似度・推薦システム・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) 超で「類似」判定 | 長さの違う文書同士でも公平に類似度を測れる |
「ユークリッド距離やピアソン相関ではダメなのか」の判断基準。 実務で迷うポイントを整理。
| 状況 | コサイン類似度 | ユークリッド距離 | ピアソン相関 |
|---|---|---|---|
| ベクトルの大きさを無視したい | ○ (方向のみ) | × (大きさ込み) | ○ (中心化後の方向) |
| テキスト・スパースな高次元 | ○ (定番) | △ (次元の呪い) | △ (中心化で密になる) |
| 評価尺度の偏り (甘評価/辛評価) を補正 | × (生の評価を比較) | × | ○ (平均を引いて補正) |
| 位置情報がある (地図上の距離) | × | ○ (定番) | × |
| 計算コスト | 低 (内積 + ノルム) | 低 (差の二乗和) | 中 (中心化が必要) |
原則: 「ベクトルの長さに意味がない / 方向だけ知りたい」→ コサイン、 「物理的距離 / 大きさも考慮」→ ユークリッド、 「個人差バイアスを除去したい」→ ピアソン。 テキストや埋め込みではほぼコサイン一択。
コサイン類似度は方向の一致度を測る。 ベクトル化方式と検索規模に応じて使い分ける。
高次元疎データなら 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-B-2026(2023 年・47 県)の 3 指標ベクトルを、 生データと列ごと z-スコア標準化の 2 通りで計算した実測コサイン類似度です。
| 県ペア(総人口・出生数・65歳以上人口の 3 次元) | 生データ cos(値域 0〜1) | z-スコア化 cos(値域 -1〜1) |
|---|---|---|
| 東京 と 大阪 | 0.9989 | 0.9949 |
| 東京 と 沖縄 | 0.9999 | −0.8851 |
| 東京 と 秋田 | 0.9890 | −0.9987 |
読み方:生データでは 3 ペアとも cos ≈ 0.99〜1.00 で、 東京・沖縄・秋田がすべて「そっくり」に見える。 これは 3 指標がどれも総人口の大小に強く連動し、 一番大きい成分が内積を支配するため。 頻度・規模の差(=各県の個性)が向きに埋もれて消えているのが、 まさに「大きさを捨てる副作用」です。 列ごとに z-スコア化して規模を揃えると、 東京-沖縄が $-0.885$、 東京-秋田が $-0.999$ と負値に転じ、 人口構成プロファイルがむしろ逆方向だと分かります。
norm < eps の行を除外します。再現コード(上表を出力):
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)) |
📤 実行結果: