論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
エンベディング
Embedding
NLP
別称: 分散表現 / 埋め込み

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

本ページで扱う中心概念をワンタッチで辿れるよう、 主要キーワードをチップ化しています。 NLP の語ベクトル、 意味類似度、 推薦システム、 高次元可視化 (t-SNE/UMAP)、 そして「埋め込みは距離の言語」というメタファーに繋がります。

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

💡 30秒で分かる結論

🍰 まずはやさしく

言葉を数字の列に置き換える地図のようなものです。

意味が似ているものを近くにまとめるために使います。

スマホの検索で似た言葉が見つかる仕組みに似ています。

この章では結論から短くポイントを解説します。

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

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

🍰 まずはやさしく

データの扱い方を決めるための道しるべです。

分析や予測をスムーズに行うために使います。

部活のメンバーを特徴ごとに分ける作業に似ています。

この章では他の技術とのつながりを説明します。

「埋め込み」は自然言語処理 → 表現学習 → ベクトル空間モデルの系譜に位置します。 統計学側からは 主成分分析 (PCA) や 多次元尺度法 (MDS) の延長として捉えるとスムーズです。 機械学習の前処理 (エンコーディング・one-hot) の発展系であり、 後段の分類・回帰・クラスタリング・検索すべてに供給される万能な特徴量と理解してください。

上位概念本ページ下位の応用
表現学習 / 特徴量設計埋め込み意味検索・推薦・クラスタリング
ベクトル空間モデルcosine 類似度の利用FAQ マッチング・FAISS
PCA / MDS高次元 → 低次元UMAP / t-SNE 可視化

🎨 直感で掴む

🍰 まずはやさしく

言葉の意味を数値で捉える感覚的な技術です。

計算機に言葉のニュアンスを伝えるために使います。

買い物で好みの商品を提案される仕組みに似ています。

この章では使い方のコツや注意点を解説します。

🎨 直感で掴む(深掘り)

埋め込みのメタファーは「意味の地図」です。 北海道と青森は地理的に近い、 東京と大阪は経済的に近い、 沖縄と鹿児島は気候的に近い —— こうした多面的な近さを 1 つの座標系で表現するのが埋め込みの役割です。 one-hot エンコーディング(47 次元、 1 つだけ 1)では すべての都道府県が等距離になり、 北海道と青森の近さも、 北海道と沖縄の遠さも区別できません。 埋め込みは、 大量のテキストや行動ログから共起情報を学習することで、 この「距離の意味」を獲得します。

word2vec の king - man + woman ≈ queen という有名な例は、 ベクトル演算が意味演算として機能することを示しました。 同様に「東京 - 関東 + 関西 ≈ 大阪」という関係が、 都道府県埋め込みでも観測できるはずです。 重要なのは「距離 = 意味的近さ」という暗黙の仮定が、 学習データの質と量によって担保されるという点です。

3 つの主要な系譜があります: (1) 静的埋め込み(word2vec, GloVe, fastText)。 単語に 1 ベクトル。 (2) 文脈埋め込み(BERT, GPT)。 文脈ごとに動的に生成。 (3) 文・文書埋め込み(Sentence-BERT, OpenAI text-embedding-3)。 文全体を 1 ベクトル化し、 意味検索 (semantic search) や RAG の基盤になります。

📐 定義

🍰 まずはやさしく

言葉などのデータを数値の束に変換する定義です。

正しく分析を行うための共通ルールとして使います。

テストの点数をグラフにまとめる作業に似ています。

この章では詳しい定義や数式の意味を解説します。

離散要素を実数ベクトルに変換した表現

英語名 Embedding。 同義・関連語:分散表現, 埋め込み。

📐 数式・定義(深掘り)

埋め込み行列 $E \in \mathbb{R}^{V \times d}$ は語彙サイズ $V$、 埋め込み次元 $d$ を持ち、 トークン $i$ の埋め込みは $E$ の $i$ 行目 $\mathbf{e}_i \in \mathbb{R}^d$ である。

$$\mathbf{e}_i = E_{i,:}, \quad E \in \mathbb{R}^{V \times d}$$

2 つのベクトル間の cosine 類似度は内積を両者の L2 ノルムで割って正規化したもの:

$$\mathrm{cosine}(\mathbf{u}, \mathbf{v}) = \frac{\mathbf{u} \cdot \mathbf{v}}{\|\mathbf{u}\|_2 \, \|\mathbf{v}\|_2} = \frac{\sum_{k=1}^{d} u_k v_k}{\sqrt{\sum_k u_k^2} \, \sqrt{\sum_k v_k^2}}$$

word2vec の Skip-gram は中心語 $w_t$ から周辺語 $w_{t+j}$ を予測する目的関数を最大化する:

$$\mathcal{L}_{\text{SG}} = \frac{1}{T} \sum_{t=1}^{T} \sum_{-c \le j \le c, j \ne 0} \log p(w_{t+j} \mid w_t), \quad p(w_O \mid w_I) = \frac{\exp(\mathbf{v}'_{w_O} \cdot \mathbf{v}_{w_I})}{\sum_{w=1}^{V} \exp(\mathbf{v}'_w \cdot \mathbf{v}_{w_I})}$$

🔬 数式を言葉で読み解く

