K-means Clustering
` 각 군집에 할당된 포인트들의 평균 좌표를 이용해 중심점을 반복적으로 업데이트
각 데이터에 대해 가까운 데이터 찾고 새로 할당된 군집 기반으로 새로운 중심 계산
클러스터 할당이 바뀌지 않을 때까지 반복
거리는 Manhattan이나 Euclidean
K 설정 문제
최적화되 k를 찾기 어려움 -> Silhouette method 사용
- 객체와 그 객체가 속한 군집의 데이터들과의 비 유사성을 계산
a(i) : i와 i가 속한 군집 데이터들과의 비 유사성
b(i) : i가 속하지 않은 다른 군집의 모든 데이터들과의 비 유사성의 최솟값(가장 가까운 군집)
s(i) = $(b(i) - a(i)) / max{a(i), b(i)}
s(i)의 값이 1에 가까울수록 올바른 클러스터에 분류된 것이라 할 수 있음.
k를 증가시키며 평균 s(i), silhouette coefficient가 최대가 되는 k를 선택
K-means의 또 다른 문제는 이상치에 민감하다는 것인데 이를 해결하기 위해 K-medoids(중간점)를 사용
평균 대신 중앙값을 구한다고 생각하면 된다.
apply
Iris 데이터를 활용하여 Kmeans clustering
1
2
3
4
5
from sklearn import datasets
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.cluster import KMeans
iris = datasets . load_iris ()
1
2
X = iris . data [:, : 2 ]
y = iris . target
1
2
3
plt . scatter ( X [:, 0 ], X [:, 1 ], c = y , cmap = 'gist_rainbow' )
plt . xlabel ( 'Spea1 Length' , fontsize = 18 )
plt . ylabel ( 'Sepal Width' , fontsize = 18 )
1
2
km = KMeans ( n_clusters = 3 , n_jobs = 4 , random_state = 21 )
km . fit ( X )
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
n_clusters=3, n_init=10, n_jobs=4, precompute_distances='auto',
random_state=21, tol=0.0001, verbose=0)
각 군집의 center 보기
1
2
centers = km . cluster_centers_
print ( centers )
[[5.77358491 2.69245283]
[5.006 3.418 ]
[6.81276596 3.07446809]]
실제 분류된 값과 군집으로 분류된 값 비교
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
new_labels = km . labels_
fig , axes = plt . subplots ( 1 , 2 , figsize = ( 16 , 8 ))
axes [ 0 ] . scatter ( X [:, 0 ], X [:, 1 ], c = y , cmap = 'gist_rainbow' ,
edgecolor = 'k' , s = 150 )
axes [ 1 ] . scatter ( X [:, 0 ], X [:, 1 ], c = new_labels , cmap = 'jet' ,
edgecolor = 'k' , s = 150 )
axes [ 0 ] . set_xlabel ( 'Sepal length' , fontsize = 18 )
axes [ 0 ] . set_ylabel ( 'Sepal width' , fontsize = 18 )
axes [ 1 ] . set_xlabel ( 'Sepal length' , fontsize = 18 )
axes [ 1 ] . set_ylabel ( 'Sepal width' , fontsize = 18 )
axes [ 0 ] . tick_params ( direction = 'in' , length = 10 , width = 5 , colors = 'k' , labelsize = 20 )
axes [ 1 ] . tick_params ( direction = 'in' , length = 10 , width = 5 , colors = 'k' , labelsize = 20 )
axes [ 0 ] . set_title ( 'Actual' , fontsize = 18 )
axes [ 1 ] . set_title ( 'Predicted' , fontsize = 18 )
2차원의 가상 데이터에 Kmeans clustering
1
2
3
4
5
6
7
from sklearn.datasets import make_blobs
# create dataset
X , y = make_blobs (
n_samples = 150 , n_features = 2 ,
centers = 3 , cluster_std = 0.5 ,
shuffle = True , random_state = 0
)
1
2
3
4
5
6
7
km = KMeans (
n_clusters = 3 , init = 'random' ,
n_init = 10 , max_iter = 300 ,
tol = 1e-04 , random_state = 0
)
y_km = km . fit_predict ( X )
y_km
array([1, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 2, 2, 0, 0, 2, 2, 1, 2, 1, 0, 1,
0, 0, 2, 1, 1, 0, 2, 1, 2, 2, 2, 2, 0, 1, 1, 1, 0, 0, 2, 2, 0, 1,
1, 1, 2, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 1, 2, 0, 2, 2, 2, 2, 0, 2,
0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 2, 2, 0, 1, 1, 0, 0, 1, 1, 1, 2,
2, 1, 1, 0, 1, 0, 1, 0, 2, 2, 1, 1, 1, 1, 2, 1, 1, 0, 2, 0, 0, 0,
2, 0, 1, 2, 0, 2, 0, 0, 2, 2, 0, 1, 0, 0, 1, 1, 2, 1, 2, 2, 2, 2,
1, 2, 2, 2, 0, 2, 1, 2, 0, 0, 1, 1, 2, 2, 2, 2, 1, 1])
군집 분류 시각화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
plt . scatter (
X [ y_km == 0 , 0 ], X [ y_km == 0 , 1 ],
s = 50 , c = 'lightgreen' ,
marker = 's' , edgecolor = 'black' ,
label = 'cluster 1'
)
plt . scatter (
X [ y_km == 1 , 0 ], X [ y_km == 1 , 1 ],
s = 50 , c = 'orange' ,
marker = 'o' , edgecolor = 'black' ,
label = 'cluster 2'
)
plt . scatter (
X [ y_km == 2 , 0 ], X [ y_km == 2 , 1 ],
s = 50 , c = 'lightblue' ,
marker = 'v' , edgecolor = 'black' ,
label = 'cluster 3'
)
# plot the centroids
plt . scatter (
km . cluster_centers_ [:, 0 ], km . cluster_centers_ [:, 1 ],
s = 250 , marker = '*' ,
c = 'red' , edgecolor = 'black' ,
label = 'centroids'
)
plt . legend ( scatterpoints = 1 )
plt . grid ()
plt . show ()
k 를 4로 할경우
1
2
3
4
5
6
km = KMeans (
n_clusters = 4 , init = 'random' ,
n_init = 10 , max_iter = 300 ,
tol = 1e-04 , random_state = 0
)
y_km = km . fit_predict ( X )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
plt . scatter (
X [ y_km == 0 , 0 ], X [ y_km == 0 , 1 ],
s = 50 , c = 'lightgreen' ,
marker = 's' , edgecolor = 'black' ,
label = 'cluster 1'
)
plt . scatter (
X [ y_km == 1 , 0 ], X [ y_km == 1 , 1 ],
s = 50 , c = 'orange' ,
marker = 'o' , edgecolor = 'black' ,
label = 'cluster 2'
)
plt . scatter (
X [ y_km == 2 , 0 ], X [ y_km == 2 , 1 ],
s = 50 , c = 'lightblue' ,
marker = 'v' , edgecolor = 'black' ,
label = 'cluster 3'
)
plt . scatter (
X [ y_km == 3 , 0 ], X [ y_km == 3 , 1 ],
s = 50 , c = 'lightblue' ,
marker = 'd' , edgecolor = 'black' ,
label = 'cluster 4'
)
# plot the centroids
plt . scatter (
km . cluster_centers_ [:, 0 ], km . cluster_centers_ [:, 1 ],
s = 250 , marker = '*' ,
c = 'red' , edgecolor = 'black' ,
label = 'centroids'
)
plt . legend ( scatterpoints = 1 )
plt . grid ()
plt . show ()
한 군집이 2개로 나눠진 것처럼 보임. K=3 일 때가 더 명확하게 나온 것 같지만 K값을 변화시켜 최적의 K를 찾아보는 게 좋다.
최적의 K 찾기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sklearn.metrics import silhouette_score
distortions = []
for i in range ( 2 , 11 ):
km = KMeans (
n_clusters = i , init = 'random' ,
n_init = 10 , max_iter = 300 ,
tol = 1e-04 , random_state = 0
)
km . fit ( X )
distortions . append ( silhouette_score ( X , km . predict ( X ), metric = 'euclidean' ))
plt . plot ( range ( 2 , 11 ), distortions , marker = 'o' )
plt . xlabel ( 'Number of clusters' )
plt . ylabel ( 'Distortion' )
plt . show ()
간단하게는 kmeans 클래스의 inertia_를 이용해 최적의 k를 찾을 수 있다.