1. Cluster(클러스터)

  • 유사한 특성을 가진 객체들의 집합
  • 고객 분류, 유전자 분석, 이미지 분할
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

# X는 2차원으로 된 데이터 프레임
# y는 데이터 답을 만들어줌
X, y = make_blobs(n_samples=100, centers=3, random_state=10)
# n_samples = 샘플을 몇개를 만들지
# centers = 몇가지의 클래스를 만들지, 군집데이터를 만들기 때문에 class가 아닌 centers라고 작성함

 

X 

# 결과값 => 
# array([[ -2.32496308,  -6.6999964 ],
#        [  0.51856831,  -4.90086804],
#        
#        ...
#        
#        [  5.40050753,  -9.29586681]])

 

X = pd.DataFrame(X) # 데이터 프레임으로 변환
X

y

# 결과값 => 
# array([2, 2, 1, 0, 1, 1, 0, 2, 1, 0, 0, 1, 1, 2, 2, 1, 0, 1, 0, 1, 0, 2,
#        1, 2, 0, 1, 1, 1, 1, 0, 2, 1, 1, 0, 2, 2, 2, 1, 1, 1, 2, 0, 2, 2,
#        1, 0, 0, 0, 2, 0, 1, 2, 0, 0, 2, 0, 1, 2, 0, 0, 1, 1, 2, 2, 2, 0,
#        0, 2, 2, 2, 1, 0, 1, 1, 2, 1, 1, 2, 0, 0, 0, 1, 0, 1, 2, 1, 2, 0,
#        2, 2, 0, 0, 0, 2, 2, 2, 1, 0, 0, 0])

 

sns.scatterplot(x=X[0], y=X[1], hue=y)

from sklearn.cluster import KMeans

km = KMeans(n_clusters=3)
# 학습
km.fit(X)
# 예측
pred = km.predict(X)

sns.scatterplot(x=X[0], y=X[1], hue=pred)

km = KMeans(n_clusters=5)
# 학습
km.fit(X)
# 예측
pred = km.predict(X)

sns.scatterplot(x=X[0], y=X[1], hue=pred)

# 평가값 : 하나의 클러스트안에 중심점으로부터 각각의 데이터 거리를 합한 값의 평균
km.inertia_
# 값이 크면 데이터간 거리가 멀어 다른 데이터와 붙어있을가능성이 높음
# 값이 낮으면 데이터가 서로 옹기종기 모여있어 집합이 잘 되어있다

# 결과값 => 130.02425208172426

inertia_list = []

for i in range(2, 11) :
    km = KMeans(n_clusters=i)
    km.fit(X)
    inertia_list.append(km.inertia_)

inertia_list

# 결과값 => 
# [976.8773336900748,
#  186.3658862010144,
#  154.03820014871644,
#  130.61963601864812,
#  113.17852746430522,
#  98.39597533978201,
#  84.97468994763855,
#  73.1518886343043,
#  65.03279448102089]

 

# 엘보우 메서드
sns.lineplot(x=range(2, 11), y=inertia_list)
# 당연히 쪼갤 수록 값이 떨어지는게 당연하면서
# 가장 최적의 값은 심하게 꺽이는 부분이 가장 깔끔하면서 최적화된 부분이라고 판단하면 된다.

 

2. Marketing 데이터셋

mkt_df = pd.read_csv('/content/drive/MyDrive/KDT v2/머신러닝과 딥러닝/ data/marketing.csv')
mkt_df

 

mkt_df.info()

# 결과값 => 
#  #   Column               Non-Null Count  Dtype  
# ---  ------               --------------  -----  
#  0   ID                   2240 non-null   int64  
#  1   Year_Birth           2240 non-null   int64  
#  2   Education            2240 non-null   object 
#  3   Marital_Status       2240 non-null   object 
#  4   Income               2216 non-null   float64
#  5   Kidhome              2240 non-null   int64  
#  6   Teenhome             2240 non-null   int64  
#  7   Dt_Customer          2240 non-null   object 
#  8   Recency              2240 non-null   int64  
#  9   MntWines             2240 non-null   int64  
#  10  MntFruits            2240 non-null   int64  
#  11  MntMeatProducts      2240 non-null   int64  
#  12  MntFishProducts      2240 non-null   int64  
#  13  MntSweetProducts     2240 non-null   int64  
#  14  MntGoldProds         2240 non-null   int64  
#  15  NumDealsPurchases    2240 non-null   int64  
#  16  NumWebPurchases      2240 non-null   int64  
#  17  NumCatalogPurchases  2240 non-null   int64  
#  18  NumStorePurchases    2240 non-null   int64  
#  19  NumWebVisitsMonth    2240 non-null   int64  
#  20  Complain             2240 non-null   int64

Customer Data Table

(영어) (한글)
ID 고객 아이디
Year_Birth 출생 연도
Education 학력
Marital_Status 결혼 여부
Income 소득
Kidhome 어린이 수
Teenhome 청소년 수
Dt_Customer 고객 등록일
Recency 마지막 구매일로부터 경과일
MntWines 와인 구매액
MntFruits 과일 구매액
MntMeatProducts 육류 제품 구매액
MntFishProducts 어류 제품 구매액
MntSweetProducts 단맛 제품 구매액
MntGoldProds 골드 제품 구매액
NumDealsPurchases 할인 행사 구매 수
NumWebPurchases 웹에서의 구매 수
NumCatalogPurchases 카탈로그에서의 구매 수
NumStorePurchases 매장에서의 구매 수
NumWebVisitsMonth 월별 웹 방문 수
Complain 불만 여부

 

mkt_df.isna().sum()

