【機械学習入門】「K-meansクラスタリング」というのをやってみる♬競馬騎手評価;PCAとクラスタ数

前回の記事でグラフは相関が見えていることを示したが、今回は全てのデータを使って、本格的にクラスタ分類し、どの騎手がという分析をする。
ただし、重要な知見として、以下の事項は教訓として意識する必要がありそうです。
「最も重要な点は，クラスタリングは探索的 (exploratory) なデータ解析手法であって，分割は必ず何らかの主観や視点に基づいているということです．よって，クラスタリングした結果は，データの要約などの知見を得るために用い，客観的な証拠として用いてはなりません．」参考②から引用
また、今回の記事は、ほぼ参考①のコードと技術を使っています。
【参考】
・①[k-meansの最適なクラスター数を調べる方法](https://qiita.com/deaikei/items/11a10fde5bb47a2cf2c2)
・②[クラスタリング (クラスター分析)](http://www.kamishima.net/jp/clustering/)
・③[クラスタ数を自動推定するX-means法を調べてみた]()
###やったこと
・データの事前処理をする
・競馬騎手データの全データを使う⇒相関が見える
・1－20クラスタまで計算してdistortionをプロットする⇒最適クラスタ数を推定できる？
・シルエット係数を計算する⇒最適クラスタ数を推定できる？
・全データによるクラスタリングとPCA分析後の（第一成分、第二成分）のクラスタリング結果⇒多変量解析から次元圧縮
###・データの事前処理をする
今回は、事前処理として偏差値に換算してある意味平等に扱うこととした。
元データは以下のリンク先のとおりで大きいものは獲得賞金の454469000
から、小さいものは勝率などの0.211まで幅が広く、どうみても民主的にフィッティングされるとは思えなかったからである。
【参考】
・[・2019年度 リーディングジョッキー （全国）@騎手・調教師データ](http://www.jra.go.jp/datafile/meikan/#)のリーディングよりデータ取得
今回は、エクセル上で平均と標準偏差を求めて、偏差値を計算しました。
###・競馬騎手データの全データを使う⇒相関が見える

```py
import pandas as pd 
import matplotlib.pyplot as plt
from pandas.tools import plotting
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import numpy as np
```

```py
df = pd.read_csv("keiba_std2.csv", sep=',', na_values=".")
df.head() #データの確認
df.iloc[:, 1:].head() #解析に使うデータは２列目以降
print(df.iloc[:, 1:])
plotting.scatter_matrix(df[df.columns[1:]], figsize=(6,6), alpha=0.8, diagonal='kde')   #全体像を眺める
plt.savefig('k-means/keiba_std2_scatter_plot4.jpg')
plt.pause(1)
plt.close()
```
![keiba_std2_scatter_plot4.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/fa2def9f-1587-416c-55d0-3adf71fc22a5.jpeg)
コード的にはクラスタリング後colors確定後に描画しているが、データ間の相関は以下のとおり

```py
fig, axes = plt.subplots(nrows=13, ncols=13, figsize=(18, 18),sharex=False,sharey=False)
for i in range(1,14):
    for j in range(1,14):
        ax = axes[i-1,j-1]
        x_data=df[df.columns[i]]
        y_data=df[df.columns[j]]
        #print(x_data)
        ax.scatter(x_data,y_data,c=colors)
        cor=np.corrcoef(x_data,y_data)[0, 1]
        ax.set_title("{:.3f}".format(cor))
fig.savefig('k-means/pandas_std2_iris_line_axes'+str(s)+'.png')
```
![pandas_std2_iris_line_axes6.png](https://qiita-image-store.s3.amazonaws.com/0/233744/12f19276-8dc7-bbd0-f427-d3ac58f73485.png)
###・1－20クラスタまで計算してdistortionをプロットする⇒最適クラスタ数を推定できる？

```py
distortions = []
distortions1 = []
for i  in range(1,21):                # 1~20クラスタまで一気に計算 
    km = KMeans(n_clusters=i,
                init='k-means++',     # k-means++法によりクラスタ中心を選択
                n_init=10,
                max_iter=300,
                random_state=0)
    km.fit(df.iloc[:, 1:])                # クラスタリングの計算を実行
    distortions.append(km.inertia_)       # km.fitするとkm.inertia_が得られる
    UF = km.inertia_ + i*np.log(20)*5e2   # km.inertia_ + kln(size)
    distortions1.append(UF)   
fig=plt.figure(figsize=(12, 10))
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
ax1.plot(range(1,21),distortions,marker='o')
ax1.set_xlabel('Number of clusters')
ax1.set_ylabel('Distortion')
#ax1.yscale('log')
ax2.plot(range(1,21),distortions,marker='o')
ax2.set_xlabel('Number of clusters')
ax2.set_ylabel('Distortion')
ax2.set_yscale('log')
ax3.plot(range(1,21),distortions1,marker='o')
ax3.set_xlabel('Number of clusters')
ax3.set_ylabel('Distortion+klog')
ax3.set_yscale('log')
plt.pause(1)
plt.savefig('k-means/keiba_std2_Distortion.jpg')
plt.close()
```
二番目の図は、縦軸を対数目盛にしました。
本当に表現力が劇的に変化しているのであれば、対数グラフで変曲点が見えると考えましたが、。。もともと通常の図でどこでクロスオーバーが発生しているかを見極めるのは難しいところです。ということで、三番目の図も書いてみました。
これは、参考③のBIC的考え方のモデルの説明変数は多くなるのを抑制するという考え方から引いています（厳密性はありません）。
※これは適当に入れただけですが、思考実験的にはこういうクロスオーバーが発生することを期待します
※「クラスター数は客観的な証拠とならない」という前提なのでだいたいの妥当性があればよいということです
![keiba_std2_Distortion.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/450460d1-da84-10df-d276-b8bf9c639cd8.jpeg)
###・シルエット係数を計算する⇒最適クラスタ数を推定できる？

```py
from sklearn.metrics import silhouette_samples
from matplotlib import cm

cluster_labels = np.unique(y_km)  # y_kmの要素の中で重複を無くす s=6 ⇒ [0 1 2 3 4 5]
n_clusters=cluster_labels.shape[0]   # 配列の長さを返す。つまりここでは n_clustersで指定したsとなる
# シルエット係数を計算
silhouette_vals = silhouette_samples(df.iloc[:, 1:],y_km,metric='euclidean')  # サンプルデータ, クラスター番号、ユークリッド距離でシルエット係数計算
y_ax_lower, y_ax_upper= 0,0
yticks = []
for i,c in enumerate(cluster_labels):
        c_silhouette_vals = silhouette_vals[y_km==c]
        c_silhouette_vals.sort()
        y_ax_upper += len(c_silhouette_vals) 
        color = cm.jet(float(i)/n_clusters)
        plt.barh(range(y_ax_lower,y_ax_upper),
        c_silhouette_vals,
        height=1.0,
        edgecolor='none',
        color=color) 
        yticks.append((y_ax_lower+y_ax_upper)/2)          
        y_ax_lower += len(c_silhouette_vals)

silhouette_avg = np.mean(silhouette_vals)                
plt.axvline(silhouette_avg,color="red",linestyle="--")plt.yticks(yticks,cluster_labels + 1)
plt.ylabel('Cluster')
plt.xlabel('silhouette coefficient')
plt.savefig('k-means/keiba_std2_silhouette_avg'+str(s)+'.jpg')
plt.pause(1)
plt.close()
```
以下を見ると、現実のデータのクラスタリングは難しそう。。。
※一応、2クラスか３クラスあたりが妥当なのかな。。。
![keiba_silhouette_avg2.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/4699c27c-0da8-96d1-85cc-7c0176fea7ea.jpeg)
![keiba_silhouette_avg3.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/a2a6f321-f4b0-6fb9-8858-a36e6d996d29.jpeg)
![keiba_silhouette_avg4.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/1c7ce3cc-1c59-4092-fc44-ef48998f101b.jpeg)
![keiba_silhouette_avg5.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/515a418d-a675-1597-a4a6-662495722e05.jpeg)
![keiba_std2_silhouette_avg6.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/20652e17-cb0c-f738-b494-08b1e538f8ed.jpeg)
![keiba_silhouette_avg10.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/f54e3b10-fc3a-4b47-7626-9a45b99bc70a.jpeg)
###・PCA分析後の（第一主成分、第二主成分）面でのクラスタリング結果
多変量解析から次元圧縮してから、クラスタリングしてみました。
つまり、最大の関心はそのままクラスタリングしたものと変わるのかどうか。

まず、主成分分析を行い、x,y = feature[:, 0], feature[:, 1]により、第一、第二主成分をX=(x,y)に代入します。


```py
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 1:])
PCA(copy=True, n_components=None, whiten=False)
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 1:])
x,y = feature[:, 0], feature[:, 1]
#print(x,y) 
X=np.c_[x,y]
```
上記のX=(x,y)を使って、この二次元面においてK-meansを使ってクラスタリングします。

```py
kmeans_model = KMeans(n_clusters=s, random_state=10).fit(X)
print(kmeans_model.labels_)
print(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1])
colors = [color_codes[x] for x in kmeans_model.labels_]
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(6, 6))
for kx, ky, name in zip(x, y, df.iloc[:, 0]):
    plt.text(kx, ky, name, alpha=0.8, size=10)
plt.scatter(x, y, alpha=0.8, color=colors)
plt.scatter(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], c = "b", marker = "*", s = 50)
plt.title("Principal Component Analysis")
plt.xlabel("The first principal component score")
plt.ylabel("The second principal component score")
plt.savefig('k-means/keiba_std2_PCA12_plot'+str(s)+'.jpg')
plt.pause(1)
plt.close()
```
####多変量でクラスタリング結果
※そもそも射影した面での中心がずれているので示していない
![pca_Sn2345678910_512.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/455bc4dd-d69c-3ee4-08e0-07277f0f7430.gif)

####PCA後主成分-第二主成分面でクラスタリング結果
![pca_n2345678910_512.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/b8aa7391-85db-910f-97ae-473eae7f8a92.gif)

####多変量とPCA後クラスタリングの結果比較
２クラス；同じ
[0 0 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 1 1]
[0 0 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 1 1]
３クラス；同じ
[0 0 0 0 2 0 2 0 2 2 1 1 1 2 1 2 2 1 1 1]
[1 1 1 1 0 1 0 1 0 0 2 2 2 0 2 0 0 2 2 2]
４クラス；異なる
[3 3 3 3 3 1 0 1 0 0 2 2 2 0 2 0 0 2 2 2]
[0 0 0 2 2 0 2 0 3 2 1 1 1 3 1 3 3 3 1 1]
５クラス；同じ
[2 2 2 2 0 4 0 4 3 0 1 1 1 3 1 3 3 3 1 1]
[4 4 4 4 0 2 0 2 1 0 3 3 3 1 3 1 1 1 3 3]
６クラス；異なる
[4 3 3 3 0 5 0 5 2 0 1 1 1 2 1 2 2 2 1 1]
[2 2 2 2 0 4 0 4 3 0 1 1 1 3 5 3 3 1 1 1]
７クラス；異なる
[4 3 3 3 0 5 6 5 2 0 1 1 1 2 1 6 2 2 1 1]
[1 1 1 1 2 4 2 4 5 2 3 3 3 5 6 5 5 0 3 0]
８クラス；異なる
[0 2 2 2 6 4 6 4 1 5 3 3 3 1 7 1 1 1 3 3]
[2 2 2 2 0 4 0 4 3 0 1 1 1 3 5 3 3 6 7 6]
９クラス；異なる
[4 5 5 5 3 0 3 0 2 8 1 1 7 2 6 2 2 2 7 1]
[2 2 2 2 0 4 0 4 8 0 1 1 1 3 5 8 3 6 7 6]
１０クラス；異なる
[5 3 3 7 6 4 6 4 2 0 1 1 1 2 9 2 2 8 8 8]
[4 4 4 3 3 1 9 1 6 9 5 5 5 0 7 6 0 8 2 8]
###まとめ
・k-meansで実データクラスタリングをやった
・クラス数の妥当性を見出すのは難しいことが分かる
・PCAで次元削減するのは有効なようだが、多変量で実施したものと一致するとは限らない

・単なる距離だけでのクラスタリングでは限界がある
・次回はちょっと理論的な話をしたいと思う
###おまけ

```
name,1,2,3,4,5,6,Rwin,kijyototal,winratio,winratio2,win3,totalwin,money
Take,24,11,12,5,13,49,7,114,0.211,0.307,0.412,4042,454469000 
Lumail,21,20,21,7,9,36,6,114,0.184,0.360,0.544,978,445864000 
Kawada,19,24,12,9,11,28,3,103,0.184,0.417,0.534,1247,403594000 
Fukunaga,17,22,16,9,6,48,3,118,0.144,0.331,0.466,2170,377694000 
Iwata,17,17,14,10,8,65,7,131,0.130,0.260,0.366,1550,395310000 
Murphei,17,11,14,6,6,30,6,84,0.202,0.333,0.500,25,327974000 
Kitamura,16,11,13,17,6,53,6,116,0.138,0.233,0.345,664,340399000 
Demulo,16,8,12,7,4,24,5,71,0.225,0.338,0.507,944,308588000 
Miura,13,12,7,11,11,68,1,122,0.107,0.205,0.262,696,198769000 
Tosaki,12,15,12,6,13,49,6,107,0.112,0.252,0.364,953,286602000 
Fujioka,12,9,4,7,6,52,4,90,0.133,0.233,0.278,747,225422000 
Ikezoe,12,7,5,7,9,59,5,99,0.121,0.192,0.242,1126,232521000 
Sameshima,10,14,3,5,3,60,3,95,0.105,0.253,0.284,152,135654000 
Matsuyama,10,7,11,10,12,79,3,129,0.078,0.132,0.217,556,195037000 
Yokoyama,10,5,2,2,6,36,2,61,0.164,0.246,0.279,2742,131128000 
Tanabe,9,16,13,13,6,58,3,115,0.078,0.217,0.330,806,226342000 
Oono,9,14,8,15,14,64,1,124,0.073,0.185,0.250,504,185507000 
Maruyama,9,6,6,12,6,65,2,104,0.087,0.144,0.202,454,188557000 
Nishimura,9,5,7,7,4,47,0,79,0.114,0.177,0.266,22,89754000 
FujiokaK,9,5,7,6,11,60,3,98,0.092,0.143,0.214,517,121869000
```


```
        1      2      3      4      5      6   Rwin  kijyototal  winratio  \
0   71.24  49.21  54.81  41.01  64.77  49.81  65.29       55.35     66.46
1   65.47  64.19  72.97  46.40  52.84  42.34  60.51       55.35     60.68
2   61.63  70.86  54.81  51.80  58.80  37.75  46.18       49.64     60.68
3   57.78  67.52  62.88  51.80  43.89  49.23  46.18       57.42     52.12
4   57.78  59.20  58.84  54.50  49.86  59.00  65.29       64.17     49.12
5   57.78  49.21  58.84  43.70  43.89  38.90  60.51       39.77     64.54
6   55.86  49.21  56.82  73.39  43.89  52.11  60.51       56.39     50.83
7   55.86  44.21  54.81  46.40  37.93  35.45  55.73       33.02     69.46
8   50.09  50.87  44.71  57.20  58.80  60.72  36.62       59.50     44.20
9   48.17  55.87  54.81  43.70  64.77  49.81  60.51       51.71     45.27
10  48.17  45.88  38.66  46.40  43.89  51.53  50.96       42.89     49.76
11  48.17  42.55  40.68  46.40  52.84  55.55  55.73       47.56     47.20
12  44.32  54.20  36.64  41.01  34.95  56.13  46.18       45.48     43.77
13  44.32  42.55  52.79  54.50  61.78  67.04  46.18       63.14     37.99
14  44.32  39.22  34.62  32.91  43.89  42.34  41.40       27.83     56.40
15  42.40  57.53  56.82  62.59  43.89  54.98  46.18       55.87     37.99
16  42.40  54.20  46.73  67.99  67.75  58.42  36.62       60.54     36.92
17  42.40  40.88  42.70  59.89  43.89  59.00  41.40       50.16     39.92
18  42.40  39.22  44.71  46.40  37.93  48.66  31.84       37.18     45.70
19  42.40  39.22  44.71  43.70  58.80  56.13  46.18       47.04     40.99

    winratio2   win3  totalwin  money
0       57.51  56.07     80.87  66.96
1       64.24  67.69     49.31  66.19
2       71.49  66.81     52.08  62.44
3       60.56  60.82     61.59  60.14
4       51.54  52.02     55.20  61.70
5       60.81  63.82     39.50  55.72
6       48.11  50.17     46.08  56.82
7       61.45  64.43     48.96  54.00
8       44.55  42.86     46.41  44.25
9       50.52  51.84     49.05  52.05
10      48.11  44.27     46.93  46.61
11      42.90  41.10     50.84  47.24
12      50.65  44.80     40.80  38.64
13      35.27  38.90     44.97  43.91
14      49.76  44.36     67.48  38.24
15      46.07  48.85     47.54  46.70
16      42.01  41.80     44.43  43.07
17      36.80  37.57     43.92  43.34
18      40.99  43.21     39.47  34.56
19      36.67  38.63     44.56  37.42
```