데이터 과학 Data Science/비지도학습

k-means 알고리즘으로 패턴 찾고 평가까지

허니비 honeybee 2022. 9. 18. 23:19

 

비지도학습은 언제 쓰냐! 

 

데이터에 라벨링이 안 되어 있을 때 쓴다. 라벨 = 정답값이라고 쉽게 생각하자. 

내가 뭔가 데이터를 이용해서 예측이나 분류를 하는 모델을 만들고 싶어.. 그럼 예측값이나 분류값이 약간은 있어야될거아님..그래야 학습을 시킬거아님? 근데 그게 없어

 

이럴 때 쓴다 ㅎ 

 

비지도 학습도 당연히 여러가지 대표 모델들이 있는데 기본적으로는 "유사성" 을 이용해서 주어진 데이터셋을 하위 데이터셋으로 분류함.그래서 분류된거끼리 묶으면 고걸 클러스팅이라고 부른다!  요번 포스팅은 그 여러가지 비지도 학습 중에서 정말 제일 쉽고 간단하고 자주 쓰이는 k-means 알고리즘을 다뤄보겠어.

 

 

 

1. k-means algorithm 개념과 작동원리 

 

k-means 알고리즘은 기본적으로 means 의 개수(k개) 를 정해주고 몇개로 분류해줘 ~ 명령내리는 애다. 사용자가 k 를 지정해줘야 한다는 게 중요한 포인트며 그걸 기준으로 분류 알고리즘이 작동한다

 

여기서 핵심은 분류를 반복할 때마다 중심centroid 가 업데이트된다는 점이다. 이 중심이 최적의 위치에 올 때 까지 계속해서 반복을 하게 된다. 그렇게 k-means 는 지정된 횟수만큼 반복해서 무작위로 나열된 점들이 서로 가장 가까운 유클리스 거리를 가질 때 까지 중심을 업데이트할거다. 유클리드 거리는.. 작을수록 비슷한 데이터라고 보면 된다. 일단 이건 넘어가겠다 

 

이 때! 초기 중심값을 선택해주는 방법이 두 가지가 있다 

 

1. 무작위 random 으로 돌리기 k-means

2. 사용자가 판단해 배치해주기 k-means ++ 

 

일반적으로는 후자가 더 좋은 결과를 낸다. 왜냐면 초기값이 지정된 경우 더 빠르게 알고리즘이 수렴하고 작업이 끝날테니깐. 가능한 경우에는 훈련데이터셋을 먼저 살펴보고 각 데이터 포인트를 가장 가까운 중심에 할당하는게 좋다. 근데 딱히 그런거 모르겠는 경우 그냥 랜덤으로 돌리자.. 되도 않는 선택을 했다가 정확도가 되려 떨어질지도..모르니

 

 

k-means / k-means ++

 

 

 

 

2. 예제코드

2.1. 라이브러리와 데이터 import 

 

불러와서 일단 데이터를 시각화해보자. 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics

# Load input data
# delimiter = 구분자
X = np.loadtxt('df', delimiter=',')

# Plot input data
plt.figure()
plt.scatter(X[:,0], X[:,1], marker='o', facecolors='none', 
        edgecolors='black', s=80)
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
plt.title('Input data')
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())

 

 

이렇게 생김. 근데 이게 가능한 이유는 일단 데이터가 2차원이기 때문이다. 3차원까지 시각화를 할 수 있다지만 그 이상 차원이 많다면 (속성이 많다면) 시각화 뿐만 아니라 어떤 속성을 기반으로 데이터가 분류됐는지 알기 좀 어려울 수 있다. 

 

 

 

 

2.2. 최적의 k 값 찾기

 

그리고 이런 류의 데이터는 딱 분포만 봐도 사실 클러스터링이 되어있는 형태의 데이터셋이다. 만약에 저렇게 데이터를 시각화 해 볼 수 없는 경우이거나 분류가 잘 안된다면 튜닝을 하면 된다. elbow method 를 이용할 수 있음. 평가지표인 interia 를 기준으로 반복문을 돌려서 fit 해보자. 

 

