言語処理100本ノック-97(scikit-learn使用):k-meansクラスタリング

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の97本目「k-meansクラスタリング」の記録です。
前回ノックで得た国名の単語ベクトルを使って国を5つのかたまり(クラスタ)に分類します。
その際に使うK-Meansは[「Coursera機械学習入門コース(8週目 - 教師なし学習(K-MeansとPCA))」](https://qiita.com/FukuharaYohei/items/7a71be58818719cdf73c)で学んだ内容で、クラスタリングの手法です。

# 参考リンク

|リンク|備考|
|:--|:--|
|[097.k-meansクラスタリング.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)/097.k-means%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0.ipynb)|回答プログラムのGitHubリンク|
|[素人の言語処理100本ノック:97](https://qiita.com/segavvy/items/e38710fed6c1cb8c5d2d)|言語処理100本ノックで常にお世話になっています|

# 環境

|種類|バージョン|内容|
|:--|:--|:--|
|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でインストールするだけです。

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

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

### 97. k-meansクラスタリング
> 96の単語ベクトルに対して，k-meansクラスタリングをクラスタ数$ k=5 $として実行せよ．

#### 課題補足(K-Means)
K-Meansに関しては[「K-means 法を D3.js でビジュアライズしてみた」](http://tech.nitoyon.com/ja/blog/2013/11/07/k-means/)がわかりやすいです。統計や数理的な部分をスキップして感覚的に理解できます。
物足りない人には無料の[Coursera機械学習入門コース](https://www.coursera.org/learn/machine-learning/)がおすすめで、内容は記事[「Coursera機械学習入門オンライン講座虎の巻(文系社会人にオススメ)」](https://qiita.com/FukuharaYohei/items/b2143413063376e97948)にまとめています。

# 回答
## 回答プログラム [097.k-meansクラスタリング.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)/097.k-means%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0.ipynb)

```python
import pandas as pd
from sklearn.cluster import KMeans

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

# K-Meansクラスタリング
country_vec['class'] = KMeans(n_clusters=5).fit_predict(country_vec)

for i in range(5):
    print('{} Cluster:{}'.format(i, country_vec[country_vec['class'] == i].index))
```

## 回答解説
前回ノックのファイルを読み込みます。

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

DataFrameとして以下の属性が出力されます。

```bash
<class 'pandas.core.frame.DataFrame'>
Index: 238 entries, American_Samoa to Zimbabwe
Columns: 300 entries, 0 to 299
dtypes: float64(300)
memory usage: 559.7+ KB
None
```

Scikit-learnだとこれだけでK-Meansできます。DataFrameを渡せるのが便利です。

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

クラスタリング結果をざっと見てみます。

```python
for i in range(5):
    print('{} Cluster:{}'.format(i, country_vec[country_vec['class'] == i].index))
```

クラスタ0が153と異常に多いですが、その他といった感じなのでしょうか。
クラスタ1はニュージーランド・イギリス、日本などいわゆる海洋国家っぽくもあるのですが、インドや中国も含んでいます。
クラスタ2はヨーロッパの国々が多いですが、ブラジルやアルゼンチンなど混ざっています。
成功しているのか判断しかねる微妙な結果です。

```bash
0 Cluster:Index(['American_Samoa', 'Antigua_and_Barbuda', 'Bosnia_and_Herzegovina',
       'Burkina_Faso', 'Cabo_Verde', 'Cayman_Islands',
       'Central_African_Republic', 'Christmas_Island', 'Keeling_Islands',
       'Cocos_Islands',
       ...
       'Tonga', 'Tunisia', 'Turkmenistan', 'Tuvalu', 'Uruguay', 'Uzbekistan',
       'Vanuatu', 'Yemen', 'Zambia', 'Zimbabwe'],
      dtype='object', length=153)
1 Cluster:Index(['New_Zealand', 'United_Kingdom', 'United_States', 'Australia', 'Canada',
       'China', 'India', 'Ireland', 'Israel', 'Japan', 'Pakistan'],
      dtype='object')
2 Cluster:Index(['Argentina', 'Austria', 'Belgium', 'Brazil', 'Bulgaria', 'Denmark',
       'Egypt', 'Finland', 'France', 'Germany', 'Greece', 'Hungary', 'Italy',
       'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Spain',
       'Sweden', 'Switzerland'],
      dtype='object')
3 Cluster:Index(['Guinea', 'Jersey', 'Mexico'], dtype='object')
4 Cluster:Index(['Czech_Republic', 'Hong_Kong', 'People's_Republic_of_China',
       'Puerto_Rico', 'South_Africa', 'Sri_Lanka', 'Great_Britain',
       'Northern_Ireland', 'Afghanistan', 'Albania', 'Algeria', 'Angola',
       'Armenia', 'Azerbaijan', 'Bangladesh', 'Cambodia', 'Chile', 'Colombia',
       'Croatia', 'Cuba', 'Cyprus', 'Ethiopia', 'Fiji', 'Georgia', 'Ghana',
       'Iceland', 'Indonesia', 'Iraq', 'Kenya', 'Latvia', 'Lebanon', 'Libya',
       'Lithuania', 'Malaysia', 'Malta', 'Mongolia', 'Morocco', 'Nepal',
       'Nigeria', 'Panama', 'Peru', 'Philippines', 'Serbia', 'Singapore',
       'Slovakia', 'Sudan', 'Thailand', 'Turkey', 'Uganda', 'Ukraine'],
      dtype='object')
```