군집화란?
k-평균
k-평균은 군집 중심점(centroid)이라는 특정한 임의의 지점을 선택해 해당 중심에 가장 가까운 포인트들을 선택하는 군집화 기법이다. 또한, 반복 몇 번으로 데이터셋을 빠르고 효율적으로 클러스터로 묶을 수 있는 간단한 알고리즘이다.
군집 중심점은 선택된 포인트의 평균 지점으로 이동하고 이동된 중심점에서 다시 가까운 포인트를 선택, 다시 중심점을 평균 지점으로 이동하는 프로세스를 반복적으로 수행하며, 모든 데이터 포인트에서 더 이상 중심점의 이동이 없을 경우에 반복을 멈추고 해당 중심점에 속하는 데이터 포인트들을 군집화하는 기법이다.
[k-평균의 장점]
- 일반적인 군집화에서 가장 많이 활용
- 알고리즘이 쉽고 간결
- 속도가 빠르고 확장이 용이
[k-평균의 단점]
- 거리 기반 알고리즘으로 속성의 개수가 매우 많을 경우 군집화 정확도 저하 (이를 위해 PCA로 차원 감소를 적용해야 할 수도 있다)
- 최적이 아닌 솔루션을 피하려면 알고리즘을 여러 번 반복을 수행하는데, 반복 횟수가 많을 경우 수행 시간이 매우 느려짐
- 몇 개의 군집을 선택해야 할지 가이드하기 어려움(클러스터 개수를 지정하는 작업이 번거로울 수 있음)
- 클러스터의 크기 또는 밀집도가 서로 다르거나 원형이 아닐 경우 잘 작동하지 않음.
사이킷런 k-평균
사이킷런 패키지는 K-평균을 구현하기 위해 KMeans 클래스를 제공하는데, 다음과 같은 초기화 파라미터를 가지고 있다.
class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.001,
precompute_distances='auto', verbose=0, random_state=None,
copy_x=True, n_jobs=1, algorithm='auto')
- n_clusters: 군집화할 개수 (군집 중심점 개수)
- init: 초기에 군집 중심점의 좌표를 설정할 방식. 일반적으로 k-means++ 방식으로 최초 설정
- max_iter: 최대 반복 횟수, 이 횟수 이전에 모든 데이터의 중심점 이동이 없으면 종료
KMeans는 사이킷런의 비지도학습 클래스와 마찬가지로 fit(데이터 세트) 또는 fit_transform(데이터 세트) 메서드를 이용해 수행하면 되며, 이렇게 수행된 KMeans 객체는 군집화 수행이 완료돼 군집화와 관련된 주요 속성을 알 수 있다.
- labels_: 각 데이터 포인트가 속한 군집 중심점 레이블
- cluster_centers_; 각 군집 중심점 좌표(shape는 [군집 개수, 피처 개수]). 군집 중심점 좌표가 어디인지 시각화
k-평균을 이용한 붓꽃 데이터 세트 군집화
꽃받침(sepal)과 꽃잎(petal)의 길이에 따라 각 데이터의 군집화가 어떻게 결정되는지 확인하고 이를 분류값과 비교해 본다.
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline
iris = load_iris()
# 편리한 핸들링을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'])
irisDF.head()
[붓꽃 데이터 세트 군집화]
데이터 세트를 3개 그룹으로 군집화하고, kmeans의 labels_ 속성값을 확인하여 각 데이터가 어떤 중심에 속하는지 확인
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, random_state=0)
kmeans.fit(irisDF)
print(kmeans.labels_)
▶ labels_의 값이 0, 1, 2로 되어 있으며, 이느 ㄴ각 레코드가 첫 번째 군집, 두 번째 군집, 세 번째 군집에 속함을 의미한다.
[군집화가 효과적으로 되었는지 확인]
실제 붓꽃 품종 분류 값과 얼마나 차이가 나는지로 군집화가 효과적으로 됐는지 확인해 본다.
target 값을 'target', labels_ 값을 'cluster' 칼럼으로 지정해 irisDF DataFrame 에 추가한 뒤에 group by 연산을 target과 cluster 레벨로 적용해 개수를 비교할 수 있다.
irisDF['target'] = iris.target
irisDF['cluster'] = kmeans.labels_
iris_result = irisDF.groupby(['target', 'cluster'])['sepal_length'].count()
print(iris_result)
▶ 분류 타깃이 0값인 데이터: 1번 군집으로 잘 그루핑 됨.
Target 1값 데이터: 3개만 2번 군집으로, 나머지는 0번 군집으로 그루핑
Target 2값 데이터: 0번, 2번 군집으로 분산돼 그루핑.
[붓꽃 데이터 세트 군집화 시각화]
2차원 평면상에서 시각적으로 표현하려는데 데이터 세트의 속성이 4개 이므로 PCA를 이용해 2개로 차원 축소한 뒤에 X 좌표, Y 좌표로 개별 데이터 표현
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca_transformed = pca.fit_transform(iris.data)
irisDF['pca_x'] = pca_transformed[:, 0]
irisDF['pca_y'] = pca_transformed[:, 1]
irisDF.head()
# 군집 값이 0, 1, 2 인 경우마다 별도의 인덱스로 추출
marker0_ind = irisDF[irisDF['cluster']==0].index
marker1_ind = irisDF[irisDF['cluster']==1].index
marker2_ind = irisDF[irisDF['cluster']==2].index
# 군집 값 0, 1, 2에 해당하는 인덱스로 각 군집 레벨의 pca_x, pca_y 값 추출, 마커: o, s, ^
plt.scatter(x=irisDF.loc[marker0_ind, 'pca_x'], y=irisDF.loc[marker0_ind, 'pca_y'], marker='o')
plt.scatter(x=irisDF.loc[marker1_ind, 'pca_x'], y=irisDF.loc[marker1_ind, 'pca_y'], marker='s')
plt.scatter(x=irisDF.loc[marker2_ind, 'pca_x'], y=irisDF.loc[marker2_ind, 'pca_y'], marker='^')
plt.xlabel('PCA 1')
plt.ylabel('PCA 2')
plt.title('3 Clusters Visualization by 2 PCA Components')
plt.show()
군집화 알고리즘 테스트를 위한 데이터 생성
사이킷런의 대표적인 군집화용 데이터 생성기로는 make_blobs()와 make_classification() API가 있다.
- make_blobs(): 개별 군집의 중심점과 표준 편차 제어 기능 추가
- make_classfication(): 노이즈를 포함한 데이터를 만드는 데 유용하게 사용
- 둘 모두 분류 용도로도 테스트 데이터 생성 가능
이 외에 make_circle(), make_moon() API는 중심 기반의 군집화로 해결하기 어려운 데이터 세트를 만드는 데 사용 된다.
[make_blobs의 호출 파라미터]
- n_samples: 생성할 총 데이터의 개수 (디폴트는 100)
- n_features: 데이터의 피처 개수. 시각화를 목표로 할 경우 2개로 설정. (첫 번째- x 좌표, 두 번째 - y 좌표)
- centers: int 값. 군집의 개수, ndarray 형태로 표현할 경우 개별 군집 중심점의 좌표 의미
- cluster_std: 생성된 군집 데이터의 표준 편차. 군집별로 서로 다른 표준 편차를 가진 데이터 세트를 만들 때 사용
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
%matplotlib inline
X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=0.8, random_state=0)
print(X.shape, y.shape)
# y target 값의 분포도 확인
unique, counts = np.unique(y, return_counts=True)
print(unique, counts)
▶ 피처 데이터 세트 X는 200개의 레코드와 2개의 피처를 가짐.
군집 타겟 데이터 y는 200개의 레코들 가짐.
3개의 cluster 값: [0, 1, 2] 이며, 각각 67, 67, 66 개로 균일하게 구성
[데이터 세트를 DataFrame으로 변경]
import pandas as pd
clusterDF = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
clusterDF.head()
[산점도 그려 군집화 분포 확인]
타깃값 0, 1, 2에 따라 마커를 다르게 해서 산점도를 그려본다.
target_list = np.unique(y)
# 각 타깃별 산점도 마커
markers = ['o', 's', '^', 'P', 'D', 'H', 'x']
# 3개의 군집 영역으로 구분한 데이터를 생성했으므로 target_list 는 [0, 1, 2]
# target==0, target==1, target==2 로 scatter plot 을 marker 별로 생성
for target in target_list:
target_cluster = clusterDF[clusterDF['target']==target]
plt.scatter(x=target_cluster['ftr1'], y=target_cluster['ftr2'],
edgecolor='k', marker=markers[target])
plt.show()
[데이터 세트에 KMeans 군집화 수행 후 군집별로 시각화]
- KMeans 객체에 fit_predict(X) 수행해 make_blobs() 의 피처 데이터 세트인 X 데이터 군집화
- 이를 clusterDF DataFrame의 'kmeans_label' 칼럼으로 저장
- KMeans 객체의 cluster_centers_ 속성은 개별 군집의 중심 위치 좌표를 나타내기 위해 사용
# KMeans 객체를 이용해 X 데이터를 K-Means 클러스터링 수행
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=200, random_state=0)
cluster_labels = kmeans.fit_predict(X)
clusterDF['kmeans_label'] = cluster_labels
# cluster_centers_ 는 개별 클러스터의 중심 위치 좌표 시각화를 위해 추출
centers = kmeans.cluster_centers_
unique_labels = np.unique(cluster_labels)
markers = ['o', 's', '^', 'P', 'D', 'H', 'x']
# 군집된 label 유형별로 iteration 하면서 marker 별로 scatter plot 수행
for label in unique_labels:
label_cluster = clusterDF[clusterDF['kmeans_label']==label]
center_x_y = centers[label]
plt.scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'],
edgecolor='k', marker=markers[label])
# 군집별 중심 위치 좌표 시각화
plt.scatter(x=center_x_y[0], y=center_x_y[1], s=200, color='white',
alpha=0.9, edgecolor='k', marker=markers[label])
plt.scatter(x=center_x_y[0], y=center_x_y[1], s=70, color='k',
edgecolor='k', marker='$%d$' % label)
plt.show()
※ make_blobs()의 타깃과 kmeans_label은 군집 번호를 의미하므로, 서로 다른 값으로 매핑될 수 있다.
print(clusterDF.groupby('target')['kmeans_label'].value_counts())
▶ target 0 - label 2 / target 1 - label 0 / target 2 - label 1로 매핑되었다.
[cluster_std 파라미터 조절하여 시각화]
make_blobs(), 는 cluster_std 파라미터로 데이터의 분포도를 조절한다.cluster_std를,
0.4, 0.8, 1.2, 1.6일 때의 데이터를 시각화하여 분포도를 확인해 본다.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import warnings
warnings.filterwarnings('ignore')
# 각 표준편차별 std 값을 정의
cluster_std_values = [0.4, 0.8, 1.2, 1.6]
# subplot 설정
fig, axs = plt.subplots(1, 4, figsize=(20, 5))
markers = ['o', 's', '^', 'P', 'D', 'H', 'x']
for i, std in enumerate(cluster_std_values):
# 군집화 데이터 생성
X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=std, random_state=0)
# KMeans 모델을 통해 군집화 수행
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=200, random_state=0)
cluster_labels = kmeans.fit_predict(X)
# 클러스터링 결과를 데이터프레임으로 변환
clusterDF = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterDF['kmeans_label'] = cluster_labels
# 각 subplot에 산점도 표시
axs[i].set_title(f'Cluster Std: {std}')
for label in np.unique(cluster_labels):
label_cluster = clusterDF[clusterDF['kmeans_label'] == label]
axs[i].scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'],
edgecolor='k', marker=markers[label], label=f'Cluster {label}')
axs[i].legend()
axs[i].set_xlabel('Feature 1')
axs[i].set_ylabel('Feature 2')
plt.tight_layout()
plt.show()
▶ cluster_std 가 작을수록 군집 중심에 데이터가 모여있으며, 클수록 데이터가 퍼져 있다.
[도움되는 글]
다음 내용
[출처]
파이썬 머신러닝 완벽 가이드
핸즈 온 머신러닝
'[파이썬 Projects] > <파이썬 머신러닝>' 카테고리의 다른 글
[머신러닝] 군집화: 평균 이동 (0) | 2024.10.25 |
---|---|
[머신러닝] 군집화: 군집 평가 (3) | 2024.10.25 |
[머신러닝] 군집화 (Clustering) (0) | 2024.10.25 |
[머신러닝] 차원 축소 - SVD (0) | 2024.10.24 |
[머신러닝] 차원 축소 - NMF (1) | 2024.10.24 |