埋め込み行列 $E$ の読み方: $E$ は「語彙 $V$ 行 × 次元 $d$ 列」の大きな表。 $i$ 行目を取り出すという操作 $E_{i,:}$ は、 one-hot ベクトル $\mathbf{x}_i$ との行列積 $\mathbf{x}_i E$ と等価で、 ニューラルネットワークの最初の線形層がそのまま埋め込み層になっています。

cosine 類似度の読み方: 分子の内積 $\mathbf{u} \cdot \mathbf{v} = \sum u_k v_k$ は「2 つのベクトルが同じ向きにどれだけ振れているか」の総量。 分母 $\|\mathbf{u}\|_2 \|\mathbf{v}\|_2$ で割ることで、 ベクトルの長さの違いを無視し、 純粋な向き(角度)だけを比べます。 結果は $[-1, 1]$ の範囲で、 $1$ が完全一致、 $0$ が無関係(直交)、 $-1$ が真逆の意味を表します。

Skip-gram の数式を言葉で読み解く: 外側の和はコーパス内の全位置 $t$ を走査。 内側の和は中心語 $w_t$ の左右各 $c$ 語を予測対象とする。 各予測 $p(w_{t+j} \mid w_t)$ は softmax で「全語彙の中でその語が選ばれる確率」を計算。 学習は 「実際に共起した語ペアの内積を大きく、 そうでないペアを小さく」 という単純な原理に集約されます。 計算量 $O(V)$ を避けるため、 実装では負例サンプリング(negative sampling)が使われます。

🧮 実値で計算してみる(SSDSE-B-2026 都道府県)

SSDSE-B-2026 から 47 都道府県の数値特徴(総人口・出生数・面積等)を取り出し、 各都道府県を 4 次元の数値埋め込みに変換して cosine 類似度を計算してみましょう。 ここでは「埋め込みは事前学習モデルに限らず、 特徴量の正規化ベクトル一般を指す」という広義の理解を掴むのが狙いです。

都道府県総人口(千人)出生数合計特殊出生率
北海道5,09224,4301.06
東京都14,08686,3480.99
大阪府8,76355,2921.19
沖縄県1,46812,5491.60

各特徴を z-score で標準化(平均 0、 標準偏差 1)し、 4 つの数値特徴で 4 次元ベクトルとしたとき、 北海道と沖縄の cosine 類似度を手計算してみます。 標準化後の値を仮に 北海道 = [-0.05, -0.45, -1.02, -1.30]、 沖縄 = [-0.78, -0.85, -1.32, +2.10] としたとき:

内積 = (-0.05)(-0.78) + (-0.45)(-0.85) + (-1.02)(-1.32) + (-1.30)(+2.10)
   = 0.039 + 0.383 + 1.346 + (-2.730) = -0.962
||北海道|| = √(0.0025 + 0.2025 + 1.0404 + 1.6900) = √2.9354 = 1.713
||沖縄||  = √(0.6084 + 0.7225 + 1.7424 + 4.4100) = √7.4833 = 2.736
cosine = -0.962 / (1.713 × 2.736) = -0.962 / 4.687 = -0.205

→ この例示値では北海道と沖縄は cosine ≈ -0.2。 出生率の正負と人口規模の負の効果で、 ベクトルとしては逆方向を向いていることが分かります。 つまり「人口少なくて出生率が高い沖縄」と「人口中規模で出生率の低い北海道」は意味空間で離れている、 という解釈になります。 なお、 SSDSE-B-2026(2023 年)の実際の標準化値で同じ計算をすると cosine = −0.90 となり、 逆方向の傾向はさらに強く現れます(手計算用の上の値は説明のための簡略化した例示値です)。

🧮 数式に値を入れて手で計算する: 語ベクトルの類推

合成 3D 埋め込みで "king - man + woman ≈ queen" を確認する。

Step 1: 仮定ベクトル

king = [0.7, 0.5, 0.8] man = [0.6, 0.4, 0.2] woman = [0.5, 0.3, 0.1] queen = [0.6, 0.4, 0.7]

Step 2: ベクトル演算

king - man + woman = [0.7-0.6+0.5, 0.5-0.4+0.3, 0.8-0.2+0.1] = [0.6, 0.4, 0.7] queen = [0.6, 0.4, 0.7] → 一致!

🐍 Python で再現

1
2
3
4
5
6
7
8
9
import numpy as np
king  = np.array([0.7, 0.5, 0.8])
man   = np.array([0.6, 0.4, 0.2])
woman = np.array([0.5, 0.3, 0.1])
queen = np.array([0.6, 0.4, 0.7])
result = king - man + woman
print(f"king - man + woman = {result}")
print(f"queen = {queen}")
print(f"一致: {np.allclose(result, queen)}")

📤 実行結果

king - man + woman = [0.6 0.4 0.7] queen = [0.6 0.4 0.7] 一致: True

💬 手計算 (Step 2) と Python 出力が完全一致。

🐍 Python での扱い

🔗 同カテゴリの他用語

自然言語処理形態素解析単語分割n-gramTF-IDF文章間類似度機械翻訳文章生成知識グラフかな漢字変換n-gram モデル自然言語処理

🐍 応用コード — SSDSE の数値 109 列を 47 県の値ベクトルとして埋め込み、 出生率に近い列を探す

SSDSE 公的データを題材に、 埋め込み を実際に動かす最小コードです。 paths は引数に直書きで、 初心者がコピペで動かせる形を優先しています。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 SSDSE-B-2026(年度) A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) 北海道 2,023 5,092,000 514,000 1,681,000 24,430 東京都 2,023 14,086,000 1,513,000 3,205,000 86,348 沖縄県 2,023 1,468,000 236,000 350,000 12,549 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import pandas as pd
import numpy as np

