Word2Vec、FastTextの比較（類義語編）

## はじめに
Word2Vecは単語を固定長のベクトルで表現する手法の一つです。
![w2v_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2415251/3ee3c112-2398-1a09-8918-748eee4cd8f8.png)

学習に与えた文章の一部の単語をマスクし、その予測をすることで学習を行います。
![w2v_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2415251/019f9017-547a-0430-60a6-dba742894910.png)

そのため、同じような文脈で登場する単語のベクトルが近くなる、という特徴があります。
図2の例では `新宿` の部分が `渋谷` になっている文章などを学習することにより `新宿` と `渋谷` のベクトルが近くなります。

Word2Vecは、学習に与えた文章に含まれる単語のベクトルしか作成できません。
一方、FastTextは、未知の単語（未知語）でもベクトルを作成することができる特徴があります。
例えば、学習に与えた文章に `新宿大学` という単語が存在しなかったとしても `新宿` や `大学` といった部分単語（サブワード）から単語のベクトルを取得することができます。

FastTextはWord2Vecの進化版とも言えますが、使い方次第で性能が下がる可能性もあります。
両者の特徴をよく理解して使うことが重要です。

今回は、類義語に着目して調査します。

## 確認環境
Python 3.8、ライブラリーは以下のgensimを使用しました。
Word2Vec
https://radimrehurek.com/gensim_3.8.3/models/word2vec.html
FastText
https://radimrehurek.com/gensim_3.8.3/models/fasttext.html

単語の分割には、Mecabを使用しました。
https://github.com/ikegami-yukino/mecab/releases

学習（モデル作成）の設定は以下のとおりです。

- データは日本語Wikipedia
- ベクトルは100次元
- min_countは20を指定
- 学習アルゴリズムは、デフォルト設定の CBOW（周辺の単語から中心語を予測）を使用

## 類似性の比較
gensimのWord2Vec、FastTextライブラリーには学習モデルに含まれる単語から類義語（ベクトルが近い単語）を出力してくれる機能があります。

- ある単語に近い単語を出力できる、most_similar関数
- 2つの単語の類似度を出力できる、similarity関数

また、類義語単語の類似度の高さが-1.0（類似度が低い）～1.0（類似度が高い）の範囲で出力されます。
この機能を使い、いろいろな単語の類義語をWord2VecとFastTextで比較してみました。

#### 類義語を見たときの違い`新宿`

<table>
<tr>
  <th colspan=2>Word2Vec</th>
  <th colspan=2>FastText</th>
</tr>
  <th>単語</th>
  <th>類似度</th>
  <th>単語</th>
  <th>類似度</th>
</tr>
<tr>
  <td>池袋</td>
  <td>0.92</td>
  <td>池袋</td>
  <td>0.93</td>
</tr>
<tr>
  <td>渋谷</td>
  <td>0.90</td>
  <td>渋谷</td>
  <td>0.92</td>
</tr>
<tr>
  <td>吉祥寺</td>
  <td>0.84</td>
  <td><font color="Red">北新宿</font></td>
  <td>0.89</td>
</tr>
<tr>
  <td>中目黒</td>
  <td>0.83</td>
  <td><font color="Red">東新宿</font></td>
  <td>0.89</td>
</tr>
<tr>
  <td>高田馬場</td>
  <td>0.82</td>
  <td>中目黒</td>
  <td>0.88</td>
</tr>
<tr>
  <td>五反田</td>
  <td>0.81</td>
  <td><font color="Red">西新宿</font></td>
  <td>0.87</td>
</tr>
<tr>
  <td>六本木</td>
  <td>0.81</td>
  <td>六本木</td>
  <td>0.84</td>
</tr>
</table>

単語 `新宿` に類似する単語を類似度の高い順に並べています。

Word2Vec、FastTextとも、図2の文章例で `新宿` の部分を類義語に置き換え得る単語が出ています。
例えば `今日、池袋で焼き肉を食べた` などとなります。

