機械学習初心者による自然言語処理考察②

#はじめに

自然言語処理100本ノック第7章で「階層型クラスタリング」が出てきたので、初心者の私なりに理解できた部分を記載する。

###第7章-68 問題文
>国名に関する単語ベクトルに対し，Ward法による階層型クラスタリングを実行せよ．さらに，クラスタリング結果をデンドログラムとして可視化せよ．

###第7章-68 解答
以下のコードが正解となっている。（[こちらの記事](https://qiita.com/yamaru/items/822af1f7f77666381e20)より引用）

```python
from sklearn.cluster import KMeans

# k-meansクラスタリング
kmeans = KMeans(n_clusters=5)
kmeans.fit(countries_vec)
for i in range(5):
    cluster = np.where(kmeans.labels_ == i)[0] #cluster毎に分類されたcuntriesのラベル（3,17,18,...）を取得
    print('cluster', i)
    print(', '.join([countries[k] for k in cluster])) #取得したラベルに紐づくcuntries(3:Zambia,17:Sudan,18:Namibia,...)を表示
```
```:出力
cluster 0
Zambia, Sudan, Namibia, Uganda, Guinea, Kenya, Zimbabwe, Angola, Gabon, Rwanda, Nigeria, Mozambique, Mauritania, Algeria, Madagascar, Ghana, Mali, Tunisia, Liberia, Niger, Senegal, Malawi, Eritrea, Burundi, Gambia, Botswana
cluster 1
Albania, Kazakhstan, Russia, Slovakia, Montenegro, Ukraine, Hungary, Turkey, Azerbaijan, Poland, Greece, Bulgaria, Romania, Lithuania, Slovenia, Moldova, Estonia, Belarus, Macedonia, Serbia, Latvia, Croatia, Armenia, Georgia, Cyprus, Uzbekistan, Turkmenistan
cluster 2
Ecuador, Guyana, Fiji, Suriname, Samoa, Nicaragua, Belize, Chile, Cuba, Bahamas, Peru, Tuvalu, Mexico, Jamaica, Colombia, Dominica, Venezuela, Honduras
cluster 3
England, Morocco, Switzerland, Greenland, Uruguay, Europe, Germany, Austria, Argentina, Australia, USA, Sweden, Ireland, Iceland, Belgium, Spain, Denmark, Finland, Canada, Netherlands, Liechtenstein, France, Norway, Malta, Brazil, Portugal, Italy, Japan
cluster 4
Indonesia, Iraq, Taiwan, India, Korea, Kyrgyzstan, Vietnam, Libya, Somalia, Iran, Jordan, Bangladesh, Qatar, Egypt, Nepal, China, Thailand, Cambodia, Lebanon, Bhutan, Malaysia, Tajikistan, Bahrain, Syria, Oman, Pakistan, Laos, Afghanistan, Philippines, Israel
```

```python:
from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage

plt.figure(figsize=(15, 5))
Z = linkage(countries_vec, method='ward')
dendrogram(Z, labels=countries)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950731/4dc3bd12-88ef-8762-6ef2-dad8d15dec07.png)


##linkage関数
ここで理解に苦しんだのは「linkage関数」である。
linkageはScipyに含まれるパッケージであり、以下のような構造となっている。

```python:
scipy.cluster.hierarchy.linkage(df, method='ward', metric='euclidean', optimal_ordering=False)
```
引数methodで、階層型クラスタリングの手法を選択している。
- method = 'single':最小結合法
- method = 'complite':最大結合法
- method = 'average':群平均法
- method = 'ward':ウォード法
今回選択した「ウォード法」とは、凝集型階層的クラスタリングと呼ばれるクラスタリングの手法の１つ。
凝集型階層的クラスタリングとは、
１．全ての点が別々のクラスタである状態から始める
２．「今あるクラスタの中で、最も距離が近い２つのクラスタを選んで１つのクラスタに合体する」という操作を行う
３．合体を目標のクラスタ数になるまで繰り返す
という手法となっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950731/d9daf777-70d7-86a9-221c-396c2a21d5dc.png)
引用元：[ウォード法によるクラスタリングのやり方](https://mathwords.net/wardmethod)

なお、```metric='euclidean'```については、点どうしの距離をユークリッド距離（２点間の直線距離）で定義するという意味である。他にもミンコフスキー距離・コサイン距離などを選択できるようだが、基本的にユークリッド距離を選択すれば良いようなので割愛する。

話を戻すと、

```python:
Z = linkage(countries_vec, method='ward')
dendrogram(Z, labels=countries)
```
ここではlinkage関数を用いて、countries_vec(国名一覧を単語ベクトルで表したもの)をウォード法により目標のクラスタ数(=5)になるまでクラスタリングを繰り返している、ということになる。