# データ読み込み(SSDSE-B 都道府県・47 県 × 約 112 列)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
df = df[df['年度'] == 2023].reset_index(drop=True)
print('shape:', df.shape)
print('列の先頭:', df.columns.tolist()[:6])

# 必要な列だけ取り出して整形
features = ['総人口', '15歳未満人口', '65歳以上人口', '出生数']
df_use = df[features].copy()
print(df_use.describe())
📤 実行例(実測) shape: (47, 112) 列の先頭: ['年度', '地域コード', '都道府県', '総人口', '総人口(男)', '総人口(女)'] 総人口 15歳未満人口 65歳以上人口 出生数 count 4.700000e+01 4.700000e+01 4.700000e+01 47.000000 mean 2.645809e+06 3.015106e+05 7.708298e+05 15473.808511 std 2.797551e+06 3.120203e+05 6.938393e+05 17155.475476 min 5.370000e+05 6.500000e+04 1.790000e+05 3263.000000 25% 1.034000e+06 1.135000e+05 3.505000e+05 5472.000000 50% 1.549000e+06 1.970000e+05 5.240000e+05 9524.000000 75% 2.636500e+06 2.935000e+05 7.890000e+05 14390.000000 max 1.408600e+07 1.513000e+06 3.205000e+06 86348.000000

💬 2023 年度に絞って 47 行になった。総人口の平均 264.6 万人に対し中央値は 154.9 万人と大きく離れ、最大 1,408.6 万人(東京都)が平均を引き上げている右に歪んだ分布。出生数も平均 15,474 人・中央値 9,524 人で同じ形をしている。埋め込みや距離計算にこのまま入れると東京都ひとつが距離を支配するので、対数変換や標準化を先に考える。

次に、 埋め込み に固有の処理を加えます。 ここがページごとの「肝」になる部分。

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
27
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score

# 列の埋め込み: 数値 109 列それぞれを「47 県の標準化値を並べた 47 次元ベクトル」とみなす
num = df.select_dtypes('number').drop(columns=['年度'])
E = ((num - num.mean()) / num.std()).T          # 行 = 列名(109 行 × 47 次元)
target = '合計特殊出生率'
norm = np.linalg.norm(E.values, axis=1)
cos = E.values @ E.loc[target].values / (norm * norm[E.index.get_loc(target)])
near = pd.Series(cos, index=E.index).drop(target).sort_values(ascending=False)
print('出生率に向きが近い列:')
print(near.head(3).round(3).to_string())

# 近い 3 列を特徴量にして出生率を予測する
feats = near.head(3).index.tolist()
X = df[feats].values
y = df[target].values

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0)
model = RandomForestRegressor(n_estimators=200, max_depth=4, random_state=0).fit(X_tr, y_tr)

pred_tr = model.predict(X_tr)
pred_te = model.predict(X_te)
print(f'train R^2 = {r2_score(y_tr, pred_tr):.3f}')
print(f'test  R^2 = {r2_score(y_te, pred_te):.3f}')
print(f'test RMSE = {np.sqrt(mean_squared_error(y_te, pred_te)):.4f}')
📤 実行例(実測) 出生率に向きが近い列: 最低気温(日最低気温の月平均の最低値) 0.532 降水量(年間) 0.528 年平均気温 0.502 train R^2 = 0.827 test R^2 = -0.040 test RMSE = 0.1187

💬 109 列をそれぞれ 47 次元のベクトルにして cos を取ると、合計特殊出生率に最も向きが近いのは最低気温 0.532・降水量 0.528・年平均気温 0.502 で、沖縄県 1.60・長崎県と宮崎県 1.49 のように暖かく雨の多い九州・沖縄ほど出生率が高い傾向を拾っている。標準化した列どうしの cos は相関係数そのものなので、「最も近い列」でも相関 0.5 程度にとどまる。この 3 列で学習すると訓練 R² 0.827 に対してテスト 15 県は −0.040 で平均値で当てるより悪く、テスト RMSE 0.119 もテスト 15 県の標準偏差 0.116 を上回る。

さらに可視化を加えると、 学んだ内容が「眼で」確認できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import matplotlib.pyplot as plt

plt.figure(figsize=(7,5))
plt.scatter(y_te, pred_te, alpha=0.7, edgecolor='k')
lims = [min(y_te.min(), pred_te.min()), max(y_te.max(), pred_te.max())]
plt.plot(lims, lims, 'r--', linewidth=2, label='完全予測ライン')
plt.xlabel('実測 出生率')
plt.ylabel('予測 出生率')
plt.title('埋め込み を使ったモデルの予測精度(SSDSE-B-2026)')
plt.legend()
plt.tight_layout()
plt.savefig('out_embedding.png', dpi=150)
📤 実行例(実測) このブロックは標準出力を出さない(図を描く・変数を定義するだけ)。

最後に、 同じ問題を別の角度から見る「クロスバリデーション版」も用意します。

1
2
3
4
5
6
7
8
9
10
from sklearn.model_selection import cross_val_score, KFold

