言語処理100本ノック-99(pandas使用):t-SNEによる可視化

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の99本目「t-SNEによる可視化」の記録です。
t-SNE(t-distributed Stochastic Neighbor Embedding)で2次元に削減をして単語ベクトルを下図のように可視化します。2次元や3次元なら人間が見てわかりますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/3a4b303f-5865-7915-9e59-94e6f1ef0fae.png)

# 参考リンク

|リンク|備考|
|:--|:--|
|[099.t-SNEによる可視化.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/099.t-SNE%E3%81%AB%E3%82%88%E3%82%8B%E5%8F%AF%E8%A6%96%E5%8C%96.ipynb)|回答プログラムのGitHubリンク|
|[素人の言語処理100本ノック:99](https://qiita.com/segavvy/items/fe530927df30732e2a46)|言語処理100本ノックで常にお世話になっています|
|[早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話](https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9)|今更ながらにMatplotlibの基本を少し覚えました|
|[color example code: colormaps_reference.py](https://matplotlib.org/examples/color/colormaps_reference.html)|MatplotlibのColor Map|

# 環境

|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.01 LTS|仮想で動かしています|
|pyenv|1.2.15|複数Python環境を使うことがあるのでpyenv使っています|
|Python|3.6.9|pyenv上でpython3.6.9を使っています<br>3.7や3.8系を使っていないことに深い理由はありません<br>パッケージはvenvを使って管理しています|

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

|種類|バージョン|
|:--|:--|
|matplotlib|3.1.1|
|pandas|0.25.3|
|scikit-learn|0.21.3|

# 課題
## [第10章: ベクトル空間法 (II)](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch10)
> 第10章では，前章に引き続き単語ベクトルの学習に取り組む．

### 99. t-SNEによる可視化
> 96の単語ベクトルに対して，ベクトル空間をt-SNEで可視化せよ．

#### 課題補足(t-SNE)
t-SNE(t-distributed Stochastic Neighbor Embedding)は次元を2または3に削減します。次元削減という意味では、PCA(主成分分析)と同じです。ただ、PCAでできない非線形構造をもつデータにも対応可能です。偉そうに書いていますが、数式を理解しておらず記事[「t-SNEによるイケてる次元圧縮&可視化」](https://qiita.com/stfate/items/8988d01aad9596f9d586)の受け売りです。

# 回答
## 回答プログラム [099.t-SNEによる可視化.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/099.t-SNE%E3%81%AB%E3%82%88%E3%82%8B%E5%8F%AF%E8%A6%96%E5%8C%96.ipynb)

```python
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.manifold import TSNE
from sklearn.cluster import KMeans

country_vec = pd.read_pickle('./096.country_vector.zip')
print(country_vec.info())

# t-SNE
t_sne = TSNE().fit_transform(country_vec)
print('t_sne shape:', t_sne.shape)

# KMeansクラスタリング
clustered = KMeans(n_clusters=5).fit_predict(country_vec)

fig, ax = plt.subplots(figsize=(22, 22))

# Set Color map
cmap = plt.get_cmap('Dark2')

for i in range(t_sne.shape[0]):
    cval = cmap(clustered[i] / 4)
    ax.scatter(t_sne[i][0], t_sne[i][1], marker='.', color=cval)
    ax.annotate(country_vec.index[i], xy=(t_sne[i][0], t_sne[i][1]), color=cval)
plt.show()
```

## 回答解説
全体の8割近くは[記事「素人の言語処理100本ノック:99」](https://qiita.com/segavvy/items/fe530927df30732e2a46)のコピペです。

ここが、今回のメインのコードです。[scikt-learnのTSNE](https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html)はいくつかパラメータがあるのですが、デフォルトのままで実行しました。[scikt-learnのTSNE](https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html)はあまりよくないと言及しているブログもありましたが、とりあえず気にせず行きます。

```python
t_sne = TSNE().fit_transform(country_vec)
```

あと、散布図で表示する色としてK-Meanで非階層クラスタリングをしています。

```python
clustered = KMeans(n_clusters=5).fit_predict(country_vec)
```

最後に`matplotlib`で散布図表示です。`plt.get_cmap`を使って表示色定義をしていて、どんな色かは[color example code: colormaps_reference.py](https://matplotlib.org/examples/color/colormaps_reference.html)に情報があります。
`scatter`で点を表示し、`annotate`でラベル(国名)を表示しています。
※今更恥ずかしながら`matplotlib`の基本を、少しだけ[記事「早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話」](https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9)で理解しました。

```python
fig, ax = plt.subplots(figsize=(22, 22))

# Set Color map
cmap = plt.get_cmap('Dark2')

for i in range(t_sne.shape[0]):
    cval = cmap(clustered[i] / 4)
    ax.scatter(t_sne[i][0], t_sne[i][1], marker='.', color=cval)
    ax.annotate(country_vec.index[i], xy=(t_sne[i][0], t_sne[i][1]), color=cval)
plt.show()
```
日本のあたりを拡大して見るとこんな感じです。前回ノックでやった階層的クラスタリングより、わかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/43ed1b5f-1ab7-b93d-dfe3-882813a7a946.png)