티스토리 뷰

K-means 클러스터링에 대해 알아보고, Mall_Customers 데이터를 활용하여 군집화와 군집 평가를 실습해본다.

 

 

K-means 클러스터링

자료출처 : By Chire - 자작, 퍼블릭 도메인, https://commons.wikimedia.org/w/index.php?curid=11765684

 

데이터를 k개의 클러스터로 묶는 비지도학습의 일종으로, 각 클러스터와 거리 차이의 분산을 최소화하는 방식으로 동작하는 알고리즘이다. 레이블이 달려 있지 않은 입력 데이터에 레이블을 추가하는 역할을 수행할 수 있다.

 

 

 

Objective function

$$ J = \sum_{j=1}^{k}\sum_{i=1}^{n}{\left\|x_{i}^{(j)}-c_{j}\right\|}^2$$

$k$ : number of clusters

$n$ : number of cases

$x_{i}$ : case $i$

$c_{j}$ : centroid for cluster $j$

 

장점

알고리즘이 간단하고 큰 데이터에도 손쉽게 사용할 수 있다.

 

단점

연속형 변수에 최적이며, 결과가 초기에 지정한 클러스터 중심의 위치에 따라 달라질 수 있어 반복적인 작업이 필요하다.

클러스터의 개수를 지정해야 하며, 클러스터의 모양을 가정하기 때문에 다양한 분포를 가지는 데이터에 적용하는데 한계가 있다.

 

 

K-means 군집 평가

비즈니스 도메인 지식

자료출처 : https://tdan.com/domain-driven-development-part-1/29632

 

K-means에 들어갈 피처 자체에 어떤 데이터 패턴이 보이는지 시각화를 통해 미리 확인해야 한다.

흔히 말하는 차원축소나, 다른 군집화를 사용하는 것에 대한 기준점으로 현재 피처들이 어떤 데이터 패턴을 보이는지가 중요하다.

 

 

Elbow method

The elbow method of k-means

 

클러스터 간의 거리의 합을 나타내는 거리가 급격하게 떨어지는 구간이 생기는데, 이때 이 지점의 k값을 군집의 개수로 사용한다.

 

 

실루엣 계수(Silhouette coefficient)

 

군집 안에 데이터들이 어느 정도 모여있고, 어느정도 군집이 구분되는지를 평가하는 척도이다.

$$S_{i}=\frac{b_{i}-a_{i}}{\mathbf{max}{\begin{Bmatrix}a_i, b_i\end{Bmatrix}}}$$

$S_{i}$ : $i$번째 데이터 포인트의 실루엣 스코어

$b_{i}$ : $i$번째 데이터와 다른 클러스터에 속한 데이터 간 거리들의 평균을 클러스터 별로 구했을 때, 가장 작은 값

$a_{i}$ : $i$번째 데이터와 동일한 클러스터에 속한 데이터들 간 거리들의 평균

 

실루엣 계수를 계산하는 과정

 

실루엣 계수들의 평균값을 계산하여 클러스터 개수를 결정하게 된다.

실루엣 계수의 평균값이 1에 가까울수록 군집화가 잘되었다.

 

장점

클러스터링 결과를 시각화할 수 있고, 적절한 클러스터 개수를 정하는 기준을 선정할 수 있다.

클러스터링이 수행된 후 실루엣 계수를 구하므로, 클러스터링 알고리즘에 영향이 없다.

 

단점

데이터의 양이 많아지면, 연산이 오래 걸린다. 전체 데이터의 실루엣 계수 평균값으로 판단할 수 없어 개별 클러스터의 평균값도 생각해야 한다.

 

 

시나리오에 대한 K-means 알고리즘 실습

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs, make_moons
from sklearn.cluster import KMeans

# 데이터 생성
# 시나리오 1: 잘 분리된 동일 밀도 클러스터
X0, y0 = make_blobs(n_samples=300, centers=3, cluster_std=0.60, random_state=0)

# 시나리오 2: 다른 밀도의 클러스터
X1, y1 = make_blobs(n_samples=[100, 800], centers=[(-1, 0), (1, 2)], cluster_std=[0.5, 2.5], random_state=42)

# 시나리오 3: 비선형 클러스터 (반달 모양)
X2, y2 = make_moons(n_samples=200, noise=0.05, random_state=42)

# K-means 알고리즘 적용
kmeans0 = KMeans(n_clusters=3, random_state=42).fit(X0)
kmeans1 = KMeans(n_clusters=2, random_state=42).fit(X1)
kmeans2 = KMeans(n_clusters=2, random_state=42).fit(X2)

# 시각화 함수
def plot_clusters(X, y, centroids, title):
    plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='viridis', marker='o', edgecolors='k', alpha=0.5)
    plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=200, marker='x')
    plt.title(title)
    plt.xlabel("Feature 0")
    plt.ylabel("Feature 1")

# 그래프 그리기
plt.figure(figsize=(18, 6))
plt.subplot(1, 3, 1)
plot_clusters(X0, kmeans0.labels_, kmeans0.cluster_centers_, "Scenario 1: Well-separated Clusters")