# 県は北から順に並んでいるので、shuffle なしだと fold が地域の塊になる → 混ぜてから分ける
cv = KFold(n_splits=5, shuffle=True, random_state=0)
scores = cross_val_score(
    RandomForestRegressor(n_estimators=200, max_depth=4, random_state=0),
    X, y, cv=cv, scoring='r2'
)
print(f'5-fold CV R^2 = {scores.mean():.3f} (±{scores.std():.3f})')
print('各 fold:', np.round(scores, 3))
📤 実行例(実測) 5-fold CV R^2 = 0.240 (±0.244) 各 fold: [-0.029 0.427 0.551 -0.06 0.31 ]

💬 県をシャッフルしてから 5 分割すると平均 R² は 0.240 だが、fold ごとに −0.060〜0.551 と大きくばらつく。shuffle なしの KFold では fold が北海道〜群馬県のような地域の塊になり、気温・降水量の範囲が訓練とテストで重ならないため平均 −2.64 まで崩れる。shuffle ありでも random_state を 1〜4 に変えると平均は 0.128・0.101・−0.037・−0.062 と動き、1 fold 9〜10 県の評価は分割の運に大きく左右される。気候 3 列だけでは出生率の県差の 2 割程度しか安定して説明できない。

🐍 Python 実装(深掘り)

① SSDSE-B-2026 から都道府県の「数値埋め込み」を作る

🎯 このコードでやること:SSDSE-B-2026 から 47 都道府県の総人口・出生数・出生率・65 歳以上人口を取り出し、 z-score で標準化して 4 次元の数値埋め込みを作る。

📥 入力データ(SSDSE-B-2026 の関連列):

都道府県 総人口 出生数 合計特殊出生率 65歳以上人口 0 北海道 5092000 24430 1.06 1681000 1 青森県 1184000 5696 1.23 417000 2 岩手県 1163000 5432 1.16 407000 ... 46 沖縄県 1468000 12549 1.60 350000
1
2
3
4
5
6
7
8
9
10
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True)  # 2023年のみ(年混在を防ぐ)
cols = ['A1101', 'A4101', 'A4103', 'A1303']  # 総人口 出生数 出生率 65歳以上
X = df[cols].values.astype(float)
Z = (X - X.mean(axis=0)) / X.std(axis=0)
emb = pd.DataFrame(Z, index=df['Prefecture'], columns=cols)
print(emb.loc[['北海道', '東京都', '大阪府', '沖縄県']].round(3))

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

A1101 A4101 A4103 A1303 Prefecture 北海道 0.884 0.528 -1.766 1.326 東京都 4.134 4.176 -2.297 3.546 大阪府 2.210 2.346 -0.780 2.408 沖縄県 -0.426 -0.172 2.331 -0.613

💬 結果の読み方:標準化後、 東京は人口・出生数・65 歳以上人口で +3.5〜+4.2σ と突出、 沖縄は出生率(A4103)で +2.3σ と突出。 規模系の列すべてで「東京」が外れ値となるが、 「沖縄」は出生率だけが他から大きく離れている。 ベクトルとしては東京と沖縄は異なる方向を向き、 cosine 類似度は低くなる。

② sklearn で cosine 類似度行列を作る

🎯 このコードでやること:標準化済みベクトル Z から 47×47 の cosine 類似度行列を作り、 北海道に最も意味的に近い 5 県を抽出する。

📥 入力データ:① で作った 47 行 × 4 列の Z 行列(標準化済み数値埋め込み)。

1
2
3
4
5
6
from sklearn.metrics.pairwise import cosine_similarity

sim = cosine_similarity(Z)
sim_df = pd.DataFrame(sim, index=df['Prefecture'], columns=df['Prefecture'])
top5 = sim_df.loc['北海道'].drop('北海道').sort_values(ascending=False).head(5)
print(top5.round(3))

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

Prefecture 静岡県 0.947 千葉県 0.921 埼玉県 0.881 茨城県 0.856 神奈川県 0.835 Name: 北海道, dtype: float64

💬 結果の読み方:北海道に最も近いのは静岡・千葉・埼玉・茨城・神奈川 — 地理的な隣県(東北)ではなく、 人口規模が中〜大きめで低出生率・高齢化が進む県が上位に並ぶ。 この 4 次元埋め込みは規模系の特徴(総人口・出生数・65 歳以上人口)に強く支配されるため、 「何を特徴量に選ぶかで『近さ』の意味が決まる」という埋め込みの本質がよく分かる結果になっている。

③ PCA で 4 次元 → 2 次元に圧縮して可視化

🎯 このコードでやること:4 次元の数値埋め込みを PCA で 2 次元に落とし、 散布図にすることで「都道府県意味地図」を視覚化する。

📥 入力データ:標準化済み 47×4 の Z。 PCA は分散最大の軸を順に選ぶ線形写像。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA(n_components=2)
P = pca.fit_transform(Z)
print('寄与率:', pca.explained_variance_ratio_.round(3))
plt.figure(figsize=(8, 6))
plt.scatter(P[:, 0], P[:, 1], alpha=0.7)
for i, pref in enumerate(df['Prefecture']):
    plt.annotate(pref, (P[i, 0], P[i, 1]), fontsize=8)
plt.xlabel('PC1'); plt.ylabel('PC2'); plt.tight_layout()

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

寄与率: [0.841 0.154] (散布図: 東京・大阪など大都市圏が片側に、 沖縄が出生率軸方向に離れ、 小規模県が密集)

💬 結果の読み方:PC1(人口規模軸)と PC2(出生率軸)で 99.5% の分散を説明。 東京は PC1 で突出、 沖縄は PC2 で突出。 残り 47 県の散らばりが「縮約された埋め込み空間」の地図になる。

