概要
分散仮説とは、「単語の意味はその周囲に現れる単語(文脈)によって決まる」という言語学・計算言語学上の仮説である。J.R. Firthの「You shall know a word by the company it keeps」という言葉に由来する。この仮説は、単語をベクトルとして表現する手法(分散表現)の理論的根拠となっており、Word2VecやGloVeといった現代的な単語埋め込み手法の基礎をなす。
直感・モチベーション
「銀行」という単語を考えたとき、その意味を辞書なしで推測するにはどうすればよいか。
- 「彼は銀行に預金した」
- 「銀行の融資を受けた」
- 「銀行口座を開設した」
これらの文から「銀行」の周囲には「預金」「融資」「口座」が頻繁に登場することがわかる。一方、「川岸」の意味で使われる「bank」の周囲には「river」「water」「flood」が現れる。同じ単語でも文脈が異なれば意味が異なる、という直感がそのまま仮説になっている。
この考え方には重要なトレードオフがある。
- 利点: 意味を人手でラベル付けせずとも、大量のテキストから自動的に抽出できる
- 限界: 文脈に依存するため、文脈が稀な専門用語や固有名詞の表現精度は低下する
数学的定式化
語彙 の中の単語 の意味を、周囲の単語(文脈語)の共起情報として表す。
ウィンドウサイズ を定めたとき、単語 に対する文脈語の集合を以下で定義する:
共起行列 の各要素 は、単語 の文脈に単語 が現れた回数を表す:
ここで はコーパス全体、 は文書 中で と がウィンドウ内に共起した回数である。
導出を見る
単語の意味的類似度をコサイン類似度で測る場合、共起行列の行ベクトルを使う:
ただし生の共起頻度は高頻度語(「は」「が」「the」など)に偏るため、PMI(点相互情報量)でスケーリングすることが多い:
PMIが負になるケースは意味が薄いため、PPMI(Positive PMI)として を使うことが一般的である。
重要な性質・注意点
- 語彙サイズのスケーリング問題: 共起行列のサイズは であり、大規模コーパスでは数十万×数十万になる。SVDなどの次元削減が必要になる
- ウィンドウサイズの影響: 小さいウィンドウ(±2程度)は構文的類似性を、大きいウィンドウ(±10程度)は意味的類似性を捉えやすい
- 仮説の限界: 「hot dog」のような慣用句や、否定文(「銀行ではない」)の扱いが苦手
まとめ
- 単語の意味 ≈ 周囲の文脈語の分布、という仮説が分散仮説
- 大量テキストから人手ラベルなしで意味を抽出できる
- 共起行列として定式化され、PMI/PPMIでスケーリングするのが一般的
- Word2Vec・GloVe・BERTなど現代的な手法の理論的根拠
実装例
pythonimport 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つの単語が偶然以上に共起しているかを対数スケールで測る指標 |
| PPMI | PMIの負値を0にクリップしたもの |
| ウィンドウサイズ | 文脈語とみなす対象単語前後の単語数 |
| 分散表現 | 単語を実数値ベクトルとして表現したもの |