본문 바로가기
머신러닝

[머신러닝][파이썬]K-means clustering

by 방구석 데이터사이언티스트 2022. 1. 14.
728x90
반응형

오늘은 KBL 선수들의 기록 데이터로 클러스터링을 진행해보겠습니다.

데이터는 KBL 공식 홈페이지를 통해 최근 5년간의 KBL 선수의 개인 기록을 크롤링했습니다. 

 

1. 모듈 가져오기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np
import seaborn as sns



import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
%matplotlib inline
 
from factor_analyzer import FactorAnalyzer


from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
cs

pandas, numpy, seaborn, matplotlib 등 기본적인 모듈과 

sklearn에서 KMeans, Silhouette_samples, silhouette_score를 가져옵니다. 

from factor_analyer import FactorAnayzer는 FA(요인분석)을 위한 것이며 이번 분석에서는 상관관계가 높은 변수들을 함축하기 위해 FA를 진행한 후 clustering을 했습니다. 

 

2. 데이터 불러오기

1
2
3
4
5
6
7
df_20=pd.read_csv('C:/Users/user/Desktop/20_21_seezn.csv')
df_19=pd.read_csv('C:/Users/user/Desktop/19_20_seezn.csv')
df_18=pd.read_csv('C:/Users/user/Desktop/18_19_seezn.csv')
df_17=pd.read_csv('C:/Users/user/Desktop/17_18_seezn.csv')
df_16=pd.read_csv('C:/Users/user/Desktop/16_17_seezn.csv')
 
df=pd.concat([df_16,df_17,df_18,df_19,df_20])
cs

판다스를 이용해 csv파일을 불러올때는 pd.read_csv()를 해주시면 됩니다.

여러 데이터를 하나로 합치고 싶을 때(세로결합)는 pd.concat()을 사용해주시면 됩니다. 

2. 데이터 Scaling

