본문 바로가기
머닝러신 아니고 머신러닝

k-means 케이평균 군집분석 정리

by jnhn 2023. 4. 4.

뭐만하면 k-어쩌고

  솔직히 처음 k-means에 대해 들었을때 드는 생각을 다름아닌 뭐만하면 k어쩌고ㅋㅋㅋㅋ 물론 당연히 Korea의 K는 아니겠지만 암튼 내기준 웃참포인트였다.

1. K-means 케이평균 군집분석이란?

  K-means 클러스터링은 총 K개의 그룹이나 클러스터를 만들어주는 것을 의미한다. 아하 그래서 군집분석이라고 그러는구나 오키

요약하자면 군집분석이란 비지도 학습의 일종으로 주어진 각 객체들의 유사성을 분석해서 유사성이 높은 대상끼리 일반화된 그룹으로 분류하는 기법이다. 군집분석 활용분야는 암판별 머신러닝모델에 지도학습데이터를 학습시킬때 비지도학습과 함께 사용해서 모델의 정확도를 높이거나, 마케팅 세그멘테이션(segmentation, 특성에 맞는 고객들끼리 군집화), 통신사 기지국 세울때 위치를 정하는데 사용된다.

knn과 케이평균을 비교하자면 이런느낌 유사하면서도 다른데. 둘은 모두 k개의 점을 지정하여 거리를 기반으로 구현되는 거리기반 분석 알고리즘이라는 점에서 유사하다. 반면, 둘의 차이점은 지도학습(정답이 있는 데이터)에 속하는 knn 알고리즘과 달리 k-means 알고리즘은 비지도학습(정답이 없는 데이터) 방법에 속한다.

  기본적인 가정은 첫째, 하나의 군집 내에 속한 개체들의 특성은 동일하다. 둘째, 군집의 갯수 혹은 구조와 관계없이 개체간의 거리를 기준으로 분류한다. 셋째 개별 군집의 특성은 군집에 속한 개체들의 평균값으로 나타낸다.

  군집분석은 다양한 데이터 형태에 적용이 가능하고, 특정변수에 대한 정의가 필요하지 않는 등 적용이 다양한 탐색기법이라는 장점이 있는 반면, 초기 군집수(k값)에 따라 결과가 바뀔수 있고 이상치에 민감하다는 단점이 있다.

 

2. R로 K-means 모델 만들기

 
#1. 기본 데이터셋을 만듭니다.

dot <- c( 3, 4, 1, 5, 7, 9, 5, 4, 6, 8, 4, 5, 9, 8, 7, 8, 6, 7, 2, 1 )
name <- c('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J')
col <- c('X', 'Y')
data <- matrix( dot, nrow=10, ncol=2, byrow=TRUE, dimnames=list(name,col) )
data

#2. 위에서 만든 데이셋으로 plot 그래프를 그립니다.
plot( data,  col='black', cex=2)

#3. R에 내장된 kmeans 함수를 이용해서 위의 data 를 2개의 군집으로 나눕니다.

km <-  kmeans( data,  2)
km

km <-  kmeans( data,  2)
km$cluster  #  각각의 데이터가 어느 군집인지 출력

km$center  #  중심점 2개의 좌표가 출력

#4. 중심점 두 지점만 시각화 합니다. 
plot(  round(km$center), col=c("red","blue"), pch=22, cex=2, bg=c('red', 'blue'),
         xlim=range(0:10), ylim=range(0:10)  )

#5. 원래 데이터들과 같이 중심점 두 지점을 시각화 합니다. 

plot(   km$center , col=c("red","blue"), pch=22, cex=2, bg=c('red', 'blue'),
         xlim=range(0:10), ylim=range(0:10)  )

par( new=T )  # 두개의 그래프를 합칠 때 사용

plot( data, col=km$cluster,  cex=2, xlim=range(0:10), ylim=range(0:10) )

#6. 각각의 좌표가 어느 군집인지 출력
cbind( data, km$cluster) 

#7. 방금 군집화한것을 더 좀 이해되기 쉽게 시각화 함(R 의 장점)
install.packages("factoextra")
library(factoextra)
km<- kmeans(data,2)
fviz_cluster(km, data = data, stand =F)

#1. 데이터셋

#2. plot 그래프

#3. 두개의 군집으로 나누기
Cluster means:   # 중심점 2개의 좌표 
      X     Y
1     7     8.0    <---- 첫번째 중심점 좌표 
2    3     3.8     <---  두번째 중심점 좌표 

Clustering vector:    # 10개의 데이터가 각각 어느 군집에 속한지를 표시 
A  B  C  D   E   F   G   H   I   J 
2  2  1   2    1   2    1    1   1   2 
#4.

#5. 원래 데이터들과 같이 중심점 두지점 시각화


그 결과

 

유방암환자와 정상환자를 분류하는 k-means모델 생성

 

####정규화하기 전

#1. 데이터 로드
wisc <-read.csv("c:\\data\\wisc_bc_data.csv")
nrow(wisc)
ncol(wisc)

#2. 분류에 필요한 컬럼만 선택
wisc2 <- wisc[ , 3:32]
##1번 컬럼(환자번호), 2번(정답)을 제외한 나머지 데이터만 선택

#3. 비지도 학습으로 2개로 군집화하기
km <- kmeans(wisc2, 2)
km