④ sentence-transformers で県名テキスト埋め込み(概念デモ)

🎯 このコードでやること:sentence-transformers の事前学習モデル(多言語対応)に都道府県名を入力し、 384 次元のテキスト埋め込みを取得 → cosine 類似度を比較する。

📥 入力データ:47 都道府県名の文字列リスト(['北海道', '青森県', ..., '沖縄県'])。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
prefs = df['Prefecture'].tolist()
vecs = model.encode(prefs)  # shape (47, 384)
sim = cosine_similarity(vecs)
idx = prefs.index('北海道')
order = sim[idx].argsort()[::-1][1:6]
for j in order:
    print(f'{prefs[j]:8} {sim[idx, j]:.3f}')

📤 実行すると次の出力が得られる(実測:キャッシュ済みの paraphrase-multilingual-MiniLM-L12-v2 で実行):

沖縄県 0.806 宮崎県 0.804 福島県 0.769 香川県 0.761 山形県 0.759

💬 結果の読み方:北海道に最も近いのは沖縄県 0.806・宮崎県 0.804 で、東北の隣県は山形県 0.759 が 5 位に入るだけ。数値埋め込み(②)が規模の近い静岡・千葉を返したのとも、地理的な近さとも一致しない。46 県との類似度は最も低い三重県でも 0.592 と全体が高めに寄っていて、上位の差は 0.05 程度しかないので、県名という短い文字列だけでは順位にほとんど意味が乗らない。テキスト埋め込みで「近さ」を測るなら、県の特徴を説明した文章を入れるなど入力側を工夫する必要がある。

⑤ ベクトル演算: 「東京 - 関東 + 関西 ≈ ?」

🎯 このコードでやること:4 次元の数値埋め込みで「東京から関東代表性を引いて関西代表性を足す」と何になるかを実験する。 word2vec の king - man + woman ≈ queen の都道府県版。

📥 入力データ:標準化済み emb から都道府県ベクトルを抽出。

1
2
3
4
5
6
v_tokyo = emb.loc['東京都'].values
v_kanto = emb.loc[['神奈川県', '埼玉県', '千葉県']].mean().values
v_kansai = emb.loc[['兵庫県', '京都府', '奈良県']].mean().values
v_target = v_tokyo - v_kanto + v_kansai
dists = emb.apply(lambda r: np.linalg.norm(r.values - v_target), axis=1)
print(dists.sort_values().head(3))

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

Prefecture 神奈川県 0.813390 大阪府 1.199628 埼玉県 1.480803 dtype: float64

💬 結果の読み方:最上位は神奈川県(東京と規模構造が近すぎるため、 引き算しても関東色が残る)だが、 2 位に大阪府が入る。 「関東のリーダー」→「関西のリーダー」というアナロジーが、 4 次元の数値埋め込みでも部分的に成立することが分かる。 word2vec のアナロジーでも入力語近傍が混ざるのは既知の現象で、 実務では入力語(とその近傍)を除外して評価することが多い。

⚠️ よくある落とし穴

❌ トークン化の影響
日本語は分かち書きが必要。 サブワード(BPE/WordPiece)と相性。
❌ 多言語
言語ごとに前処理が違う。
❌ プロンプトインジェクション
LLM 利用時はユーザー入力の検証を。

⚠️ 落とし穴(5 件、 各 80-150 字)

  1. バイアスの継承:埋め込みは学習データの偏見(性別・人種・職業ステレオタイプ)を内包する。 「nurse - woman + man ≈ doctor」のような問題が報告済。 監査・debias 後処理 (Bolukbasi 2016 等) が必須。
  2. 次元の呪い:高次元(>100)では「すべてのベクトル間距離がほぼ等しく」なる現象が起き、 cosine 類似度の識別力が低下する。 d を下げる、 標準化、 球面正規化を併用する。
  3. OOV(語彙外)問題:word2vec/GloVe は学習語彙外の単語をベクトル化できない。 fastText(部分語)や BPE、 BERT(サブワード)で緩和されるが、 未知語は依然として未解決領域。
  4. t-SNE / UMAP の誤読:高次元から 2D に落とした図は近傍関係は保つが距離は保たない。 「クラスタ間の距離」「クラスタの大きさ」を意味のあるものとして解釈してはならない。
  5. cosine vs Euclidean の混同:埋め込みベクトルが L2 正規化されていないと、 cosine 類似度と Euclidean 距離は別の順位を返す。 「sim 算出前に必ず normalize」が定石。

🗺 用語マインドマップ — 周辺概念の整理

「埋め込み」を中央に置いて、 周辺概念を 5 つの方向に整理します。 これは記憶の足場になります。

方向隣接概念関係性
北 (上位)表現学習・特徴量設計高次元データを低次元密ベクトルに写す技法群の総称
南 (下位)RAG・推薦・類似検索埋め込み + cosine 類似度で実装する代表的応用
東 (発展)Sentence-BERT / CLIP / マルチモーダルテキスト・画像・音声を同一空間に統合する拡張
西 (前提)One-hot エンコーディング / TF-IDF疎ベクトル表現。 埋め込みが解決した「次元の呪い」「同義性の欠如」の出発点
中央埋め込み (Embedding)意味的類似が距離として現れる低次元密ベクトル空間への写像

