[머신러닝: 비지도학습 실습]

2024. 12. 19. 16:51·Machine learning

💡 주제

고객 세분화 분석

🎯 목표 고객 데이터셋을 사용하여 비슷한 행동을 보이는 고객 그룹을 식별합니다.

📖 학습 내용 - 비지도 학습의 개념을 이해하고, 클러스터링 기법을 통해 데이터의 패턴을 발견하는 능력

  • 데이터 전처리 및 탐색: 비지도 학습에서의 데이터 준비 과정
  • 클러스터링 기법 적용: 다양한 클러스터링 알고리즘의 이해와 실습
  • 최적의 클러스터 수 결정: 모델의 성능을 평가하는 방법과 시각화 기술을 통해 인사이트 도출
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 플롯을 사용하여 각 클러스터를 다른 색으로 표현합니다.

 

 

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
'Machine learning' 카테고리의 다른 글
  • [Python 지도학습 실습 RETURN 2]
  • [Python 지도학습 실습 RETURN 1]
  • [머신러닝: 지도학습 실습 2]
  • [머신 러닝: 지도학습 실습 1]
100.nam
100.nam
100.nam님의 블로그 입니다.
  • 100.nam
    100.nam님의 블로그
    100.nam
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Python 정리
      • Python 문제 풀기
      • Machine learning
      • SQL 정리
      • SQL 문제풀기
      • Django 정리
      • LangChain,Graph
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    내일배움캠프
    Python
    스파르타코딩크럽
    스파르타코딩클럽
    vscode
    인공지능을위한파이썬
    SQL
    머신러닝
    pandas
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
100.nam
[머신러닝: 비지도학습 실습]
상단으로

티스토리툴바