plt.subplot(1, 3, 2)
plot_clusters(X1, kmeans1.labels_, kmeans1.cluster_centers_, "Scenario 2: Clusters with Different Densities")

plt.subplot(1, 3, 3)
plot_clusters(X2, kmeans2.labels_, kmeans2.cluster_centers_, "Scenario 3: Non-linear Clusters (Moon-shaped)")
plt.show()

 

각 시나리오에 대한 군집화 결과 그래프

 

 

Mall Customers 데이터를 활용한 K-means 알고리즘 실습

#pip install yellowbrick
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from yellowbrick.cluster import KElbowVisualizer
from sklearn.metrics import silhouette_score
from yellowbrick.cluster import SilhouetteVisualizer
from sklearn.cluster import DBSCAN
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

df=pd.read_csv('Mall_Customers.csv')

 

K-means를 이용해 군집을 만들어본다.

df_sp=df.drop('CustomerID',axis=1)
sns.set_style('ticks')
sns.pairplot(df_sp, hue='Gender')
plt.show()

 

각 특성에 대한 이해를 위한 분석 결과

 

군집화 전, 스케일링을 진행한다.

df_km = pd.get_dummies(df_sp, columns = ['Gender'],drop_first=True)

#스케일링 불러오기
mns = MinMaxScaler()
df_mns = mns.fit_transform(df_km)

# 컬럼 합쳐보기
df_mns_sp = pd.DataFrame(data= df_mns, columns = df_km.columns)

#minmax 스케일링 작업 완료
df_mns_sp

 

K-means를 불러와 데이터를 학습시킨다.

init : 초기 중심점을 어떤 식으로 둘 것인가?

n_cluster : 지정할 클러스터의 수

n_init : 중심점을 이동하면서 몇 번 반복할 것인가?

max_iter : 알고리즘 수렴 전 최대 몇 번 반복하는가?

kmeans_model1 =KMeans(n_clusters = 3, random_state=111) #고객군의 군집을 3개정도만 나눠보자!
kmeans_model1.fit(df_mns_sp)

#kmeans 제공하는 함수들
#inertia_ SSE 값 출력
#cluster_centers_ 중심 좌표
# n_iter_ 반복횟수 출력
print(kmeans_model1.inertia_)
print(kmeans_model1.cluster_centers_)
print(kmeans_model1.n_iter_)
print(kmeans_model1.labels_)

'''
9.40389112855273

[[ 1.91538462e-01  3.47213115e-01  4.70612245e-01  0.00000000e+00]
 [ 1.39423077e-01  2.15163934e-01  6.11394558e-01  1.00000000e+00]
 [ 3.92307692e-01  5.54098361e-01  1.34183673e-01  1.00000000e+00]
 [ 2.93803419e-01  5.91074681e-01  8.33333333e-01  1.00000000e+00]
 [ 6.95266272e-01  3.21563682e-01  4.89403454e-01  0.00000000e+00]
 [ 1.43491124e-01  8.76418663e-02  8.11616954e-01 -1.66533454e-16]
 [ 4.52662722e-01  9.45775536e-02  2.00941915e-01 -1.66533454e-16]
 [ 2.72893773e-01  5.82357533e-01  8.23129252e-01 -5.55111512e-17]
 [ 4.95879121e-01  6.41686183e-01  2.00437318e-01 -1.11022302e-16]
 [ 7.85502959e-01  2.76166456e-01  3.96389325e-01  1.00000000e+00]]
 
6

[1 1 6 5 6 5 6 5 9 5 9 5 6 5 2 1 6 1 9 5 1 1 6 1 6 1 6 1 6 5 9 5 9 1 6 5 6
 5 6 5 4 1 9 0 6 5 4 0 0 0 4 1 0 9 4 9 4 9 0 9 9 1 4 4 9 1 4 4 1 0 9 4 4 4
 9 1 4 1 0 4 9 1 9 4 0 9 4 0 0 4 4 1 9 0 0 1 4 0 9 1 0 4 9 1 9 0 4 9 9 9 9
 0 0 1 0 0 4 4 4 4 1 0 0 3 0 7 2 3 9 3 2 3 0 7 2 7 8 3 2 7 8 3 0 7 2 3 2 7
 8 3 2 3 8 7 8 7 2 7 2 7 4 7 2 7 2 7 2 7 8 3 2 3 2 3 8 7 2 3 2 3 8 7 2 7 8
 3 8 3 8 7 8 7 2 7 8 7 8 3 2 3]
 '''

 

Elbow chart를 활용하여 군집에 대한 평가를 진행한다.

Elbow_ch =KElbowVisualizer(kmeans_model1)
Elbow_ch.fit(df_mns_sp)
Elbow_ch.draw()

Elbow chart에서 값의 변화

 

실루엣계수의 변화를 확인한다.

반복문을 통해 실루엣 계수가 어떤 식으로 변화하는지 확인한다.