マインドマップは「学んだ用語を整理する道具」として優秀。 紙にこの 5 方向を書き、 自分なりの隣接概念を埋めると、 暗黙的にあった理解構造が可視化されます。

埋め込み (Embedding) Transformer 類似度計算 トークン化 Word2Vec BERT

🔗 隣接手法への橋渡し

エンベディングは単独の表現ではなく、 離散カテゴリ ・テキスト ・グラフを密ベクトル空間に写す表現学習の総称である。 Word2Vec ・BERT ・GNN など派生手法と、 類似検索 ・分類 ・生成 AI の下流タスクと一体で設計する。

エンベディングは「高次元・離散な対象を密ベクトルに埋め込む」表現学習で、 上流のトークナイズ・カテゴリ整理が品質を決め、 並列の Word2Vec・BERT・グラフ埋め込みのいずれが目的に合うかを選び、 下流の類似検索・分類・生成 AI で再利用する。

🌳 手法選択フロー

エンベディングを使うかは「対象データの離散性・類似性検索の有無・下流タスクの種類」の 3 軸で決まる。 自然言語・カテゴリ・グラフのいずれかが主体で、 類似検索や生成が下流にあれば必須。

  1. 何を近さと呼ぶのか
    意味が近い、 一緒に出現する、 同じ利用者が使う — 何を「近い」とするかで学習方法が変わる。 この定義が曖昧なままだと、 出来上がった空間の評価もできない。
  2. 自分で学習するか、 既存を使うか
    一般的な語なら学習済み埋め込みで足りる。 専門用語や社内語彙が中心なら、 自分のデータで追加学習する。
  3. 何次元にするか
    次元が大きいほど表現力は上がるが、 データが少ないと過学習し、 距離も 0 付近に集中する。 下流タスクの性能で選ぶ。
  4. 距離の測り方は
    長さの影響を除きたいならコサイン類似度、 大きさも意味を持つなら内積。 閾値はそのデータの分布を見てから決める。

SSDSE-B-2026 で 47 都道府県を人口・出生・気候などの数値列ベクトルから埋め込むと、 東京など大都市圏と沖縄が外れ位置、 中小規模県が密集する 2 次元配置が得られ、 地域類似性の可視化と政策グルーピングに活用できる(産業別就業者構成で埋め込みたい場合は SSDSE-A / E 系のデータを使う)。

🎮 触って理解する

埋め込みとは「意味を座標に変換する」技術です。 下の 2 つの実験で、 「近さ=意味の近さ」と「ベクトルの引き算=意味の引き算」を手で動かして体感してください。 すべてお使いの端末の中だけで計算しており、 通信は一切行いません。

実験1: 意味の地図をドラッグして類似度を見る

6 つの単語を 2 次元の埋め込み空間に配置しています。 点をドラッグして動かし、 下の 2 つのプルダウンで選んだ単語ペアの コサイン類似度(向きの近さ)と ユークリッド距離(位置の近さ)がリアルタイムに変わる様子を確かめてください。 初期配置では「動物」「乗り物」「都市」が 3 つの塊(クラスタ)になっています。

原点 (0,0) を中心とした座標。 各単語のベクトルは原点からの矢印で表されます。 選択中の 2 単語は色付きの矢印で強調されます。

コサイン類似度 cos(A,B)
–
+1 =同じ向き(意味が近い) / 0 =無関係 / −1 =逆向き
ユークリッド距離 |A−B|: –
A=(–, –) B=(–, –)

実験2: ベクトル演算でアナロジー(王 − 男 + 女 ≈ 女王)

埋め込みの最も驚くべき性質は、 意味の引き算・足し算がベクトル演算で書けることです。 あらかじめ用意した固定の埋め込みを使い、 A − B + C を計算して、 その結果に最も近い単語を自動で探します。 初期設定 王 − 男 + 女 は 女王 を指し示します。

★ が計算結果 A−B+C の位置。 破線の平行四辺形が「A→B と C→結果 が同じ方向」であることを示します。