# 결과값 => 
# ID                      0
# Year_Birth              0
# Education               0
# Marital_Status          0
# Income                 24
# Kidhome                 0
# Teenhome                0
# Dt_Customer             0
# Recency                 0
# MntWines                0
# MntFruits               0
# MntMeatProducts         0
# MntFishProducts         0
# MntSweetProducts        0
# MntGoldProds            0
# NumDealsPurchases       0
# NumWebPurchases         0
# NumCatalogPurchases     0
# NumStorePurchases       0
# NumWebVisitsMonth       0
# Complain                0

 

mkt_df.drop('ID', axis=1, inplace=True)

mkt_df.describe()

 

mkt_df.sort_values('Year_Birth')

 

# 내림 차순
mkt_df.sort_values('Income', ascending=False)

 

# NaN이 있을때 NaN이 저장되지 않으므로 아래의 코드는 사용 조심.
mkt_df = mkt_df[mkt_df['Income'] != 666666]

mkt_df.sort_values('Income', ascending=False)
# marital_status = widow > 즉 사별(배우자가 사망 혹은 재혼하지 않은 사람)

 

mkt_df = mkt_df.dropna()

# Dt_Customer : 고겍 등록일
mkt_df['Dt_Customer'] = pd.to_datetime(mkt_df['Dt_Customer'])

# 마지막으로 가입된 사람을 기준으로 현재 데이터의 가입 날짜(달) 차 구하기
# pass_month
mkt_df['pass_month'] = (mkt_df['Dt_Customer'].max().year * 12 + mkt_df['Dt_Customer'].max().month) - (mkt_df['Dt_Customer'].dt.year * 12 + mkt_df['Dt_Customer'].dt.month)
mkt_df.head()

mkt_df.drop('Dt_Customer', axis=1, inplace=True)

 

# 와인 + 과일 + 육류제품 + 어류 제품 + 단맛 제품 + 골드 제품의 합계 구하기

mkt_df['Total_mnt'] = mkt_df[['MntWines', 'MntFruits', 'MntMeatProducts', 'MntFishProducts', 'MntSweetProducts', 'MntGoldProds']].sum(axis=1)

mkt_df['Children'] = mkt_df[['Kidhome', 'Teenhome']].sum(axis=1)

mkt_df.drop(['Kidhome', 'Teenhome'], axis=1, inplace=True)

 

mkt_df['Education'].value_counts()
# 결과값 =>
# Graduation    1115
# PhD            481
# Master         365
# 2n Cycle       200
# Basic           54

mkt_df['Marital_Status'].value_counts()
# Married     857
# Together    572
# Single      471
# Divorced    232
# Widow        76
# Alone         3
# Absurd        2
# YOLO          2

 

mkt_df['Marital_Status'] = mkt_df['Marital_Status'].replace({
    'Married': 'Partner',
    'Together': 'Partner',
    'Single': 'Single',
    'Divorced': 'Single',
    'Widow': 'Single',
    'Alone': 'Single',
    'Absurd': 'Single',
    'YOLO': 'Single',
})

mkt_df['Marital_Status'].value_counts()
# 결과값 => 
# Partner    1429
# Single      786

 

mkt_df = pd.get_dummies(mkt_df, columns=['Education', 'Marital_Status'])

 

from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit_transform(mkt_df)
pd.DataFrame(ss.fit_transform(mkt_df))
ss_df = pd.DataFrame(ss.fit_transform(mkt_df), columns=mkt_df.columns)

 

3. KMeans

  • K개의 중심점을 찍은 후에, 이 중심점에서 각 점간의 거리의 합이 가장 최소가 되는 중심점 k의 위치를 찾고, 이 중심점에서 가까운 점들을 중심점을 기준으로 묶는 알고리즘
  • K개의 클러스터의 수는 정해줘야함
inertia_list = []

for i in range(2, 11) :
    km = KMeans(n_clusters=i, random_state=2024)
    km.fit(ss_df)
    inertia_list.append(km.inertia_)
inertia_list
# 결과값 => 
# [42898.75475762481,
#  39825.85332911935,
#  37620.72546383063,
#  36296.39316484985,
#  34242.24326674706,
#  32502.627684050876,
#  30781.8055617468,
#  29990.604680739903,
#  28248.19018930947]
sns.lineplot(x=range(2,11), y=inertia_list)

4. 실루엣 스코어(Silhouette Score)

  • 각 군집 간의 거리가 얼마나 효율적으로 분리 되어있는지를 나타냄
  • 실루엣 분석은 실루엣 계수를 기반으로 하는데, 실루엣 계수는 개별 데이터가 가지는 군집화 지표
from sklearn.metrics import silhouette_score

score = []

for i in range(2, 11) :
    km = KMeans(n_clusters=i, random_state=2024)
    km.fit(ss_df)
    pred = km. predict(ss_df)
    score.append(silhouette_score(ss_df, pred))
socre
# 결과값 => 
# [0.23022720420084983,
#  0.1422826246539863,
#  0.11964043510714399,
#  0.1281132041299626,
#  0.12161756074874215,
#  0.1252612275778885,
#  0.14543070406681055,
#  0.13864397879387974,
#  0.14911484181076592]
sns.lineplot(x=range(2, 11), y=score)
# k의 군집 위치를 찾는건 떨어지는것이 찾는게 아니라 상승폭의 숫자를 보는것이 정답이다. 즉 8이 가장 좋다.

km = KMeans(n_clusters=8, random_state=2024)
km.fit(ss_df)
pred = km.predict(ss_df)
pred
# 결과값 => array([5, 3, 2, ..., 5, 2, 0], dtype=int32)
mkt_df['label'] = pred

 

# 자기지도학습
mkt_df['label'].value_counts()

# 결과값 => 
# 5    518
# 4    449
# 2    409
# 0    265
# 3    260
# 1    239
# 6     54
# 7     21