Qiitaコーパスを作る会 3️⃣単語埋め込みの様子を見てみる

# はじめに
[前回](https://qiita.com/LeftLetter/items/80b40574311448ea9290)、[前々回](https://qiita.com/LeftLetter/items/24ed8f792f56a2ec2392)でQiitaのコーパスを作成しました。
今回は、Word2VecとfastTextをQiitaコーパスで学習させ、足し算引き算などを色々やってみます。

今回のシリーズで作ったソースコードは[GitHub](https://github.com/LeftLetter/qiita_corpus)に置いてあります。

# 学習
はじめに、モデルにQiitaコーパスを学習させます。
パラメータは割と適当です。

```python:model_creation.py
# --------------------------------------------------
# モデルの作成
# --------------------------------------------------
from gensim.models.fasttext import FastText
from gensim.models import word2vec, Word2Vec

sentences = word2vec.LineSentence('data/qiita_corpus.txt')

# Word2Vec (Skip-gram)
sg_model = Word2Vec(sentences=sentences, size=200, workers=6,
                    min_count=20, window=15, sg=1, iter=5)
sg_model.save('model/sg.model')
print('Finish Skip-gram')

# Word2Vec (CBOW)
cbow_model = Word2Vec(sentences=sentences, size=200, workers=6,
                      min_count=20, window=15, sg=0, iter=5)
cbow_model.save('model/cbow.model')
print('Finish CBOW')

# fastText (Skip-gram)
ft_sg_model = FastText(sentences=sentences, size=200, workers=6,
                       min_count=20, window=15, sg=1, iter=5)
ft_sg_model.save('model/ft_sg.model')
print('Finish fastText Skip-gram')

# fastText (CBOW)
ft_cbow_model = FastText(sentences=sentences, size=200, workers=6,
                         min_count=20, window=15, sg=0, iter=5)
ft_cbow_model.save('model/ft_cbow.model')
print('Finish fastText CBOW')

```

# 単語埋め込みの様子を見てみる

こんな感じのソースを用意しました。
今回試したのは、以下の四つのモデルです。

* Word2Vec (Skip-gram)
* Word2Vec (CBOW)
* fastText (Skip-gram)
* fastText (CBOW)

```python:word_embedding.py
import pprint
from gensim.models.fasttext import FastText
from gensim.models import Word2Vec


# 単語
positive = []
negative = []

# データ読み込み
# --------------------------------------------------
# 単語埋め込み情報の獲得
# --------------------------------------------------
sg_model = Word2Vec.load('model/sg.model')
cbow_model = Word2Vec.load('model/cbow.model')
ft_sg_model = FastText.load('model/ft_sg.model')
ft_cbow_model = FastText.load('model/ft_cbow.model')

# Word2Vec (Skip-gram)
similar_words = sg_model.wv.most_similar(
    positive=positive, negative=negative, topn=5)
print('Word2Vec (Skip-gram)')
pprint.pprint(similar_words)
print()

# Word2Vec (CBOW)
similar_words = cbow_model.wv.most_similar(
    positive=positive, negative=negative, topn=5)
print('Word2Vec (CBOW)')
pprint.pprint(similar_words)
print()

# fastText (Skip-gram)
similar_words = ft_sg_model.wv.most_similar(
    positive=positive, negative=negative, topn=5)
print('fastText (Skip-gram)')
pprint.pprint(similar_words)
print()

# fastText (CBOW)
similar_words = ft_cbow_model.wv.most_similar(
    positive=positive, negative=negative, topn=5)
print('fastText (CBOW)')
pprint.pprint(similar_words)
print()

```

## Javaに似た単語は？

やってみます。
注）前処理で大文字→小文字変換を行なっているため、結果は全て小文字になっています。

```
Word2Vec (Skip-gram)
[('kotlin', 0.721146821975708),
 ('scala', 0.7156604528427124),
 ('jvm', 0.7039327621459961),
 ('groovy', 0.7008844614028931),
 ('jdk', 0.6704262495040894)]

Word2Vec (CBOW)
[('kotlin', 0.7293031811714172),
 ('scala', 0.7025946378707886),
 ('groovy', 0.6870735883712769),
 ('c#', 0.6510794162750244),
 ('jvm', 0.6288336515426636)]

fastText (Skip-gram)
[('javasript', 0.7638771533966064),
 ('java0', 0.7570677995681763),
 ('javap', 0.756486177444458),
 ('javasdk', 0.7484714388847351),
 ('javaw', 0.7446058392524719)]

fastText (CBOW)
[('javaw', 0.9195868968963623),
 ('javap', 0.9180891513824463),
 ('java0', 0.9162457585334778),
 ('rjava', 0.9135065078735352),
 ('javasript', 0.8905590176582336)]
```

Word2VecではKotlinが一位！
一方fastTextはjavasript(JavaS'c'riptですらない)などと仰っています。本当か・・・？

## じゃあJavaScriptに似た単語は？

jQuery、CoffeeScriptが出てくるようです。TypeScriptは出てこないんですね。
また、fastTextの結果から**JavaScriptはtypoしやすい**という重要な知見が得られました。

```
Word2Vec (Skip-gram)
[('jquery', 0.6775738000869751),
 ('coffeescript', 0.6770436763763428),
 ('js', 0.6437661647796631),
 ('javascirpt', 0.637963056564331),
 ('css', 0.6350248456001282)]

Word2Vec (CBOW)
[('coffeescript', 0.6459994912147522),
 ('クライアントサイド', 0.6359869837760925),
 ('jquery', 0.6306584477424622),
 ('javascirpt', 0.6256442666053772),
 ('webassembly', 0.5922628045082092)]

fastText (Skip-gram)
[('javascrip', 0.8898588418960571),
 ('javascipt', 0.8314067721366882),
 ('reascript', 0.8168306946754456),
 ('javasctipt', 0.813858687877655),
 ('javascirpt', 0.7917824983596802)]

fastText (CBOW)
[('javascrip', 0.9571106433868408),
 ('javasctipt', 0.9136332273483276),
 ('javascriptcore', 0.902661144733429),
 ('javascipt', 0.8993234634399414),
 ('javascirpt', 0.8857988119125366)]
```

## JavaScript+サーバ-ブラウザ=?
Node.jsになることを期待しましたが・・・？

```
Word2Vec (Skip-gram)
[('サイド', 0.6167241334915161),
 ('クライアントサイド', 0.5421619415283203),
 ('node.js', 0.532085120677948),
 ('サーバー', 0.5232232213020325),
 ('フロント', 0.4977383017539978)]

Word2Vec (CBOW)
[('クライアントサイド', 0.5689905881881714),
 ('サーバー', 0.5387918949127197),
 ('フロントエンド', 0.5109777450561523),
 ('バックエンド', 0.5094153881072998),
 ('フロント', 0.5013124346733093)]

fastText (Skip-gram)
[('サイド', 0.6113017797470093),
 ('サーバーサイドプログラミング', 0.5575705766677856),
 ('クライアントサイド', 0.5540342330932617),
 ('サーバー', 0.5538838505744934),
 ('node.js', 0.5490145087242126)]

fastText (CBOW)
[('サーバーワークス', 0.682847261428833),
 ('サーバサイドアプリケーション', 0.6821614503860474),
 ('サーバーサイドスクリプト', 0.6803215742111206),
 ('サーバント', 0.655984103679657),
 ('javasctipt', 0.6549049615859985)]
```

「サーバーサイド」が二語に別れてしまい、大分邪魔していますね。類似度は低いものの、Word2Vec (Skip-gram)とfastText (Skip-gram)ではNode.jsが登場しています。

## おまけ： Qiita＋記事-いいね
Qiitaの記事からいいねがなくなったら。

```
Word2Vec (Skip-gram)
[('解説', 0.5123943090438843),
 ('参考', 0.5046669244766235),
 ('続編', 0.5001996159553528),
 ('について', 0.499592125415802),
 ('本', 0.4853358566761017)]

Word2Vec (CBOW)
[('ブログ', 0.5708048939704895),
 ('ブログ記事', 0.5347858667373657),
 ('資料', 0.5178197026252747),
 ('tips', 0.47396498918533325),
 ('日記', 0.46794208884239197)]

fastText (Skip-gram)
[('ブログ', 0.5461423397064209),
 ('リンク集', 0.5251568555831909),
 ('参考', 0.5230625867843628),
 ('について', 0.5179448127746582),
 ('qita', 0.5117931365966797)]

fastText (CBOW)
[('特集記事', 0.6208770275115967),
 ('記事化', 0.613355278968811),
 ('ブログ記事', 0.5975614786148071),
 ('quiita', 0.5818290710449219),
 ('新聞記事', 0.5802720189094543)]
```

単なる解説やブログになってしまいます。
皆さんいいねしましょう。


# おわりに
fastTextのサブワードを考慮する性質は技術用語にはあまり向かないことが分かりました。

全体的には、なかなか面白い結果が出たのではないでしょうか。
前処理の段階でもう少しちゃんとやれば精度は大分上がりそうな印象です。

前々回→
[Qiitaコーパスを作る会 1️⃣Qiitaの全記事を取得してみる](https://qiita.com/LeftLetter/items/24ed8f792f56a2ec2392)
前回→
[Qiitaコーパスを作る会 2️⃣前処理をする](https://qiita.com/LeftLetter/items/80b40574311448ea9290)