본문 바로가기
AI, 빅데이터

[AI] K-Means Clustering

by Foxy현 2022. 12. 18.
728x90
반응형

이번 글에서는 군집화로 널리 사용되는 비지도 학습 중 하나인 K-means 클러스터링에 대해 알아보겠습니다

 

먼저 비지도 학습은 컴퓨터에게 우리가 정답을 주지 않고 데이터만 주었을 때 데이터 안에서 패턴이나 구조등을 발견하는 것을 말합니다.

 

대표적으로 군집화 알고리즘이 있으며, 이는 추천 시스템, 검색 엔진 등에 사용되곤 합니다.

 

군집화의 목표는 서로 유사한 데이터들은 같은 그룹으로, 서로 유사하지 않는 데이터는 다른 그룹으로 묶는 것입니다.

이때, 몇개의 그룹인지 또는 데이터간의 유사 데이터를 정의해야 하는데 이런 문제들을 해결하는 방법 중 하나가 K-means 알고리즘입니다.

 

K-means에 K는 무엇일까요?

K는 클러스터 그룹의 수를 말합니다. 데이터를 줬을 때 몇개의 그룹으로 묶을 것인지를 지정하는 것이죠.

또한 Means는 각 데이터로부터 데이터가 속한 클러스터의 중심까지의 평균 거리를 의미합니다.

이 거리를 최소화 하는 것이 목표가 되겠네요. 왜냐하면 거리가 가까울수록 유사하다는 의미이니까요!

 

그렇다면 이를 구현하는 과정에 대해 살펴보겠습니다

  1. K개의 랜덤 중심점을 배치
  2. 각 그룹의 데이터들을 가장 가까운 중심점으로 할당(초기 군집)
  3. 군집으로 형성된 데이터들 안에서 해당 중심점을 업데이트
  4. 반복하여 더이상 중심점이 바뀌지 않을 때까지 업데이트

구현해봅시다.

 

먼저 필요한 라이브러리를 불러옵니다.

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import random

 

먼저 데이터를 생성합시다.

데이터는 임의로 작성했습니다.

 

중심점 3개와 중심점 주변에 랜덤 데이터를 생성합니다.

 

center_1 = np.array([1,1])
center_2 = np.array([5,5])
center_3 = np.array([8,1])

data = np.random.randn(10,2) + center_1
data = np.concatenate((data, np.random.randn(10,2) + center_2))
data = np.concatenate((data, np.random.randn(10,2) + center_3))

plt.scatter(data[:,0], data[:, 1])

 

이제 K_means 함수를 만들어봅시다.

이번 글에서는 머신러닝 라이브러리를 사용하지 않고, 직접 구현합니다.

 

def k_means(x,k):
    random_point = np.random.choice(len(x),size=k,replace=False) # 랜덤 인덱스 
    # ============ 1. 군집의 중심 위치 선정 =============
    a = x[random_point,:] # data 인덱스의 값(x,y)
    
    # 클러스터 생성
    cluster = np.zeros(x.shape[0]) # x 크기만큼 0 배열 생성
    
    bools=1 # while문의 조건문에 사용할 변수 완료시 false(0)으로 변경
    
    
    # =============== 2. 군집 재구성 =================
    while bools:
        for index,row in enumerate(data): # enumerate로 인덱스와 값 가져오기
            tmp=float('inf') # 거리는 실수일 수 있으므로 양의 무한대 선언
            
            # 아래의 for문에서는 각 k점과의 distance와 k의 인덱스 값을 cluster에 저장함
            for q,w in enumerate(a): # q = 인덱스, w = (x,y)
                d = np.sqrt((w[0]-row[0])**2 + (w[1]-row[1])**2)
                if tmp>d:
                    tmp=d
                    cluster[index]=q # 클러스터에는 0부터 k-1까지의 값을 갖음
                    
    # ============== 3. 군집별 평균 위치 결정 ================
        new = pd.DataFrame(data).groupby(cluster).mean().values # 빠른 연산위해 df로 변경 후 평균 계산
        # 클러스터별로 묶고 평균 계산을 한 데이터들을 new에 저장

        # 그래프 그리기
        sns.scatterplot(data[:,0],data[:,1],hue=cluster)
        plt.scatter(a[:,0],a[:,1],marker='*',c='r',s=100)
        plt.show()
        
        # ============= 5. 수렴 조건 ===============
        if np.count_nonzero(a-new)==0:
        # nonzero = 요소 개수 세기 
            bools=0 # => while문 종료
        else:
            # ============= 4. 군집 중심 갱신 ==============
            a=new
        # a와 new가 같지 않을 경우 갱신

 

위의 과정에 대해 설명을 하자면,

random_point = np.random.choice(len(x),size=k,replace=False)

x 데이터에서 k개의 중심 위치 인덱스를 선정합니다.

a = x[random_point,:]

a에는 data 인덱스의 실제 값이 들어갑니다

cluster = np.zeros(x.shape[0])

x크기만큼의 0배열을 만들어 클러스터 배열을 생성합니다.

while bools:
        for index,row in enumerate(data): 
            tmp=float('inf') 
            for q,w in enumerate(a): 
                d = np.sqrt((w[0]-row[0])**2 + (w[1]-row[1])**2)
                if tmp>d:
                    tmp=d
                    cluster[index]=q

data의 인덱스와 값을 가져오고, 각 k 점과의 distance와 k의 인덱스 값을 cluster에 저장합니다

클러스터에는 0부터 k-1까지의 값을 갖습니다.

 

K-Means 함수를 사용해볼까요?

k_means(data,5)

초기와 마지막으로 cluster 된 위치가 달라지는 것을 확인할 수 있네요

 

 

 

 

 

 

728x90
반응형