1
2
3
4
5
from sklearn.preprocessing import StandardScaler
df_num=df.iloc[:,3:-1# 연속형 변수만 추출
 
# Standard scaler
df_scale = pd.DataFrame(StandardScaler().fit_transform(df_num), columns=df_num.columns, index = df_num.index)
cs

 

 

clustering을 진행하기 전 주의사항이 크게 두 가지 있습니다.

1. 일반적으로 연속형 변수만을 활용한다. 

2. 변수를 정규화 혹은 표준화를 한다. 

 

이유 : 먼저 연속형 변수만을 사용하는 이유는 clustering의 유사도 척도가 거리를 기반으로 하기 때문입니다. 

예를 들어 성별 같은 범주형 변수는 남자 와 여자를 거리의 척도로 나타낼 수 없기 때문입니다. 남자 = 1, 여자 = 0으로 인코딩한다면 그 차이는 1이지만 남자 = 10 , 여자 = 0으로 인코딩하면 그 차이는 10이기에 일관성이 없는 것이죠

또한 변수를 정규화 혹은 표준화를 하는 것도 중요합니다. 일반적으로 유클리드 거리를 계산할 때 각 변수들의 단위가 다르다면 단위가 작은 변수는 영향이 적겠죠? 그렇기 때문에 변수를 정규화/표준화를 해야합니다. 

 

따라서 df.iloc[:, 3:-1]는 df(데이터프레임)에서 4번째부터 마지막 변수전까지 추출하는 것이며

StandardScaler().fit_transform()을 통해 스탠다드스케일링을 합니다. 스탠다드스케일링을 하고나면 데이터가 array형태로 되어있기때문에 pd.DataFrame()을 통해 다시 데이터프레임형태로 만드는 것입니다. 

 

3. 변수 축소(FA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Bartlett Test
## 요인분석 모형의 적합성 여부 검정 (요인분석모형으로 적합한지 유의확률로 파악)
## H0: 상관관계 행렬이 단위행렬이다 --> 귀무가설이 기각되어야 요인분석 모델 사용가능
from factor_analyzer.factor_analyzer import calculate_bartlett_sphericity
chi_square_value, p_value = calculate_bartlett_sphericity(df_scale)
chi_square_value, p_value # p-value < 0.05 --> 귀무가설 기각
 
# KMO Test (Kaiser-Meyer-Olkin Test)
## 변수들간 상관관계가 다른 변수에 의해 잘 설명되는 정도를 나타내는 값
## 이 값이 작으면 요인분석을 위한 변수들의 선정이 적절하지 못하다는 것을 의미
## 일반적으로 0.9 이상이면 아주 좋음, 0.8 이상이면 꽤 좋음, 0.7 이상이면 적당함, 0.6 이상이면 평범함, 0.5 미만이면 안 좋음
 
from factor_analyzer.factor_analyzer import calculate_kmo
kmo_all, kmo_model =calculate_kmo(df_scale)
kmo_model # 0.8 이상이므로 꽤 좋음
 
# factor 3개로 선택
fa = FactorAnalyzer(n_factors=3, rotation = "varimax")
fa.fit(df_scale)
# FactorAnalyzer()에서 method="ml", rotation="promax" 설정도 가능 #ml: 최대우도방법
# 다른 옵션 추가 설명: https://github.com/EducationalTestingService/factor_analyzer
 
# FA: Factor Loadings
fa_result_loading = pd.DataFrame(fa.loadings_, 
                                 columns = ['Factor1''Factor2''Factor3'],
                                 index=df_scale.columns)
 
# 시각화
plt.figure(figsize=(6,10))
sns.heatmap(fa_result_loading, cmap="Blues", annot=True, fmt='.2f'#소수 둘째자리까지
cs
 

위 코드는 FA요인분석을 하는 코드입니다.

Bartlett Test와 KMO test는 FA를 진행하기전 진행하는 검정입니다. 데이터의 변수들이 FA를 하기 적절성과 적합성을 확인하는 작업입니다. 

마지막 두줄은 Factor Loadings을 시각화하는 코드입니다.

Facrtor Loading는 변수들이 어떻게 묶였고 어떤 요인으로 정의할 수 있을 지 해석하는 용도입니다.

 

1
2
3
4
5
6
# Factor Analysis가 적용된 dataset (scaled)
X_f = fa.fit_transform(df_scale)
X_ff = pd.DataFrame(X_f[:,:3], 
                    columns = ['Factor1''Factor2''Factor3'], 
                    index = df_scale.index)
X_ff
cs

 

실질적으로 clustering을 하기위한 데이터프레임을 생성하는 코드입니다. (885, 3) 사이즈의 데이터프레임이 생성되는 것을 확인 하실 수 있습니다. 

4. k-means Clustering

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# graph를 통해 k값 선정
# distortion = 군집내 오차제곱합(SSE; Sum of Suqared Errors)
distortions = []
for i in range(1,20):
    km = KMeans(
    n_clusters= i, init='random',
    n_init=10, max_iter=300,
    tol=1e-04, random_state=0
    )
    km.fit(X_ff) # elbow 계산할 dataset 적기
    # inertia는 군집내 분산을 의미
    distortions.append(km.inertia_)
plt.figure(figsize=(10,6))
plt.plot(range(1,20), distortions, marker='o')
plt.xlabel('Number of Clusters')
plt.ylabel('Distortion')
plt.show()
cs

 

k(군집수)를 선택하기위해 elbow method를 사용했습니다. 저는 그래프를 봤을 때 k = 4 혹은 5가 좋을 것이라고 판단했습니다. 결론적으로 k = 5로 지정하고 clustering을 진행했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
model = KMeans(n_clusters=5, random_state=20210330, algorithm='auto')
# n_clusters=5 : 군집의 개수 (k)
# random_state=20210330 : seed 역할 (모델을 일정하게 생성 = 랜덤X)
model.fit(X_ff)
 
# 각 군집(cluster) 표시
pred = model.predict(X_ff)
 
# 4. 원형 데이터에 군집 예측치 추가
X_ff['k_means_cluster'= pred
 
# 군집별 centroid
centers = model.cluster_centers_
centers
cs

본격적으로 clustering을 fitting하는 작업입니다. 그리고 pred = model.predict(X_ff)로 데이터의 군집을 뽑아낸 다음 X_ff['k_means_cluster'= pred로 원래데이터에 하나의 변수로 클러스터를 표시해놓을 수 있습니다. 그래서 많은 지도학습 예측모델을 생성하는 과제에서 클러스터링 결과를 하나의 파생변수로 사용하는 사례도 종종 있습니다. 마지막 두 줄은 군집별 중심을 보여주는 코드입니다. 

 

 

728x90
반응형

댓글