import matplotlib.pyplot as pltfrom matplotlib import gridspecfig = plt.figure(figsize=(100, 100))fig.subplots_adjust(bottom=0.5)f,ax=plt.subplots(2,3)# 3x2 의 Figure 와 Axes#각 subplot 크기를 조정하는 방법gs = gridspec.GridSpec(nrows=2, # row 몇 개 ncols=3, # col 몇 개 height_ratios=[1, 1], #height 비율 width_ratios=[1,1,1] #width 비율 )#noisy_circles plotax[0]= plt.subplot(gs[0])ax[0]=plt.scatter(X1[:, 0], X1[:, 1], s=10, color=colors1[y1])# noisy_moons plotax[0]= plt.subplot(gs[1])ax[0]= plt.scatter(X2[:, 0], X2[:, 1], s=10, color=colors2[y2])# blobs plotax[0]= plt.subplot(gs[2])ax[0]= plt.scatter(X3[:, 0], X3[:, 1], s=10, color=colors3[y3])# no_structure plotax[0]= plt.subplot(gs[3])ax[0]= plt.scatter(X4[:, 0], X4[:, 1], s=10, color=y4)#no_structure 의 y4는 None이므로 colors 함수에 대입하지 않았다.# aniso plotax[0]= plt.subplot(gs[4])ax[0]= plt.scatter(X5[:, 0], X5[:, 1], s=10, color=colors5[y5])# varied plotax[0]= plt.subplot(gs[5])ax[0]= plt.scatter(X6[:, 0], X6[:, 1], s=10, color=colors6[y6])plt.tight_layout()plt.show()
KMeans Clustering
# KMeans 군집 모델 package importfrom sklearn.cluster import KMeans
# 각 모형에서 원래 group 수 대로 clustering prediction 진행y1_pred=KMeans(n_clusters=2, random_state=0).fit_predict(X1)y2_pred=KMeans(n_clusters=2, random_state=0).fit_predict(X2)y3_pred=KMeans(n_clusters=3, random_state=0).fit_predict(X3)y4_pred=KMeans(n_clusters=5, random_state=0).fit_predict(X4)#group 수 임의로 지정y5_pred=KMeans(n_clusters=3, random_state=0).fit_predict(X5)y6_pred=KMeans(n_clusters=3, random_state=0).fit_predict(X6)
보면 집단이 원으로 뭉쳐있는 3번째(위->아래, 왼쪽->오른쪽 순) 그룹만 잘 분류가 되었고 나머지는 분류가 잘 안됨을 알 수 있다. KMeans clustering은 각 그룹이 빽빽히 뭉쳐있는 경우가 아니면 정확도가 낮음을 알 수 있다. 특히나 뭉쳐진 모양이 아닌 1,2,5번째와 같이 특정 모양을 띨 경우 더더욱이 분류가 안됨을 알 수 있다.
Agglomerative Clustering
from sklearn.cluster import AgglomerativeClustering# 각 모형에서 원래 group 수 대로 clustering prediction 진행y1_pred=AgglomerativeClustering(n_clusters=2).fit_predict(X1)y2_pred=AgglomerativeClustering(n_clusters=2).fit_predict(X2)y3_pred=AgglomerativeClustering(n_clusters=3).fit_predict(X3)y4_pred=AgglomerativeClustering(n_clusters=5).fit_predict(X4)#group 수 임의로 지정y5_pred=AgglomerativeClustering(n_clusters=3).fit_predict(X5)y6_pred=AgglomerativeClustering(n_clusters=3).fit_predict(X6)
Agglomerative Clustering을 진행한 결과 kmeans와는 살짝 다른 결과가 도출되었다. 6번째 모형을 보면 원래 분류와 거의 동일하게 분류가 됨을 알 수 있었다. 또한 kmeans clustering은 나눠진 그룹의 크기가 거의 같도록 분류되었다면 agglomerative clustering은 이에 구애받지 않고 group이 나누어짐을 알 수 있었다.(이는 1,2번의 파란색 group의 크기가 더 큼을 통해 추론 가능하다. kmeans는 색깔별 크기가 거의 동일)
Different clustering methods
이제 다양한 clustering 방법을 통해 분류를 진행해보겠다. 여기서 쓰일 clustering method는 다음과 같다.
KMeans, DBSCAN, Agglomerative Clustering, Mean shift, Spectral Clustering, Birch
noisy circles는 spectral clustering이 잘 되는 듯 보인다. DBSCAN과 meanshift method도 다른 것과는 달리 원형 모향을 잘 살려 clustering한 것을 알 수 있는데 안쪽과 바깥쪽을 구분 못하고 하나로 인식한 것이 아쉬운 점이다.
plotall2(datasets[1])
noisy moons는 DBSCAN과 Spectral Clustering이 뛰어난 성능을 보인다.
plotall3(datasets[2])
blobs는 agglomerative clustering, kmeans, MeanShift, spectral clustering, birch가 정확하게 분류하였다. 제일 분류하기 쉬운 모형이긴 한 것 같다.
plotall2(datasets[3])
no_structure은 DBSCAN과 MeanShift가 제대로 clustering하였다. 하지만 agglomerative clustering과 kmeans, spectral clustering, birch는 number of clusters를 지정해 주었기 때문에 위와 같은 결과를 냈음으로 판단된다.
plotall3(datasets[4])
aniso는 spectral clustering이 제일 비슷하게 clustering을 진행한 것으로 보인다. agglomerative clustering은 조금 아쉬운 결과를 내었는데 그래도 이와 같은 모형에서는 나름 성능이 좋아 보인다.
plotall3(datasets[5])
varid는 Agglomerative clustering과 spectral clustring이 제일 좋은 성능을 내었고, kmeans가 조금 아쉬운 결과를 내었다.
Min(Single Link) , Max(Complete Link), Group Average, Centroid, Ward
from scipy.cluster.hierarchy import dendrogram, ward, linkageX, y = datasets.make_blobs(random_state=0, n_samples=15)colors = np.array(list(islice(cycle(['#377eb8', '#ff7f00', '#4daf4a','#f781bf', '#a65628', '#984ea3', '#999999', '#e41a1c', '#dede00']), int(max(y) + 1))))
# add black color for outliers (if any)colors = np.append(colors, ["#000000"])plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y])#각 점이 몇번째 점인지 출력for i inrange(len(X)): x = X[i,0] y = X[i,1]#plt.plot(x, y) plt.text(x * (1+0.02), y * (1+0.02) , i, fontsize=12)plt.show()
Min(Single Link) Method
#method=’single’는 Nearest Point Algorithm을 나타내는 것으로#min(single link) proximity를 나타내는 것이다.linkage_array =linkage(X, method='single', metric='euclidean')# 클러스터 간의 거리 정보가 담긴 linkage_array를 사용해 덴드로그램을 그립니다dendrogram(linkage_array)# 두 개와 세 개의 클러스터를 구분하는 커트라인을 표시합니다ax = plt.gca()bounds = ax.get_xbound()ax.plot(bounds, [3, 3], '--', c='k')ax.plot(bounds, [1.9, 1.9], '--', c='k')ax.text(bounds[1], 3, ' 2 Clusters ', va='center', fontdict={'size': 15})ax.text(bounds[1], 1.9, ' 3 Clusters ', va='center', fontdict={'size': 15})plt.xlabel("샘플 번호")plt.ylabel("클러스터 거리")#https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.linkage.html
Max(Complete Link) Method
#method=’complete’는 Farthest Point Algorithm(Voor Hees Algorithm)을 나타내는 것으로#Max(complete link) Proximity를 나타내는 것이다.linkage_array =linkage(X, method='complete', metric='euclidean')# 클러스터 간의 거리 정보가 담긴 linkage_array를 사용해 덴드로그램을 그립니다dendrogram(linkage_array)# 두 개와 세 개의 클러스터를 구분하는 커트라인을 표시합니다ax = plt.gca()bounds = ax.get_xbound()ax.plot(bounds, [6.5, 6.5], '--', c='k')ax.plot(bounds, [5.5, 5.5], '--', c='k')ax.text(bounds[1], 6.5, ' 2 Clusters ', va='center', fontdict={'size': 15})ax.text(bounds[1], 5.5, ' 3 Clusters ', va='center', fontdict={'size': 15})plt.xlabel("샘플 번호")plt.ylabel("클러스터 거리")
Group Average Method
#method=’average’는 group aberage Proximity를 나타내는 것이다.linkage_array =linkage(X, method='average', metric='euclidean')# 클러스터 간의 거리 정보가 담긴 linkage_array를 사용해 덴드로그램을 그립니다dendrogram(linkage_array)# 두 개와 세 개의 클러스터를 구분하는 커트라인을 표시합니다ax = plt.gca()bounds = ax.get_xbound()ax.plot(bounds, [4.5, 4.5], '--', c='k')ax.plot(bounds, [3.5, 3.5], '--', c='k')ax.text(bounds[1], 4.5, ' 2 Clusters ', va='center', fontdict={'size': 15})ax.text(bounds[1], 3.5, ' 3 Clusters ', va='center', fontdict={'size': 15})plt.xlabel("샘플 번호")plt.ylabel("클러스터 거리")
Centroid Method
#method=’centriod’는 centriod Proximity를 나타내는 것이다.linkage_array =linkage(X, method='centroid', metric='euclidean')# 클러스터 간의 거리 정보가 담긴 linkage_array를 사용해 덴드로그램을 그립니다dendrogram(linkage_array)# 두 개와 세 개의 클러스터를 구분하는 커트라인을 표시합니다ax = plt.gca()bounds = ax.get_xbound()ax.plot(bounds, [4,4], '--', c='k')ax.plot(bounds, [3, 3], '--', c='k')ax.text(bounds[1], 4, ' 2 Clusters ', va='center', fontdict={'size': 15})ax.text(bounds[1], 3, ' 3 Clusters ', va='center', fontdict={'size': 15})plt.xlabel("샘플 번호")plt.ylabel("클러스터 거리")
Ward Method
# 데이터 배열 X 에 ward 함수를 적용합니다# 이는 병합 군집을 수행할 때 생성된 거리 정보가 담긴 배열을 리턴합니다linkage_array =ward(X)# 클러스터 간의 거리 정보가 담긴 linkage_array를 사용해 덴드로그램을 그립니다dendrogram(linkage_array)# 두 개와 세 개의 클러스터를 구분하는 커트라인을 표시합니다ax = plt.gca()bounds = ax.get_xbound()ax.plot(bounds, [10, 10], '--', c='k')ax.plot(bounds, [7, 7], '--', c='k')ax.text(bounds[1], 10, ' 2 Clusters ', va='center', fontdict={'size': 15})ax.text(bounds[1], 7, ' 3 Clusters ', va='center', fontdict={'size': 15})plt.xlabel("샘플 번호")plt.ylabel("클러스터 거리")
5가지 method의 2,3 clusters로 구분되는 대략적인 거리를 정리해보면 다음과 같다.
Min(single link)method : 3, 1.9
Max(complete link)method: 6.5, 5.5
Group average method: 4.5, 3.5
Centroid method: 4, 3
Ward method: 10, 7
구분 거리는 min < centriod < group average < max < ward 순으로 나타낼 수 있다.
Single linkage는 두 그룹이 묶일 때 한 쌍의 point들만 가까우면 되므로 만들어진 cluster가 너무 분산되어 있을 가능성이 있다.
위 결과에서 보면 1이 (0,4,8)이 아닌 (5,6,10,11,..)에 묶여 있는 것으로 이를 확인할 수 있다.
반대로 complete linkage는 만들어지는 cluster가 너무 밀집되어 있을 가능성이 크다.
이 둘을 완화하는 방법이 group average method와 centroid method라 볼 수 있을 것 같다.
3) K-Means Clustering
초기값/update Centroid
kmeans clustering은 centriod 위치를 정하고, 그 위치에서 데이터까지의 distance 연산을 통해 clustering하는 알고리즘이다.
그러하여 Centriod 위치 지정이 중요한데 이를 지정하는 방법은 다음과 같다.
Random Partition
임의로 cluster number를 부여하여 clustering 진행.
Forgy/Lloyd
데이터 중 K개의 데이터를 뽑아(중복X) Centroid로 설정, clustering 진행 완료 후 centroid 재설정. 이를 반복
MacQueen
데이터 중 K개의 데이터를 뽑아(중복X) Centroid로 설정, clustering 진행 [여기까지는 forgy와 같음], 만약 한 데이터가 현재 속해 있는 cluster(A)의 centroid보다 다른 cluster(B)의 centroid가 더 가깝다고 판단되는 경우 데이터는 B cluster에 할당되고 cluster의 centroid가 현재 cluster에 속한 데이터의 평균으로 다시 계산된다.
Hartigan & Wong
within-cluster sum of squares of errors를 최소화하는 알고리즘.
centroid초기 설정은 forgy와 같으며 가까운 centroid에 데이터가 속한 것도 같으나 만약 cluster 변경이 생긴 경우 SSE를 계산하여 cluster 변경 후의 SSE가 더 작은 경우에만 변경 유지.