TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 머신러닝>

[머신러닝] 군집화: k-평균

by 기록자_Recordian 2024. 10. 25.
728x90
반응형
군집화란?
 

[머신러닝] 군집화 (Clustering)

군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석, 고객 분류, 추천 시스템, 검색 엔진, 이미지 분할, 준지도 학습, 차원 축소

puppy-foot-it.tistory.com


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 가 작을수록 군집 중심에 데이터가 모여있으며, 클수록 데이터가 퍼져 있다.

 

[도움되는 글]

 

[머신러닝] 군집: k-평균 알고리즘 훈련하기

k-평균  [머신러닝] 군집화: k-평균군집화란? [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석,

puppy-foot-it.tistory.com


다음 내용

 

[머신러닝] 군집화: 군집 평가

군집화란? [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석, 고객 분류, 추천 시스템, 검색 엔

puppy-foot-it.tistory.com


[출처]

파이썬 머신러닝 완벽 가이드

핸즈 온 머신러닝

 

728x90
반응형