KMeans_model1={'random_state':111}
sil_coef = []

for i in range(2,11):
    kmeans_sil = KMeans(n_clusters = i, **KMeans_model1)
    kmeans_sil.fit(df_mns_sp)
    score = silhouette_score(df_mns_sp, kmeans_sil.labels_)
    sil_coef.append(score)

plt.plot(range(2,11), sil_coef)
plt.xticks(range(2,11))
plt.show()

클러스터에 따른 실루엣 계수의 변화

 

군집별로 실루엣계수를 시각화한다.

## 군집별로 같이 시각화를 통해 살펴보자!
fig, ax = plt.subplots(3,2 , figsize=(15,10))

for i in [2,3,4,5,6,7]:
    kmeans_model3 = KMeans(
        n_clusters=i,
        random_state=111 )
    q, mod = divmod(i,2)

# 실루엣계수 시각화를 군집별로 진행
	visual = SilhouetteVisualizer(kmeans_model3,
                                 color = 'yellowbricks',
                                 ax=ax[q-1][mod])
	visual.fit(df_mns_sp)

군집별 실루엣계수 시각화 결과

 

 

Mall_Customers 데이터에 클러스터 값을 라벨링 해본다.

from sklearn.cluster import KMeans
kmeans_model1 =KMeans(n_clusters = 4, random_state=111)

# fit_predict 메서드를 이용해서 라벨을 확인할 수 있다.
kmeans_model1.fit_predict(df_mns_sp)

'''
array([2, 2, 3, 1, 1, 1, 3, 1, 0, 1, 0, 1, 3, 1, 0, 2, 3, 2, 0, 1, 0, 2,
       3, 2, 3, 2, 3, 2, 3, 1, 0, 1, 0, 2, 3, 1, 3, 1, 3, 1, 3, 2, 0, 1,
       3, 1, 3, 1, 1, 1, 3, 2, 1, 0, 3, 0, 3, 0, 1, 0, 0, 2, 3, 3, 0, 2,
       3, 3, 2, 1, 0, 3, 3, 3, 0, 2, 3, 0, 1, 3, 0, 2, 0, 3, 1, 0, 3, 1,
       1, 3, 3, 2, 0, 3, 1, 2, 3, 1, 0, 2, 1, 3, 0, 2, 0, 1, 3, 0, 0, 0,
       0, 1, 3, 2, 1, 1, 3, 3, 3, 3, 2, 3, 1, 2, 1, 1, 0, 2, 0, 2, 0, 2,
       1, 1, 0, 1, 3, 2, 0, 1, 3, 2, 1, 1, 0, 2, 0, 1, 3, 2, 0, 2, 3, 1,
       3, 1, 0, 1, 0, 1, 3, 1, 0, 1, 0, 1, 0, 1, 3, 2, 0, 2, 0, 2, 3, 1,
       0, 2, 0, 2, 3, 1, 0, 1, 3, 2, 3, 2, 3, 1, 3, 1, 0, 1, 3, 1, 3, 2,
       0, 2], dtype=int32)
'''

 

클러스터링 값을 groupby로 확인해본다.

cluster_stats= df.groupby('cluster_kn').agg({
    'Gender': 'count',
    'Age':['mean','std'],
    'Annual Income (k$)' :['mean','std'],
    'Spending Score (1-100)':['mean','std']
})

cluster_stats.columns = ['Count','Age_Mean','Age_Std','Income_mean','Income_std','Score_mean','Score_std']
fig, axes = plt.subplots(3,2, figsize=(15,15))

# Age 평균, 표준편차 시각화
sns.barplot(x=cluster_stats.index, y ='Age_Mean', data=cluster_stats, ax =axes[0,0])
axes[0,0].set_title('Average Age')

sns.barplot(x=cluster_stats.index, y ='Age_Std', data=cluster_stats, ax =axes[0,1])
axes[0,1].set_title('Average Age')

sns.barplot(x=cluster_stats.index, y ='Income_mean', data=cluster_stats, ax =axes[1,0])
axes[1,0].set_title('Average Income')

sns.barplot(x=cluster_stats.index, y ='Income_std', data=cluster_stats, ax =axes[1,1])
axes[1,1].set_title('Average Income')

sns.barplot(x=cluster_stats.index, y ='Score_mean', data=cluster_stats, ax =axes[2,0])
axes[2,0].set_title('Average Score')

sns.barplot(x=cluster_stats.index, y ='Score_std', data=cluster_stats, ax =axes[2,1])
axes[2,1].set_title('Average Score')

 

Age의 평균, 표준편차와 클러스터 값의 비율 그래프

 

 

클러스터 값을 확인해보면, 다음과 같다.

클러스터 값에 대한 정보

 

 

 

 

 

 

 

활용 데이터셋 : https://www.kaggle.com/datasets/shwetabh123/mall-customers

 

Mall_Customers

 

www.kaggle.com

공지사항
최근에 올라온 글
Total
Today
Yesterday