#interia = 평가지표, 얼마나 응집성이 있는지 봄
k_list = []
cost_list = []
for k in range (2, 7):
    kmeans = KMeans(n_clusters=k).fit(X)
    interia = kmeans.inertia_
    print ("k:", k, "| cost:", interia)
    k_list.append(k)
    cost_list.append(interia)
    
plt.plot(k_list, cost_list)

 

 

그러면  요런식으로 k 값 별로 cost 값이 나와 줌. 값이 확 꺾이는 구간을 이용하자 (이 예제에선 4나 5가 적절)

k: 2 | cost: 228671013638.4617
k: 3 | cost: 154450862150.5793
k: 4 | cost: 93438696006.9793
k: 5 | cost: 60814830876.553154
k: 6 | cost: 46125419994.00405
[<matplotlib.lines.Line2D at 0x7f6495111890>]

 

 

 

 

 이 엘보우 메서드는 무엇을 의미하냐! 언제 클러스터 세트가 데이터 분산의 "대부분" 을 의미하는지 알려준다. 데이터가 얼마나 잘 응집되었는지, 분산의 얼만큼을 클러스터가 포함하는지를 기준으로 나눠준다. 이 때 저 엘보우 메서드에서 확 꺾이는 부분 ( 이 예제에서는 4) 를 이용하는 이유는 그때가 바로 분산 증가율이 뚝 떨어지는 구간이기 때문이다. 

 

다만, 비지도학습이니만큼 클러스터의 개수를 정확히 얻는 완벽한 방법은 존재하지 않는다. 

 

 

 

 

2.3. 객체 선언 ~ 훈련 ~예측

 

어찌되었건 k-means 를 써보겠다

객체를 선언하고 바로 fit 해주면 끝 엄청쉬움. 조절을 해볼만한 파라미터들은 다음과 같음. 알고리즘 방식과 init 에 따라 성능편차가 꽤나 있음 

# Create KMeans object 
#init{‘k-means++’, ‘random’} 디폴트는 전자
#n_init = 반복할 횟수, 디폴트가 10, 높일수록 inerita 값 개선됨
# algorithm{“lloyd”, “elkan”, “auto”, “full”}, default=”lloyd”

kmeans = KMeans(init='k-means++', n_clusters=num_clusters, n_init=10)

# Train the KMeans clustering model
kmeans.fit(X)

 

 

2.3. 클러스터링 시각화 with 경계

 

경계를 설정하기 위해.. 넘파이의 meshgrid 를 이용하자

# Step size of the mesh
#경계를 시각화하기 위함임! gird 의 사이즈 조절
step_size = 0.01

# Define the grid of points to plot the boundaries
# meshgrid() = 격자 만드는 메서드
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
x_vals, y_vals = np.meshgrid(np.arange(x_min, x_max, step_size), 
        np.arange(y_min, y_max, step_size))

# Predict output labels for all the points on the grid 
output = kmeans.predict(np.c_[x_vals.ravel(), y_vals.ravel()])

# Plot different regions and color them 
output = output.reshape(x_vals.shape)
plt.figure()
plt.clf()
plt.imshow(output, interpolation='nearest',
           extent=(x_vals.min(), x_vals.max(), 
               y_vals.min(), y_vals.max()),
           cmap=plt.cm.Paired, 
           aspect='auto', 
           origin='lower')

# Overlay input points
# 색칠한 경계 위에 입력 포인트 오버레이# 색칠한 경계 위에 입력 포인트 오버레이
plt.scatter(X[:,0], X[:,1], marker='o', facecolors='none', 
        edgecolors='black', s=80)

# Plot the centers of clusters
# 클러스터의 중심 칠하기
cluster_centers = kmeans.cluster_centers_
plt.scatter(cluster_centers[:,0], cluster_centers[:,1], 
        marker='o', s=210, linewidths=4, color='black', 
        zorder=12, facecolors='black')

x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
plt.title('Boundaries of clusters')
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

 

그럼 요렇게 결과물이 나올거임.. 안 예쁘다.. 색이랑 사이즈랑 x y 까지 입력해주면 좀 봐줄만한 그래프가 되겠지만 나라면 예측 데이터 태블로로 넘겨서 시각화하겠음...

 

 

 

 

728x90
반응형