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


다음 내용

 

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

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

puppy-foot-it.tistory.com


[출처]

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

 

728x90
반응형