#4. 시각화하기
library(factoextra)
fviz_cluster(km, data= wisc2, stand=F)

#5. 모델 평가
cbind(wisc$id, wisc$diagnosis, km$cluster)
install.packages("gmodels")
library(gmodels)
CrossTable(wisc$diagnosis, km$cluster)
##정규화한 후
#1. 데이터 로드
wisc <-read.csv("c:\\data\\wisc_bc_data.csv")
nrow(wisc)
ncol(wisc)

#2. 분류에 필요한 컬럼만 선택
wisc2 <- wisc[ , 3:32]
##1번 컬럼(환자번호), 2번(정답)을 제외한 나머지 데이터만 선택

#정규화합니다
normalize <- function(x){return((x -min(x))/(max(x)- min(x)))}
wisc_n <- as.data.frame(lapply(wisc2, normalize))

#3. 비지도 학습으로 2개로 군집화하기
km2 <- kmeans(wisc_n, 2)
km2

#4. 시각화하기
library(factoextra)
fviz_cluster(km2, data= wisc_n, stand=F)

#5. 모델 평가
cbind( wisc$id,  wisc$diagnosis,  km2$cluster) 
#install.packages("gmodels")
library(gmodels) 
CrossTable( wisc$diagnosis, km2$cluster )

 

 

유방암데이터를 정규화하기 전(좌), 후(우)

 

정규화하기 전의 정확도는 0.85 정규화 후는 0.9279438으로 상승함

3. K-means 머신러닝은 어떻게 데이터를 군집화하는가?

  군집분석의 유사성계산은 거리와 유사성으로 구분하는데 거리는 값이 작을수록 두 값이 유사함을 의미하고, 유사성은 값이 클수록 두 두 관찰지가 서로 유사함을 뜻한다(코사인값, 상관계수). 데이터와 데이터 사이의 거리를 계산해서 가장 가까운 거리에 있는 데이터끼리 묶어주는데 이 거리를 계산할 때 사용하는 수학식이 바로 유클리드 거리공식(L2 Distance)이다. 공식은 아래와 같다.

2차원에서의 l2 거리공식

  중학생때 배웠던 피타고라스 정리가 떠오름

n차원에서의 유클리드 거리공식

두 점 사이의 유클리드 거리를 구하는 코드는 다음과 같다.

a = c(2, 5)
b = c(4, 7)

답: sqrt(sum(b-a)^2)

cf) 맨하탄거리공식(Manhattan Distance): 블록별로 택시가 지나가듯이 출발점과 도착점을 잇는 가장 짧은 거리의 길이 실제로 맨하탄 골목길을 걸어가는 것에서 유래했다고 한다.

이외에도 민코우스키 거리, 마할라노비스 거리, 자카드 거리 공식이 있다. 

 

4. Python 파이썬으로 K-means 모델 만들기

#1. 데이터를 로드
import pandas as pd df = pd.read_csv("/content/wisc_bc_data.csv")
df.head()

#2. 결측치 확인
df.isnull().sum()

#3. 필요한 컬럼 선택
data = df.iloc[ : , 2: ]# 환자번호와 정답은 제외합니다.
data.head()

#4. 정규화 진행 
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler()
scaler.fit(data)

# 정규화 계산
data_scaled = scaler.transform(data)

# 정규화된 내용으로 데이터 변환
data_scaled

#5. 모델 생성
from sklearn.cluster import KMeans
model = KMeans( n_clusters = 2, random_state=1 )

#6. 모델 훈련
model.fit(data_scaled)

# 비지도학습이라 정답없이 데이터만 학습했습니다.
# 지도학습에서는 model.fit(x, y) <-- 정답을 같이 줬습니다

#7. 군집 결과 확인
km = model.labels_ km

#8. 정확도 확인 ( 비지도 학습은 정확도를 확인하는게 아니지만 잘 분류했는지 궁금해서 확인 )
df['cluster'] = km df[['diagnosis', 'cluster']]
#머신러닝이 0 을 B 로 예측하고 있고 1을 M 으로 예측하고 있습니다. # 진짜 정답 데이터를 M 을 1로 변경하고 B 를 0으로 변경해서y_train 을 생성
y_train = df.diagnosis.apply( lambda x : x =='M').astype(int)
y_train
from sklearn.metrics import confusion_matrix confusion_matrix( y_train, df.cluster ) # (정답, 예측)
#4 정규화 진행: "k-means 모델은 이상치에 굉장히 민감하므로 이상치를 제거하거나 또는 이상치를 둔감하게 만들어주는 정규화 작업을 반드시 수행해야 좋은 모델이 나옵니다. "


#6 모델훈련: 비지도학습이라 정답없이 데이터만 학습함 만약 지도학습이었다면 정답도 줘야함

#7 군집결과를 확인할때 0이양성인지 1이 양성인지 알 수가 없다.

#8. 정확도를 확인하기 위해서는 데이터를 변환해주어야함

결과:
array([[348,   9],
         [ 32, 180]])

        348 +  180 
-------------------------------  =    0.9279437609841827
  348 + 9 + 32 + 180

위의 내용은 ITWILL EDUCATION CENTER  빅데이터 분석 전문가 양성과정 유연수선생님의 강의를 바탕으로 요약한 바를 밝힙니다.