cs-kb
一覧に戻る

分散仮説

2026年4月16日19時間前に更新
自然言語処理分散表現共起行列PMI

概要

分散仮説とは、「単語の意味はその周囲に現れる単語(文脈)によって決まる」という言語学・計算言語学上の仮説である。J.R. Firthの「You shall know a word by the company it keeps」という言葉に由来する。この仮説は、単語をベクトルとして表現する手法(分散表現)の理論的根拠となっており、Word2VecやGloVeといった現代的な単語埋め込み手法の基礎をなす。

直感・モチベーション

「銀行」という単語を考えたとき、その意味を辞書なしで推測するにはどうすればよいか。

  • 「彼は銀行に預金した」
  • 「銀行の融資を受けた」
  • 「銀行口座を開設した」

これらの文から「銀行」の周囲には「預金」「融資」「口座」が頻繁に登場することがわかる。一方、「川岸」の意味で使われる「bank」の周囲には「river」「water」「flood」が現れる。同じ単語でも文脈が異なれば意味が異なる、という直感がそのまま仮説になっている。

この考え方には重要なトレードオフがある。

  • 利点: 意味を人手でラベル付けせずとも、大量のテキストから自動的に抽出できる
  • 限界: 文脈に依存するため、文脈が稀な専門用語や固有名詞の表現精度は低下する

数学的定式化

語彙 VV の中の単語 ww の意味を、周囲の単語(文脈語)の共起情報として表す。

ウィンドウサイズ kk を定めたとき、単語 wtw_t に対する文脈語の集合を以下で定義する:

Context(wt)={wtk,,wt1,wt+1,,wt+k}\text{Context}(w_t) = \{w_{t-k}, \ldots, w_{t-1}, w_{t+1}, \ldots, w_{t+k}\}

共起行列 MRV×VM \in \mathbb{R}^{|V| \times |V|} の各要素 MijM_{ij} は、単語 wiw_i の文脈に単語 wjw_j が現れた回数を表す:

Mij=dDcount(wi,wj,d)M_{ij} = \sum_{d \in D} \text{count}(w_i, w_j, d)

ここで DD はコーパス全体、count(wi,wj,d)\text{count}(w_i, w_j, d) は文書 dd 中で wiw_iwjw_j がウィンドウ内に共起した回数である。

導出を見る

単語の意味的類似度をコサイン類似度で測る場合、共起行列の行ベクトルを使う:

sim(wi,wj)=MiMjMiMj\text{sim}(w_i, w_j) = \frac{M_{i\cdot} \cdot M_{j\cdot}}{\|M_{i\cdot}\| \cdot \|M_{j\cdot}\|}

ただし生の共起頻度は高頻度語(「は」「が」「the」など)に偏るため、PMI(点相互情報量)でスケーリングすることが多い:

PMI(wi,wj)=logP(wi,wj)P(wi)P(wj)\text{PMI}(w_i, w_j) = \log \frac{P(w_i, w_j)}{P(w_i)P(w_j)} P(wi,wj)=Miji,jMij,P(wi)=jMiji,jMijP(w_i, w_j) = \frac{M_{ij}}{\sum_{i,j} M_{ij}}, \quad P(w_i) = \frac{\sum_j M_{ij}}{\sum_{i,j} M_{ij}}

PMIが負になるケースは意味が薄いため、PPMI(Positive PMI)として max(0,PMI)\max(0, \text{PMI}) を使うことが一般的である。

重要な性質・注意点

  • 語彙サイズのスケーリング問題: 共起行列のサイズは V2|V|^2 であり、大規模コーパスでは数十万×数十万になる。SVDなどの次元削減が必要になる
  • ウィンドウサイズの影響: 小さいウィンドウ(±2程度)は構文的類似性を、大きいウィンドウ(±10程度)は意味的類似性を捉えやすい
  • 仮説の限界: 「hot dog」のような慣用句や、否定文(「銀行ではない」)の扱いが苦手

まとめ

  • 単語の意味 ≈ 周囲の文脈語の分布、という仮説が分散仮説
  • 大量テキストから人手ラベルなしで意味を抽出できる
  • 共起行列として定式化され、PMI/PPMIでスケーリングするのが一般的
  • Word2Vec・GloVe・BERTなど現代的な手法の理論的根拠

実装例

python
import math from collections import defaultdict def build_cooccurrence_matrix(corpus: list[list[str]], window: int = 2): vocab = sorted(set(w for sent in corpus for w in sent)) w2i = {w: i for i, w in enumerate(vocab)} n = len(vocab) M = [[0] * n for _ in range(n)] for sent in corpus: for t, word in enumerate(sent): start = max(0, t - window) end = min(len(sent), t + window + 1) for ctx in sent[start:end]: if ctx != word: M[w2i[word]][w2i[ctx]] += 1 return vocab, M def ppmi(M: list[list[float]]): total = sum(sum(row) for row in M) row_sums = [sum(row) for row in M] col_sums = [sum(M[i][j] for i in range(len(M))) for j in range(len(M[0]))] n = len(M) result = [[0.0] * n for _ in range(n)] for i in range(n): for j in range(n): if M[i][j] == 0: continue pij = M[i][j] / total pi = row_sums[i] / total pj = col_sums[j] / total pmi = math.log(pij / (pi * pj)) result[i][j] = max(0.0, pmi) return result # 使用例 corpus = [ ["銀行", "に", "預金", "した"], ["銀行", "の", "融資", "を", "受けた"], ["預金", "と", "融資", "は", "銀行", "の", "業務"], ] vocab, M = build_cooccurrence_matrix(corpus, window=2) P = ppmi(M)

関連記事

前提知識

  • 行列演算と内積 — ベクトル類似度の計算基盤

派生技術

  • N-gram — 局所的な文脈を捉える古典的手法
  • Word2Vec — 分散仮説をニューラルネットで実装した手法
  • TF-IDF — 単語の重要度を文書頻度から測る手法

応用事例

  • 類義語検索 — 意味的に近い単語の自動発見
  • 感情分析 — 文脈から単語の極性を推定

用語解説

用語説明
分散仮説単語の意味はその文脈(周囲の単語)によって決まるという仮説
共起行列単語ペアがコーパス中で共起した回数を格納した行列
PMI(点相互情報量)2つの単語が偶然以上に共起しているかを対数スケールで測る指標
PPMIPMIの負値を0にクリップしたもの
ウィンドウサイズ文脈語とみなす対象単語前後の単語数
分散表現単語を実数値ベクトルとして表現したもの

関連リンク

この記事への参照