Python クラス数を指定して分類するクラスター分析「k-means」

'22/07/02更新:クラスタリング前の散布図を冒頭に追加
 本記事では、クラス数を指定してクラスター分析(クラスタリング)する雛形コードを載せました。分析結果は、グラフ化してcsvファイルに出力する仕様です。
 例題データには、siciki-learnにあるワインデータセットを使用しました。下図はそのデータの散布図です。

そして、下図は本プログラムを実行した例です。クラス数(分類数)に3を指定して3つに分類した場合です。

f:id:HK29:20210520005558p:plain

次に、下図は分類数に4を指定して4つに分類した場合です。グラフのプロットで工夫しています。分類数が多い場合は、凡例を右外に出したり、マーカーの塗りつぶしをなくすことで見易くなる場合もあります。

f:id:HK29:20210607204537p:plain

ちなみに、下図のようにエルボー法によって、分類数を推定するコードも記載しています。変化率が小さくなった時点で判断します。この場合は3から4で変化率が小さいため3が妥当かと推定します。

f:id:HK29:20210519233019p:plain

■本プログラム

#!/usr/bin/env python
# coding: utf-8

# In[1]:


from sklearn import datasets
from sklearn import preprocessing
from sklearn.cluster import KMeans
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
plt.rcParams['font.size'] = 18 # グラフの基本フォントサイズの設定

wine_data = datasets.load_wine()
df = pd.DataFrame(wine_data.data, columns=wine_data.feature_names)
df


# In[2]:


# クラスタリングするデータの抽出
column_list = ["alcohol","color_intensity"]
X = df[column_list]


# In[3]:


# ヒストグラムの作成
X.hist()
plt.tight_layout()


# In[4]:


# 標準化(平均0, 標準偏差1)インスタンス
scaler = preprocessing.StandardScaler()

# 標準化を実行し変数に代入する
scaler.fit(X)
scaled_X = scaler.transform(X)
#scaled_X


# In[5]:


# エルボー法によるクラスタリング数の推定
sse_list = []
for i in range(1,11):            
    km = KMeans(n_clusters=i,
                random_state=0)
    km.fit(scaled_X)                         
    sse_list.append(km.inertia_)  

plt.plot(range(1,11), sse_list, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('SSE')
plt.grid(True)
#plt.savefig('elbow-chart.jpg')
#plt.close()


# In[6]:


# クラスタリングの実行
cls = KMeans(n_clusters=4)
result = cls.fit(scaled_X)
result


# In[7]:


# クラスタリングした集合体の個々の値を戻す
inversed_X = scaler.inverse_transform(scaled_X)
inversed_X


# In[8]:


# パンダスデータフレームへ変換
df = pd.DataFrame(inversed_X, columns=column_list)
df


# In[9]:


# クラスタリング結果
labels = result.labels_
labels


# In[10]:


# クラスタリング結果をパンダスへ変換
df2 = pd.DataFrame(labels, columns=['label'])
df2


# In[11]:


# データフレームを列方向へ結合する
DF = pd.concat([df, df2], axis=1)
DF.to_csv('k-means.csv')
DF


# In[12]:


# クラスター分析のセンター値の取得
print(result.cluster_centers_)


# In[13]:


# クラスター分析のセンター値を実際の値へ戻す
inversed_center = scaler.inverse_transform(result.cluster_centers_)
inversed_center


# In[15]:


# クラスタリング結果をグラフ化
markers = ['o', '^', ',', 'v']
colors = cm.rainbow(np.linspace(0, 1, len(DF['label'].unique())))
for i, p in enumerate(DF['label'].unique()):
    plt.scatter(DF.loc[DF.label == p, column_list[0]],
                DF.loc[DF.label == p, column_list[1]],
                marker = markers[i],
                facecolor = 'None',
                edgecolors = colors[i],
                label = 'label_' + str(p),
                )
plt.scatter(inversed_center[:,0],
            inversed_center[:,1],
            s=250,
            marker='*',
            edgecolors="black",
            c='yellow')
plt.xlabel(column_list[0])
plt.ylabel(column_list[1])
#plt.legend(loc='best', fontsize=14)
plt.legend(bbox_to_anchor=(1, 0.95))
plt.tick_params()
plt.grid()
#plt.savefig('k-means.jpg')
#plt.close()


# In[ ]:

以上

<広告>