< K-Means Clustering >
- K-Means Clustering은 비지도 학습 알고리즘 중 하나로, 데이터를 여러 개의 클러스터로 그룹화하는 데 사용된다.
- 이 알고리즘의 목표는 데이터 포인트들을 그룹 내에서 가능한 작은 거리의 합계로 클러스터링하는 것!
# 이전까지 작성한 Classification(분류)에 KNN, SVM, Decision Tree, Logistic regression
# Prediction(예측)에 regression(회귀) 은 모두 Supervised Learnig
# Clustering은 모두 Unsupervised Learning 이다.
k 개의 그룹을 만든다. 즉, 비슷한 특징을 갖는 것들끼리 묶는것
다음을 두개, 세개, 네개 그룹 등등 원하는 그룹으로 만들 수 있다.
알고리즘
또다시 중심에 직교하는 선을 긋고, 자신의 영역안에 있는 것들을 자신의 색으로 바꾼다.
중심을 이동해서, 영역을 나눴는데, 나눈 영역안에 다른 카테고리가 더이상 나타나지 않으면, 끝낸다.
< Random Initialization Trap >
- 클러스터링 알고리즘에서 발생할 수 있는 문제
- 이 문제는 K-Means 알고리즘이 초기 중심의 무작위 선택에 따라 결과가 크게 달라질 수 있다는 것을 의미한다.
다음과 같은 데이터 분포가 있다고 치자.
우리가 원하는 클러스터링 그룹화는, 아래와 같은 것이다.
원치 않는 그룹화가 되어버렸다!
위와 같은 문제는 해결한것이, K-Means++ 알고리즘이다.
< Choosing the right number of clusters >
몇개로 분류할지는 어떻게 결정하는가? K의 갯수를 정하는 방법
within-cluster sums of squares
센터가 원소들과의 거리가 멀수록 값이 커진다. 따라서 최소값에 가까워지는 갯수를 뽑되, 갯수가 너무 많아지면 차별성이 없어진다.
# 사람 팔꿈치처럼 확 꺾인다고 하여 엘보우 메소드라고 한다.
< 에제를 통하여 코딩해 보자 >
import pandas as pd
df = pd.read_csv('../data/Mall_Customers.csv')
# 원하는 그룹(비슷한 사람들끼리) 을 만들어야 한다. => 클러스터링
df.isna().sum()
CustomerID 0
Genre 0
Age 0
Annual Income (k$) 0
Spending Score (1-100) 0
dtype: int64
# 클러스터링(Unsupervised) 은 y 그룹을 만들어 달라고 요청하는거기 때문에 X만 생성
X = df.loc[ : , 'Genre' : 'Spending Score (1-100)' ]
# 문자열 데이터가 있으므로 인코딩
X['Genre'].nunique()
2
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit_transform(X['Genre'])
array([1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1,
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
1, 1])
# 스펠링 순으로 순서를 매기기 때문에 0이 Female 1이 Male
sorted(X['Genre'].unique())
['Female', 'Male']
# 인코딩한 데이터를 Genre 컬럼 값으로 넣기
X['Genre'] = encoder.fit_transform(X['Genre'])
ㄴ 변환된것 확인
# K-Means는 피쳐스케일링을 안해도 된다. 어차피 이 데이터를 가지고 평균을 구하는거기 때문에
# 한다고 문제가 되진 않지만 구지 필요가 없다
# 컬럼이 4개이므로 차트로 그릴수 없다. 차트로 그릴수 있는 최대 갯수는 3개 x,y,z 4개 이상은 불가능 하다.
# KMeans 인공지능 생성
from sklearn.cluster import KMeans
# 인공지능 이름은 kmeans () 파라미터 안에 그룹수를 정해줘야 하는데 아직 적합한 수를 못구했으므로 임의로 적는다. 지금은 3개
kmeans = KMeans(n_clusters= 3, random_state= 10)
# 학습 fit 와 예측 predict를 한꺼번에 실행
y_pred = kmeans.fit_predict(X)
y_pred
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1])
# 구한 그룹정보를 원본 데이터에 넣어준다.
df['Group'] = y_pred
# 그룹1인 그룹사람들에게 푸시보낼거다. 이 그룹 데이터 가져와라
df.loc[df['Group'] == 1 , ]
## 그룹수를 바꾸면서 적합한 그룹수를 다시 알아보자
# 반복문을 사용하여 1~10개까지 그룹수를 넣어본다.
# wcss라는 임의의 비어있는 리스트를 만들어줘서 해당 반복문 결과를 리스트에 저장시킨다.
wcss = []
for i in range(1, 10+1) :
kmeans = KMeans(n_clusters=i, random_state= 10)
kmeans.fit(X)
wcss.append(kmeans.inertia_)
# 경고문은 무시하여도 된다.
wcss
[308862.06,
212889.442455243,
143391.59236035674,
104414.67534220166,
75399.61541401484,
58348.64136331505,
51167.19736842105,
45324.85021951262,
40811.455768566826,
37141.48254409704]
# 시각화 해보자
import matplotlib.pyplot as plt
plt.plot(wcss)
plt.show()
# 대략 5개일때부터 변화가 없으므로, 그룹수를 5개로 하여 다시 학습 후 예측
kmeans = KMeans(n_clusters= 5, random_state= 1)
y_pred = kmeans.fit_predict(X)
# 원본데이터에 예측값을 컬럼으로 넣어 눈으로 비교해보자.df['Group'] = y_pred
# 각 그룹별로 확인해보고 싶을때.
# 나눈 갯수대로 해당 값만 불러와서 확인 할수 있다.
df.loc[df['Group'] == 0 , ]
df.loc[df['Group'] == 4 , ]