− +
計算結果に最も近い単語
–
–
近い順の候補:

    🧠 もう一段深く理解する

    🎯 直感

    意味の近さを距離や角度で表すのが埋め込みの本質です。 実験1 で分かる通り、 コサイン類似度は「原点から見た向き」を、 ユークリッド距離は「位置そのもの」を測ります。 埋め込みでは向き(コサイン)を使うのが標準で、 ベクトルの長さ(=出現頻度などの影響)を打ち消せるためです。

    ⚠️ よくある落とし穴
    • 次元の呪い: 実際の埋め込みは 50〜768 次元。 高次元では「ほとんどの点が等距離」に見え、 2 次元の直感が崩れます。
    • 学習データのバイアス: 埋め込みはデータの偏り(性別・職業の固定観念など)をそのまま学習します。 「王−男+女≈女王」が成り立つのと同じ仕組みで、 差別的な連想も再現してしまいます。
    • 解釈: 各次元に人間が読める意味はありません。 「近い/遠い」は言えても「なぜ近いか」は別途分析が必要です。 t-SNE/UMAP の 2D 図は距離ではなく近傍関係を保つため、 図上の距離を鵜呑みにしないこと。
    🚀 発展
    • word2vec: 実験2 のアナロジーを大量テキストの共起から自動獲得した古典的手法(本サイトでは 自然言語処理 (NLP) を参照)。
    • 文埋め込み: 単語だけでなく文全体を 1 ベクトル化。 テキスト類似度 や RAG の基盤になります。
    • レコメンド: 商品・ユーザを埋め込み、 コサイン類似度で「近いもの」を推薦(推薦システム)。 Transformer も入力を埋め込みから始めます。

    🧭 深掘り追補: 「埋め込み」という発想の核 — 3 つの本質

    ここまでの解説を「一言でいうと何だったのか」に圧縮し直します。 埋め込みの定義は分野ごとに揺れますが、 次の 3 点はどの流儀にも共通する発想の核です。

    1. 高次元・離散 → 低次元・密。 one-hot(語彙数 $V$ 次元、 ほぼ全部 0 の疎ベクトル)や共起カウント行列を、 数十〜数百次元の密な実数ベクトルに置き換える。 情報を捨てるのではなく、 「予測に効く共通構造」だけを残す圧縮です(次元削減・TF-IDF の疎ベクトルとの対比で理解すると鮮明)。
    2. 意味の近さを距離・角度で表す。 「似ている ⇔ ベクトルが近い」という約束をデータから作り込む。 近さの物差しは cosine 類似度(向き)とユークリッド距離(位置)で、 両者は L2 ノルムを揃えたときだけ同じ順位を返します。
    3. 学習された表現である。 設計者が座標軸を決めるのではなく、 「共起を当てる」「同じ意味のペアを近づける」といった代理タスクの副産物として座標が決まる。 だから各次元に人間可読なラベルはなく、 学習データが変われば地図も変わります。

    対象は単語に限りません。 単語・文の埋め込み(NLP・テキスト類似度)、 アイテム/ユーザ埋め込み(推薦システムで「この商品を買った人はこれも」を内積で計算)、 グラフ埋め込み(ネットワークの頂点をランダムウォークの「文」と見なして word2vec を流用する node2vec など)—— いずれも「離散シンボルを共通のベクトル空間に載せ、 あとはベクトル演算に持ち込む」という同じ設計思想です。 本ページの SSDSE-B の県ベクトルは、 この最も素朴な形(数値特徴の標準化ベクトル)にあたります。

    🧮 実測追補: SSDSE-B-2026 の 109 次元「県ベクトル」で本質を確かめる

    上の 🧮 セクションは 4 次元の入門例でした。 ここでは SSDSE-B-2026(cp932、 2 行目の日本語ヘッダを skiprows で除外、 2023 年度・47 都道府県)の数値列 109 個すべてを使い、 各県を 109 次元ベクトルとして扱った実測結果を示します。 レシピは「列ごとに z-score 標準化 → cosine 類似度行列」だけです。

    df = pd.read_csv("SSDSE-B-2026.csv", encoding="cp932", skiprows=[1])
    X = df[df["SSDSE-B-2026"]==2023] の数値109列 → Z = (X − mean) / std
    C = cosine_similarity(Z) # 47×47 の類似度行列

    実測① 標準化しないと「全県が似ている」ことになる

    生の値のまま cosine を取ると、 総人口など桁の大きい列が向きを支配し、 47 県の全ペア平均は cosine = 0.954(最小でも 0.42)。 「どの県も互いにそっくり」という無意味な結果になります。 z-score 標準化後は全ペア平均 0.074、 範囲は −0.90 〜 +0.96 に広がり、 初めて識別力のある空間になります。 埋め込み以前にスケーリングあり —— これが実データで一番効く教訓です。

    実測② 最近傍は直感と整合する

    県cosine 最近傍(上位2)読み方
    東京都大阪府 0.905 / 愛知県 0.884大都市圏プロファイル
    埼玉県神奈川県 0.928 / 千葉県 0.916首都圏ベッドタウン型
    鳥取県島根県 0.912 / 山口県 0.873小規模県どうしが近い
    沖縄県鹿児島県 0.672 / 長崎県 0.611気候・人口動態の近さ

    逆に遠いペアは 北海道×沖縄県 cosine = −0.30、 東京都×沖縄県 −0.27(ユークリッド距離では 46.7 と全ペア中最大級)。 4 次元入門例の「北海道×沖縄 = −0.90」より緩和されるのは、 次元を増やすと気候・観光など両県が同じ側に振れる軸も混ざるためで、 「特徴の選び方が距離の意味を決める」ことの実例です。

    実測③ cosine とユークリッドは本当に順位が変わる

    同じ 109 次元ベクトルでも、 最近傍(1 位)が cosine とユークリッドで食い違う県は 47 県中 22 県。 例えば北海道の最近傍は cosine では大阪府(0.666。 多くの総量指標が平均より大きい「向き」が揃う)ですが、 ユークリッドでは福岡県(距離 9.56。 規模の水準が近い)。 落とし穴セクションの「cosine vs Euclidean の混同」は、 この規模のデータでも半数近くの結論を変えるわけです。

    実測④ 次元数の選択 — 2 次元の地図はご近所を 8 割壊す

    PCA で圧縮すると、 第 1 主成分だけで分散の 77.3%(ほぼ「県の規模」軸)、 2 次元で 82.2%、 5 次元で 90.5%、 10 次元で 95.7% を説明します。 しかし「cosine 最近傍が 109 次元のときと一致する県」は 2 次元で 9/47、 5 次元で 21/47、 10 次元で 39/47。 つまり分散の 8 割を保っても近傍関係は 2 割しか保てないことがあり、 「説明率が高いから 2 次元散布図で類似県を論じてよい」とは言えません。 可視化は可視化、 検索は元の次元 —— と役割を分けるのが安全です。

    ⚠️ 深掘り追補: 運用フェーズの落とし穴 — 作った後に効いてくる 4 つ

    上の落とし穴(バイアス・次元の呪い・OOV・t-SNE の誤読・cosine/Euclidean)は主に作るときの話でした。 ここでは埋め込みを保存して使い続ける段階で痛い目を見るパターンを補います。

    ❌ 埋め込みの陳腐化 — モデルを替えたら全部作り直し
    埋め込みベクトルは生成したモデルとバージョンに固有の座標系を持ちます。 別モデル(あるいは同モデルの新バージョン)のベクトルと混ぜて cosine を取っても数値に意味はありません。 モデル更新時は保存済みベクトルを全件再計算(re-embedding)するのが原則。 また世の中の言葉遣い・データ分布が変わるデータドリフトでも検索品質は静かに劣化するため、 評価セットでの定点観測と再学習計画をセットで持ちます。
    ❌ 「ベクトルだから匿名」ではない — 復元攻撃
    文埋め込みから元テキストをかなりの精度で復元する研究(embedding inversion。 vec2text 等)が報告されており、 埋め込みは不可逆な要約ではなく可逆に近い圧縮と考えるべきです。 個人情報を含む文書の埋め込みをベクトル DB に置くなら、 元文書と同じアクセス制御・暗号化・削除義務を適用します(プライバシー・個人情報)。 「数値の列にしたから安全」は通用しません。
    ❌ 次元数 d を「大きいほど良い」で選ぶ
    d が大きいほど表現力は上がりますが、 保存容量・検索コストは線形に増え、 少データでは過学習気味になり、 距離の集中(実測④のとおり近傍構造は次元に敏感)も悪化します。 逆に小さすぎると意味が潰れます。 「下流タスクの精度が飽和する最小の d」を実験で選ぶのが定石で、 事前学習モデルなら公式次元(384/768/1536 等)を使い、 必要なら PCA / Matryoshka 的切り詰めで縮めて効果を検証します。
    ❌ バイアス監査を「学習時に 1 回」で済ませる
    埋め込みのバイアス(WEAT 等で測る連想の偏り)は、 debias 処理をしても下流タスクで復活する例が知られています。 アルゴリズムバイアスは空間そのものではなく意思決定の出口で測り続ける必要があり、 採用・与信など人に関わる用途では公平性指標の継続監視が前提です(詳細は上の R542 補強3 も参照)。

    🚀 深掘り追補: 発展 — 対比学習・近似最近傍・転移・評価

    ① 対比学習 — 現代の埋め込みは「ペアを近づけて」作る

    word2vec の「共起を当てる」に代わり、 現在の文・画像埋め込みの主流は対比学習 (contrastive learning) です。 「意味が同じペア(正例)を近づけ、 バッチ内の他サンプル(負例)を遠ざける」損失(InfoNCE)を最小化します。 質問と回答文、 画像とキャプション(CLIP)のように異なるモダリティを同じ空間に入れられるのが強みで、 ラベル不要の自己教師あり学習として大規模化できます。 Sentence-BERT や OpenAI/E5 系の文埋め込みもこの系譜です。

    ② 類似度検索の実装 — ANN とベクトル DB

    全件と cosine を計算する厳密 k-NN は $O(N)$ で、 数百万ベクトルでは間に合いません。 実運用では HNSW(グラフを辿る)や IVF(クラスタに絞る)などの近似最近傍探索 (ANN) を使い、 「再現率 Recall@k を少し犠牲に速度を数百倍にする」トレードオフを取ります。 FAISS などのライブラリ、 これに永続化・メタデータフィルタを足したベクトル DBが RAG の検索部を担います(パイプライン全体は上の R542 補強2 を参照)。 47 県規模なら総当たりで十分 —— ANN が要るのはデータが桁で増えてからです。

    ③ 転移とファインチューニング

    事前学習済み埋め込みをそのまま特徴量として使うのは転移学習の最小形です。 ドメイン語彙(医療・法律・自治体統計など)で精度が足りなければ、 自前の正例ペアで対比学習を続けるファインチューニングが次の一手。 Transformer の入力層(トークン埋め込み)を凍結するか更新するかも、 データ量に応じた設計判断です。

    ④ 埋め込みの評価 — 内的評価と外的評価

    評価は 2 系統に分けます。 内的評価は空間そのものを見る: 類似度の人手評定との相関、 アナロジー正答率、 近傍検索の Recall@k / nDCG(上の 🔎 補足も参照)。 外的評価は下流タスクで測る: その埋め込みを特徴量にした分類・検索・クラスタリングの精度で、 実務上はこちらが最終判断です。 多タスクベンチマーク(MTEB 等)は「モデル選定の地図」として便利ですが、 自分のドメインの小さな評価セットを 1 つ持つことが何より効きます。

    ⑤ 次元削減・疎表現との住み分け

    埋め込みと次元削減は近縁ですが役割が違います。 PCA は分散を、 t-SNE・UMAP は近傍関係を保つ座標変換で、 主に可視化・前処理に使う。 一方 TF-IDF は学習不要・解釈容易な疎表現で、 キーワード一致が効く検索では今も強力です。 実務の意味検索では「疎 (BM25/TF-IDF) と密(埋め込み)のハイブリッド」が定番 —— 対立ではなく併用が答えになることが多い、 と覚えてください(テキスト類似度)。