FastTextはそれに加え `新宿` を含む単語（赤字）も出ています。
Word2Vecでは

- `新宿` と `北新宿` の類似度は0.65
- `新宿` と `東新宿` の類似度は0.65
- `新宿` と `西新宿` の類似度は0.77

ですので `新宿` を部分単語に含む単語の類似度が高くなる特徴が表れています。


#### 類義語を見たときの違い `東京`

<table>
<tr>
  <th colspan=2>Word2Vec</th><th colspan=2>FastText</th>
</tr>
  <th>単語</th>
  <th>類似度</th>
  <th>単語</th>
  <th>類似度</th>
</tr>
<tr>
  <td>大阪</td>
  <td>0.82</td>
  <td><font color="Red">東京現像所</font></td>
  <td>0.82</td>
</tr>
<tr>
  <td>横浜</td>
  <td>0.74</td>
  <td>大阪</td>
  <td>0.79</td>
</tr>
<tr>
  <td>京都</td>
  <td>0.73</td>
  <td><font color="Red">東京會舘</font></td>
  <td>0.78</td>
</tr>
<tr>
  <td>小金井</td>
  <td>0.59</td>
  <td><font color="Red">大阪工業会</font></td>
  <td>0.71</td>
</tr>
</table>

単語 `東京` に類似する単語を類似度の高い順に並べています。

Word2Vecでは `大阪` `横浜` など `東京` と同じ“地名”の概念の単語が、類似度上位に出ています。
対してFastTextは `東京現像所` など“地名”ではなく“組織”の概念の単語が出ています。

また、FastTextでは `東京` と類似度が高い `大阪` を含む `大阪工業会` などの単語も出ています。

#### 存在しない類義語を見たときの違い（1） `新宿大学`
<table>
<tr>
  <th colspan=2>Word2Vec</th>
  <th colspan=2>FastText</th>
</tr>
  <th>単語</th>
  <th>類似度</th>
  <th>単語</th>
  <th>類似度</th>
</tr>
<tr>
  <td>存在しない</td>
  <td>-</td>
  <td>麻布<font color="Red">大学</font></td>
  <td>0.99</td>
</tr>
<tr>
  <td></td>
  <td></td>
  <td>清和<font color="Red">大学</font></td>
  <td>0.99</td>
</tr>
<tr>
  <td></td>
  <td></td>
  <td>八戸<font color="Red">大学</font></td>
  <td>0.98</td>
</tr>
</table>

Word2Vecでは、学習データに存在しない単語 `新宿大学` は類似単語が出力できません。
FastTextについては、類似度上位3番目までの単語を表に記しています。

結果を見ると `新宿` を含む単語はなく `大学` を含む単語が出ています。
most_similar上位1,000単語で見ても `新宿` を含む単語はありませんでした。

学習したWikipediaに含まれる単語数は、

- `新宿` は 19,629個
- `大学` は 258,070個

であることから、学習のデータ量が影響しているようです。

#### 存在しない類義語を見たときの違い（2） `日本豆腐`
<table>
<tr>
  <th colspan=2>Word2Vec</th>
  <th colspan=2>FastText</th>
</tr>
  <th>単語</th>
  <th>類似度</th>
  <th>単語</th>
  <th>類似度</th>
</tr>
<tr>
  <td>存在しない</td>
  <td>-</td>
  <td><font color="Red">日本</font>晴</td>
  <td>0.95</td>
</tr>
<tr>
  <td></td>
  <td></td>
  <td><font color="Red">日本</font>香堂</td>
  <td>0.94</td>
</tr>
<tr>
  <td></td>
  <td></td>
  <td><font color="Red">日本</font>食研</td>
  <td>0.93</td>
</tr>
</table>

Word2Vecでは、学習データに存在しない単語 `日本豆腐` は類似単語が出力できません。
FastTextについては、類似度上位3番目までの単語を表に記しています。

結果を見ると`豆腐`を含む単語はなく `日本` を含む単語が出ています。
most_similar上位1,000単語で見ても `豆腐` を含む単語はありませんでした。

