💡 주제
고객 세분화 분석
🎯 목표 고객 데이터셋을 사용하여 비슷한 행동을 보이는 고객 그룹을 식별합니다.
📖 학습 내용 - 비지도 학습의 개념을 이해하고, 클러스터링 기법을 통해 데이터의 패턴을 발견하는 능력
- 데이터 전처리 및 탐색: 비지도 학습에서의 데이터 준비 과정
- 클러스터링 기법 적용: 다양한 클러스터링 알고리즘의 이해와 실습
- 최적의 클러스터 수 결정: 모델의 성능을 평가하는 방법과 시각화 기술을 통해 인사이트 도출
CustomerID | Gender | Age | Annual Income (k$) | Spending Score (1-100) |
1 | Male | 19 | 15 | 39 |
2 | Male | 21 | 15 | 81 |
3 | Female | 20 | 16 | 6 |
4 | Female | 23 | 16 | 77 |
5 | Female | 31 | 17 | 40 |
6 | Female | 22 | 17 | 76 |
7 | Female | 35 | 18 | 6 |
8 | Female | 23 | 18 | 94 |
9 | Male | 64 | 19 | 3 |
데이터를 열어보니 200개의 행과 5개의 열로 구성되어 있다.
일단 데이터를 분석해보자
- CustomerID: 고객 ID (고유값, 분석에 필요하지 않을 가능성이 큼)
- Gender: 성별 (문자형 데이터, 필요시 인코딩 필요)
- Age: 나이 (18~70세)
- Annual Income (k$): 연간 소득 (15~137k$)
- Spending Score (1-100): 소비 점수 (1~99)
데이터셋 탐색 및 전처리:
- 결측치 처리:
- 데이터 안에 결측치(NA)는 없다.
- CustomerID는 분석에 불필요하므로 제거하자.
- Gender를 숫자형으로 인코딩 시키자.
# 1. CustomerID 제거
df = df.drop(columns=['CustomerID'])
# 2. Gender 인코딩 (LabelEncoder 사용)
# Male은 1, Female은 0으로 변환합니다
le = LabelEncoder()
df['Gender'] = le.fit_transform(df['Gender'])
- 스케일링:
- 데이터의 스케일을 조정하기 위해 표준화(Standardization) 또는 정규화(Normalization)를 수행합니다
# 3. Age, Annual Income, Spending Score 표준화 (StandardScaler) 및 정규화 (MinMaxScaler)
# 표준화
scaler_standard = StandardScaler()
df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] = scaler_standard.fit_transform(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# 정규화
scaler_minmax = MinMaxScaler()
df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] = scaler_minmax.fit_transform(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
#둘중 한가지 선택하기(여기서는 표준화를 사용함)
- 최적의 클러스터 수 결정:
- 엘보우 방법 또는 실루엣 점수를 사용하여 최적의 클러스터 수를 찾습니다.
- 엘보우, 실루엣 스코어
# 엘보우 기법 (K-means 클러스터링)
inertia = []
silhouette_scores = []
k_range = range(2, 11) # K 값은 2부터 10까지 확인
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
inertia.append(kmeans.inertia_)
score = silhouette_score(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']], kmeans.labels_)
silhouette_scores.append(score)
# 두 가지 기법을 함께 시각화
fig, ax = plt.subplots(1, 2, figsize=(15, 6))
# 엘보우 기법 (inertia)
ax[0].plot(k_range, inertia, marker='o', color='b', linestyle='--')
ax[0].set_title('Elbow Method for Optimal K')
ax[0].set_xlabel('Number of clusters (K)')
ax[0].set_ylabel('Inertia')
# 실루엣 점수 시각화
ax[1].plot(k_range, silhouette_scores, marker='o', color='g', linestyle='--')
ax[1].set_title('Silhouette Scores for K-means')
ax[1].set_xlabel('Number of clusters (K)')
ax[1].set_ylabel('Silhouette Score')
plt.tight_layout()
plt.show()
엘보우 기법: inertia는 각 K값에 대한 군집 내 거리 합을 계산한다.
이를 통해 K값을 증가시킬 때 inertia 값이 급격히 감소한 후,
더 이상 크게 줄어들지 않는 지점을 엘보우에서 찾을 수 있다.
k=6 근처가 엘보우 지점으로 보인다.
실루엣 점수: 각 K값에 대한 실루엣 점수를 계산하여 클러스터링의 품질을 평가한다.
실루엣 점수는 각 클러스터가 잘 구분되어 있을수록 높다.
K=6 지점이 가장 좋아보인다.
- K-means
# K-means 클러스터링 (최적의 K = 실루엣 점수가 가장 높은 K값 선택)
optimal_k = k_range[silhouette_scores.index(max(silhouette_scores))]
print(f"Optimal number of clusters (K): {optimal_k}")
# K-means 클러스터링 결과 시각화
kmeans = KMeans(n_clusters=optimal_k, random_state=42)
df['KMeans_Cluster'] = kmeans.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# K-means 클러스터링 결과 scatterplot 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['KMeans_Cluster'], palette='Set1', s=100, alpha=0.7)
plt.title(f'K-means Clustering (K={optimal_k})')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
- 계층적 군집화
# 계층적 군집화 (Agglomerative Clustering)
agg_clust = AgglomerativeClustering(n_clusters=optimal_k, affinity='euclidean', linkage='ward')
df['Hierarchical_Cluster'] = agg_clust.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# 계층적 군집화 결과 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['Hierarchical_Cluster'], palette='Set2', s=100, alpha=0.7)
plt.title(f'Agglomerative Clustering (K={optimal_k})')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
- DBSCAN
# DBSCAN 군집화
dbscan = DBSCAN(eps=0.5, min_samples=5)
df['DBSCAN_Cluster'] = dbscan.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# DBSCAN 군집화 결과 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['DBSCAN_Cluster'], palette='Set3', s=100, alpha=0.7)
plt.title('DBSCAN Clustering')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
- 결과 시각화:
- 클러스터링 결과를 2D 또는 3D로 시각화하여 고객 세분화 결과를 분석합니다.
- 시각화: matplotlib 또는 seaborn을 사용하여 클러스터를 색상으로 구분하여 시각화합니다. 2D 플롯을 사용하여 각 클러스터를 다른 색으로 표현합니다.
- 클러스터링 결과를 2D 또는 3D로 시각화하여 고객 세분화 결과를 분석합니다.
3개의 알고리즘 모두 비슷한 성능을 보이는 것으로 판단된다,
일단 3개의 알고리즘 장점과 단점을 알아보고 마치자.
더보기
K-means 클러스터링:
- 장점:
- 빠르고 효율적: 대규모 데이터에서 잘 작동합니다.
- 구형 군집을 잘 찾습니다. 즉, 군집이 구형 모양일 때 효과적입니다.
- 초기화가 간단하고, 병렬화가 용이해 빠른 학습이 가능합니다.
- 단점:
- K값(군집의 수)을 사전에 설정해야 합니다.
- 구형 군집에 잘 맞고, 밀도가 고른 군집에서 잘 작동합니다. 하지만 비구형 군집이나 불균형 군집에서는 성능이 떨어질 수 있습니다.
- 적합성: 이 데이터는 소비 점수와 소득을 기준으로 군집을 나누기 때문에, K-means는 적합할 수 있습니다. 특히 군집이 대체로 구형일 가능성이 높아 잘 작동할 것입니다
더보기
계층적 군집화 (Hierarchical Clustering):
- 장점:
- 클러스터의 수를 미리 알지 않아도 된다: 덴드로그램을 통해 적절한 군집 수를 찾을 수 있습니다.
- 군집 간의 관계를 시각화할 수 있습니다.
- 단점:
- 계산 비용이 많이 들고, 데이터가 많을 경우 시간이 오래 걸릴 수 있습니다.
- 큰 데이터셋에서는 메모리 사용량이 많아 성능이 저하될 수 있습니다.
- 적합성: 계층적 군집화는 군집의 구조를 시각적으로 이해할 수 있다는 점에서 유용합니다. 특히 고객 세그먼트를 더 깊이 이해하고자 할 때 좋습니다.
더보기
DBSCAN (Density-Based Spatial Clustering of Applications with Noise):
- 장점:
- 밀도 기반으로 군집을 찾기 때문에, 불규칙한 모양의 군집도 잘 찾을 수 있습니다.
- 군집의 개수를 사전에 정할 필요가 없으며, 노이즈(이상값)에 강합니다.
- 단점:
- eps와 min_samples 값을 잘 설정해야 하며, 적절한 밀도를 가지는 군집이 있어야 잘 작동합니다.
- 밀도가 고르지 않거나 너무 희박한 군집이 있을 경우 잘 작동하지 않을 수 있습니다.
- 적합성: DBSCAN은 불규칙한 모양의 군집을 잘 찾고, 노이즈에 강한 특성이 있습니다. 데이터가 밀도 기반으로 잘 분리될 수 있다면 좋은 선택이 될 수 있습니다.
전체 코드도 남기겠습니다.
더보기
import pandas as pd
from sklearn.preprocessing import LabelEncoder, StandardScaler, MinMaxScaler
from sklearn.cluster import KMeans, DBSCAN
from sklearn.metrics import silhouette_score
from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.cluster.hierarchy import dendrogram, linkage
# 데이터 불러오기
df = pd.read_csv("Mall_Customers.csv")
# 1. CustomerID 제거
df = df.drop(columns=['CustomerID'])
# 2. Gender 인코딩 (LabelEncoder 사용)
le = LabelEncoder()
df['Gender'] = le.fit_transform(df['Gender'])
# 3. Age, Annual Income, Spending Score 표준화 (StandardScaler) 및 정규화 (MinMaxScaler)
# 표준화
scaler_standard = StandardScaler()
df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] = scaler_standard.fit_transform(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# 정규화
#scaler_minmax = MinMaxScaler()
#df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] = scaler_minmax.fit_transform(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
#둘중 한가지 선택하기(여기서는 표준화를 사용함)
# =====================================================
# K-means 군집화
inertia = []
silhouette_scores = []
k_range = range(2, 11) # K 값은 2부터 10까지 확인
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
inertia.append(kmeans.inertia_)
score = silhouette_score(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']], kmeans.labels_)
silhouette_scores.append(score)
# =====================================================
# 두 가지 기법을 함께 시각화
fig, ax = plt.subplots(1, 2, figsize=(15, 6))
# 엘보우 기법 (inertia)
ax[0].plot(k_range, inertia, marker='o', color='b', linestyle='--')
ax[0].set_title('Elbow Method for Optimal K')
ax[0].set_xlabel('Number of clusters (K)')
ax[0].set_ylabel('Inertia')
# 실루엣 점수 시각화
ax[1].plot(k_range, silhouette_scores, marker='o', color='g', linestyle='--')
ax[1].set_title('Silhouette Scores for K-means')
ax[1].set_xlabel('Number of clusters (K)')
ax[1].set_ylabel('Silhouette Score')
plt.tight_layout()
plt.show()
# =====================================================
# K-means 클러스터링 (최적의 K = 실루엣 점수가 가장 높은 K값 선택)
optimal_k = k_range[silhouette_scores.index(max(silhouette_scores))]
print(f"Optimal number of clusters (K) for K-means: {optimal_k}")
# K-means 클러스터링 결과 시각화
kmeans = KMeans(n_clusters=optimal_k, random_state=42)
df['KMeans_Cluster'] = kmeans.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# K-means 클러스터링 결과 scatterplot 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['KMeans_Cluster'], palette='Set1', s=100, alpha=0.7)
plt.title(f'K-means Clustering (K={optimal_k})')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
# =====================================================
# 계층적 군집화 (Agglomerative Clustering)
agg_clust = AgglomerativeClustering(n_clusters=optimal_k, affinity='euclidean', linkage='ward')
df['Hierarchical_Cluster'] = agg_clust.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# 계층적 군집화 결과 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['Hierarchical_Cluster'], palette='Set2', s=100, alpha=0.7)
plt.title(f'Agglomerative Clustering (K={optimal_k})')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
# =====================================================
# DBSCAN 군집화
dbscan = DBSCAN(eps=0.5, min_samples=5)
df['DBSCAN_Cluster'] = dbscan.fit_predict(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# DBSCAN 군집화 결과 시각화
plt.figure(figsize=(8, 6))
sns.scatterplot(x=df['Age'], y=df['Annual Income (k$)'], hue=df['DBSCAN_Cluster'], palette='Set3', s=100, alpha=0.7)
plt.title('DBSCAN Clustering')
plt.xlabel('Age')
plt.ylabel('Annual Income (k$)')
plt.show()
'Machine learning' 카테고리의 다른 글
[Python 지도학습 실습 RETURN 2] (3) | 2024.12.27 |
---|---|
[Python 지도학습 실습 RETURN 1] (1) | 2024.12.26 |
[머신러닝: 지도학습 실습 2] (6) | 2024.12.19 |
[머신 러닝: 지도학습 실습 1] (4) | 2024.12.18 |
[머신 러닝: 지도학습에 대해] (0) | 2024.12.12 |