word2vec の Out-Of-Vocabulary 対策の一案

# word2vec
word2vec は、大量のテキストデータを解析して、解析結果から単語をベクトルで表現する手法です。
単語をベクトル化することで、単語間の意味的な類似度を計算することができるようになります。
さらに、文書を単語のベクトルの和で表現することもできます。

# Out-Of-Vocabulary (OOV)
大変便利な word2vec ですが、問題点もあります。
それは、word2vec でテキストからベクトルを生成する際に、そのテキストに含まれない単語 (OOV: Out-Of-Vocabulary) はベクトル化できないという問題です。

# Skip-Gram
word2vec には、Skip-Gram と CBOW という 2つの手法がありますが、ここでは Skip-Gram について考えます。
Skip-Gram は、テキスト内の各単語について、各単語の周辺 (window size 内) に出現する単語の確率を予測するという問題を解くことで、副次的に各単語のベクトル表現を得ることができます。

以下のテキストデータを例にして考えます。
emi looks **happy** .
she always looks **happy** .
she dreamed a **happy** dream last night .

happy の周辺単語は、windows size = 2 の場合、happy の前後それぞれの2単語を集計し、
以下のようになります。
(単語: 出現頻度)
emi: 1
looks: 2
.: 2
always: 1
dreamed: 1
a: 1
dream: 1
last: 1

word2vec の学習では、happy から emi、looks など各単語の出現確率を予測するよう学習を行います。

# Out-Of-Vocabulary (OOV) 対策
上記のとおり、Skip-Gram では、各単語の周辺確率を予測することで、各単語のベクトルを得るため、ある単語の周辺の単語としてよく出現する単語については、類似したベクトルになるのではないでしょうか。

OOV の単語 $w\_{{oov}}$ については、その単語の周辺にのる単語 $w\_{{i}}$ のベクトル $vector(w\_{{i}})$ を周辺での出現確率 $p(w\_{{i}})$ で重みづけして、以下のように計算してみます。

$vector(w\_{{oov}}) = Σ p(w\_{{i}}) × vector(w\_{{i}})$
$w\_{{i}}$ is a word in window of $w\_{{oov}}$

OOV の単語の出現確率については、OOV の単語が含まれる別のテキストデータを
持ってくれば集計することができます。

# 検証
word2vec によって生成されたベクトルと、周辺単語の確率とベクトルから生成したベクトルの類似度を比較することで、OOV 対策の妥当性の検証を行います。

## word2vec によるベクトル生成
[『詳解 ディープラーニング 第2版](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-%E7%AC%AC2%E7%89%88-TensorFlow-Keras%E3%83%BBPyTorch%E3%81%AB%E3%82%88%E3%82%8B%E6%99%82%E7%B3%BB%E5%88%97%E3%83%87%E3%83%BC%E3%82%BF%E5%87%A6%E7%90%86-%E5%B7%A3%E7%B1%A0/dp/4839969515)』で紹介されている日英対訳コーパスの英語文 5万文のテキストで word2vec でベクトルを生成します。

word2vec のパラメータは以下を指定しました。
 -size 100
 -window 5
 -cbow 0
-iter 15
 -min-count 5

## 周辺単語の出現確率
word2vec にかけた同じ5万文のテキストで、テキスト内に出現する各単語について
周辺単語の出現頻度を集計し、出現確率を求めます。
周辺単語は word2vec と同様に、window size=5 以内の単語とします。

以下は各単語の周辺単語とその出現頻度の例です。

・例1 football
各周辺単語の出現頻度: .:6, i:5, played:3, playing:2, game:2, ...
出現頻度の合計: 48

・例2 tennis
各周辺単語の出現頻度: .:156, play:78, i:75, playing:45, to:36, ...
出現頻度の合計: 1284

・例3 baseball
各周辺単語の出現頻度: .:93, play:35, the:32, i:26, to:24, ...
出現頻度の合計: 759

## 周辺単語からのベクトル生成
上記の football の場合、以下のように study のベクトルを計算します

vector(football) =
6/48 × vector(.) + 5/48 × vector(i) + 3/48 × vector(played)
+ 2/48 × vector(playing) + 2/48 × vector(game) + ...

## word2vec のベクトルと周辺単語から生成したベクトルの比較
周辺単語のベクトルから生成したベクトルが word2vec のベクトルとどれだけ近いかで周辺単語のベクトルから生成したベクトルの評価を行います。

2つのベクトルの近さは、2つのベクトルの cos を計算し、cos が 1 に近いほど類似しているとみなします。

・例1: football
cos: 0.872

・例2: tennis
cos: 0.566

・例3: basketball
cos: 0.771

他の単語についても同様に類似度を計算したところ、
類似度と単語数の分布は以下のようになりました。

|類似度|単語数|割合|累積割合|
|:---:|:---:|:---:|:---:|
|0.9 - 1.0|13|0.5%|0.5%|
|0.8 - 0.9|323|13.6%|14.1%|
|0.7 - 0.8|741|31.1%|45.2%|
|0.6 - 0.7|545|22.9%|68.1%|
|0.5 - 0.6|526|22.1%|90.2%|
|0.4 - 0.5|230|9.7%|99.9%|
|0.3 - 0.4|3|0.1%|100.0%|
|合計|2381|||		

約7割の単語で類似度が 0.6 以上、約9割の単語で類似度 0.5 以上ですので、
そこそこよい結果だったのではないかと思います。

# 終わりに
Out-Of-Vocabulary (OOV) の対策として、単語の周辺単語を集計し、周辺単語の出現確率、周辺単語のベクトルからベクトルを生成してみました。

検証に使ったテキストデータでは、word2vec のベクトルと本手法とのベクトルのcos 類似度で、約7割の単語で類似度が 0.6 以上、約9割の単語で類似度 0.5 以上となりました。

OOV の周辺単語を集計するテキストがあれば、OOV の単語のベクトルを零ベクトルとして諦めなくても良さそうです。