- `日本` は 899,852個
- `豆腐` は 1,777個

であることから、やはり学習のデータ量が影響しているようです。

#### 表記ゆれのある単語（1） `ヴェネチア`

<table>
<tr>
  <th colspan=2>Word2Vec</th>
  <th colspan=2>FastText</th>
</tr>
  <th>単語</th>
  <th>類似度</th>
  <th>単語</th>
  <th>類似度</th>
</tr>
<tr>
  <td>ヴェネツィア</td>
  <td>0.80</td>
  <td><font color="Red">ヴェネ</font>ツィ<font color="Red">ア</font></td>
  <td><font color="Red">0.95</font></td>
</tr>
<tr>
  <td>ベネチア</td>
  <td>0.79</td>
  <td>ベネ<font color="Red">チア</font></td>
  <td><font color="Red">0.86</font></td>
</tr>
<tr>
  <td>ベニス</td>
  <td>0.74</td>
  <td>ベニス</td>
  <td>0.72</td>
</tr>
</table>

`ヴェネチア` という地名は `ヴェネツィア` `ベネチア` `ベニス` という別の表記があります。

FastTextは部分一致が類似度に反映されるため `ヴェネチア` と重なる文字（赤字部分）が多い表記ゆれに対しては、Word2Vecより高い類似度になる傾向があります。
重なる文字がない`ベニス`に対しては、Word2VecとFastTextでほぼ同じ類似度になりました。

#### 表記ゆれのある単語（2） 送り仮名

<table>
<tr>
  <th>比較単語</th>
  <th>Word2Vec類似度</th>
  <th>FastText類似度</th>
</tr>
<tr>
  <td>「引っ越し」 「引越」</td>
  <td>0.36</td>
  <td><font color="Red">0.52</font></td>
</tr>
<tr>
  <td>「引っ越し」 「引越し」</td>
  <td>0.84</td>
  <td>0.84</td>
</tr>
<tr>
  <td>「押さえる」「押える」</td>
  <td>0.66</td>
  <td><font color="Red">0.80</font></td>
</tr>
<tr>
  <td>「聞こえる」「聞える」</td>
  <td><font color="Red">0.79</font></td>
  <td>0.75</td>
</tr>
<tr>
  <td>「申し込む」 「申込む」</td>
  <td>「申込む」が未知語</td>
  <td><font color="Red">0.75</font></td>
</tr>
<tr>
  <td>「終わる」 「終る」</td>
  <td><font color="Red">0.68</font></td>
  <td>0.54</td>
</tr>
<tr>
  <td>「変わる」 「変る」</td>
  <td><font color="Red">0.52</font></td>
  <td>0.49</td>
</tr>
<tr>
  <td>「暮らす」 「暮す」</td>
  <td><font color="Red">0.76</font></td>
  <td>0.72</td>
</tr>
<tr>
  <td>「起こる」 「起る」</td>
  <td><font color="Red">0.77</font></td>
  <td>0.45</td>
</tr>
<tr>
  <td>「当たる」 「当る」 </td>
  <td><font color="Red">0.79</font></td>
  <td>0.66</td>
</tr>
<tr>
  <td>「行なう」 「行う」</td>
  <td><font color="Red">0.98</font></td>
  <td>0.97</td>
</tr>
</table>

送り仮名の表記ゆれを比較しました。
Word2VecとFastTextで高い類似度の方を赤字にしています。

`ヴェネチア` の例から文字一致でFastTextの類似度が高くなると予想しましたが、そうなりませんでした。
文字が一致していても `終わる` の `終` と `る` の間に `わ` が入っている、すなわち文字が連続して一致していない場合では必ずしも類似度は高くならないようです。

## おわりに
ここまでお読みいただきありがとうございました。
FastTextの未知語ベクトル出力は魅力的な機能ですが、既知語の類義語出力にも影響があることや、データ量の影響があるなど注意点もあることが分かりました。
次は演算機能についても確認してみたいと思います。