지난번 포스팅에서는 분할적 군집분석(Partitioning clustering)에서 군집의 개수 k를 결정하는 3가지 방법 (계층적 군집분석 덴드로그램, Elbow method, Silhouettes method)을 소개하였습니다.

군집분석 결과를 현장에 적용하려면 각 군집의 특성을 이해하고, 군집별로 차별화된 대응 전략을 도출할 수 있어야만 합니다. 이번 포스팅에서는 군집분석 결과를 해석하는 3가지 방법을 소개하겠습니다.

(1) 군집별 변수별 중심 좌표 (Center Points by Clusters)
(2) 군집별 변수별 평행 좌표 그림 (Parallel Coordinates Plot by Clusters)
(3) (차원축소 후) 군집별 산점도 (Scatter Plot by Clusters using Reduced Dimension)



  (0) 샘플 데이터 준비 : USArrests {datasets}


예제로 사용할 샘플 데이터는 R datasets 패키지에 내장되어있는 USArrests 데이터셋을 사용하겠습니다. 미국 내 50개 주별 범죄율 관련된 살인(murder), 폭행(assault), 도시인구(UrbanPop), 강간(rape) 의 4개 변수 통계 데이터가 들어있습니다.

군집분석은 변수별 척도에 민감하므로 scale() 함수를 사용해서 표준화(standardization)를 해주었습니다.


## importing USArrests dataset from {datasets}
data(USArrests)

dim(USArrests)
# [1] 50  4

head(USArrests)
# Murder Assault UrbanPop Rape
# Alabama      13.2     236       58 21.2
# Alaska       10.0     263       48 44.5
# Arizona       8.1     294       80 31.0
# Arkansas      8.8     190       50 19.5
# California    9.0     276       91 40.6
# Colorado      7.9     204       78 38.7


## standardization (scaling)
USArrests_scaled <- data.frame(scale(USArrests))

head(USArrests_scaled)
# Murder   Assault   UrbanPop         Rape
# Alabama    1.24256408 0.7828393 -0.5209066 -0.003416473
# Alaska     0.50786248 1.1068225 -1.2117642  2.484202941
# Arizona    0.07163341 1.4788032  0.9989801  1.042878388
# Arkansas   0.23234938 0.2308680 -1.0735927 -0.184916602
# California 0.27826823 1.2628144  1.7589234  2.067820292
# Colorado   0.02571456 0.3988593  0.8608085  1.864967207





  (1) 군집별 변수별 중심 좌표 (Center Points by Clusters)


표준화한 USArrests 데이터셋에 대해 k-means 의 군집개수 k=4 로 해서 군집분석을 하고, 4개의 군집에 대해 해석(interpretation, profiling)을 해보겠습니다.


군집분석 결과를 해석하는 가장 쉽고 또 직관적인 방법은 각 군집별로 군집화에 사용했던 변수들의 중심 좌표를 살펴보는 것입니다.


R 의 군집분석 결과에는 군집별 중심좌표로서 군집별 변수별 평균('Cluster means') 정보가 군집분석 결과 객체의 "centers" attributes에 계산되어 저장되어 있습니다.



## -- (1) Centers per Clusters
## K-means clustering
set.seed(1004)
kmeans_k4 <- kmeans(USArrests_scaled, centers = 4)


## attributes of k-means clustering results

names(kmeans_k4)
# [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
# [6] "betweenss"    "size"         "iter"         "ifault"



## center points per variables

kmeans_k4$centers
# Murder    Assault   UrbanPop        Rape
# 1 -0.9615407 -1.1066010 -0.9301069 -0.96676331
# 2  0.6950701  1.0394414  0.7226370  1.27693964
# 3  1.4118898  0.8743346 -0.8145211  0.01927104
# 4 -0.4894375 -0.3826001  0.5758298 -0.26165379




그런데 kmeans_k4$centers 로 조회한 4개 각 군집의 변수별 중심 좌표 (평균) 은 여기서는 표준화한 후의 데이터에 대한 변수별 평균입니다. 표준화하기 전의 원래 데이터의 군집별 변수별 중심 좌표 (평균)을 알고 싶으면, 아래의 예시처럼 원래의 데이터에 군집화 결과 변수를 추가해주고(미국 주 이름별로 이미 정렬이 된 상태이기 때문에 merge가 아니라 그냥 칼럼을 추가해주었습니다.), 각 군집별 변수별 평균을 구해주면 됩니다.


## add 'cluster' to the original dataset

USArrests$cluster <- kmeans_k4$cluster
head(USArrests)

# Murder Assault UrbanPop Rape cluster
# Alabama      13.2     236       58 21.2       3
# Alaska       10.0     263       48 44.5       2
# Arizona       8.1     294       80 31.0       2
# Arkansas      8.8     190       50 19.5       3
# California    9.0     276       91 40.6       2
# Colorado      7.9     204       78 38.7       2


library(dplyr)
USArrests %>%
  group_by(cluster) %>%
  summarise(murder = mean(Murder),
            assault = mean(Assault),
            urbanpop = mean(UrbanPop),
            rape = mean(Rape))


# # A tibble: 4 x 5
# cluster murder assault urbanpop  rape
# <fct>    <dbl>   <dbl>    <dbl> <dbl>
#   1 1         3.6     78.5     52.1  12.2
# 2 2        10.8    257.      76    33.2
# 3 3        13.9    244.      53.8  21.4
# 4 4         5.66   139.      73.9  18.8





  (2) 군집별 변수별 평행 좌표 그림 (Parallel Coordinates Plot by Clusters)


다변량 데이터셋으로 군집분석을 했을 때 다수 변수들에 대해 관측치 개개의 값들이 군집별로 어떻게 다른지를 보려면 평행 좌표 그림을 사용할 수 있습니다.


GGally 패키지의 ggparcoord() 함수를 이용해서 ggplot2 기반의 군집별 변수별 평행좌표그림 (parallel coordinates plot)을 그려보겠습니다.


표준화하기 전의 원본 데이터를 사용하고, scale = "std" 를 해주면 알아서 각 변수들을 표준화해줍니다.

(혹은 표준화한 데이터를 바로 사용해도 됩니다).


단, 관측치 개수가 너무 많으면 하나의 평행좌표그림에 모든 관측치를 표현할 경우 서로 겹쳐보여서 군집 특성을 파악하는 것이 힘들 수도 있습니다.


ggplotly 패키지의 ggplotly() 함수를 사용하면 interactive plot 을 그려서 군집별로 하이라이트해서 좀더 수월하게 그래프를 볼 수도 있습니다. (저는 R 4.02 버전을 쓰고 있는데요, 이 버전에서는 ggplotly 가 지원이 안된다고 나오네요 -_-;)



## Parallel Coordinates Plot
install.packages("GGally")
library(GGally)

USArrests$cluster <- as.factor(USArrests$cluster)

p <- ggparcoord(data = USArrests,
                columns = c(1:4),
                groupColumn = "cluster",
                scale = "std") +
  labs(x = "Violent Crime Rates by US State",
       y = "value in scaled",
       title = "Parallel Coordinates Plot by Cluster")

p




## Interactive plot using ggplotly

install.packages("ggplotly")
library(ggplotly)
ggplotly(p)

 




  (3) (차원축소 후) 군집별 산점도 (Scatter Plot by Clusters using Reduced Dimension)


다변량 데이터셋으로 분할적 군집분석(partitioning clustering)한 결과를 2차원의 평면에 군집별로 색깔과 모양을 달리해서 산점도로 표현을 할 수 있다면 군집별 특성을 이해하는데 도움이 될 것입니다.


다변량 변수를 2차원으로 차원축소하는데 요인분석(factor analysis), 주성분분석(principal component analysis, PCA) 등을 사용합니다.


k-means 군집분석한 결과를 R의 Factoextra 패키지의 fviz_cluster() 함수를 사용하면 주성분분석(PCA) 으로 다변량을 2차원으로 축소해주고, 이를 군집별로 색깔과 모양을 달리하여 R ggplot2 기반의 세련된 시각화를 해줍니다.


아래 예의 경우 Dim1 (62%), Dim2 (24.7%) 라고 되어있는데요, 이는 전체 분산 중 가로 축 Dim1 이 62%를 설명하고, 세로 축 Dim2 가 24.7% 를 차지한다는 뜻입니다. USArrests 데이터셋의 경우 '살인(murder)', '폭행(assault)', '강간(rape)'의 3개 변수가 "범죄"와 관련이 있어서 Dim1에 의해 많이 설명이 되고, 나머지 변수인 '도시인구(UrbanPop)'가 Dim2에 의해 설명이 되겠네요.

(* 주성분분석 참조 : https://rfriend.tistory.com/61 )



## fviz_silhouette:Visualize Silhouette Information from Clustering
install.packages("factoextra")
library(factoextra)


# Visualize kmeans clustering
fviz_cluster(kmeans_k4, USArrests_scaled, ellipse.type = "norm")+
  theme_minimal()




[ R factoextra package Reference ]

* https://rpkgs.datanovia.com/factoextra/index.html

* https://cran.r-project.org/web/packages/factoextra/factoextra.pdf



혹은 다변량 데이터셋에서 군집을 구분해서 잘 설명해줄 수 있는 대표적인 변수 2개만 선택해서 ggplot2로 직접 2차원 산점도를 그릴 수도 있습니다.

이번 USArrests 데이터셋의 경우 '살인(murder)', '폭행(assault)', '강간(rape)'의 3개 변수가 "범죄"와 관련이 있으므로 이중에서 '살인(murder)' 변수를 하나 뽑고, 나머지 변수인 '도시인구(UrbanPop)'를 나머지 하나로 선택해서 2차원 산점도를 그려보겠습니다.


## Scatter plot by Murder and UrbanPop by clusters
library(ggplot2)
library(repr)
options(repr.plot.width=12, repr.plot.height=12)


set.seed(1004)
km_4 <- kmeans(USArrests_scaled, centers = 4)


cluster_num <- as.factor(km_4$cluster)
city_name <- rownames(USArrests_scaled)

ggplot(data=USArrests_scaled, aes(x=Murder, y=UrbanPop, colour=cluster_num)) +
  geom_point(shape=19, size=4) +
  ggtitle("Scatter Plot of USArrests") +
  theme(plot.title = element_text(size = 20, face = "bold")) +
  annotate("text", x = USArrests_scaled$Murder, y = USArrests_scaled$UrbanPop+0.1,
           label=city_name, size = 5, color="gray") +
  annotate("point", x = km_4$centers[1,1], y = km_4$centers[1,3], size = 6, color = "black") +
  annotate("point", x = km_4$centers[2,1], y = km_4$centers[2,3], size = 6, color = "black") +
  annotate("point", x = km_4$centers[3,1], y = km_4$centers[3,3], size = 6, color = "black") +
  annotate("point", x = km_4$centers[4,1], y = km_4$centers[4,3], size = 6, color = "black") +
  annotate("text", x = km_4$centers[1,1], y = km_4$centers[1,3]+0.2, label="cluster 1", size = 8) +
  annotate("text", x = km_4$centers[2,1], y = km_4$centers[2,3]+0.2, label="cluster 2", size = 8) +
  annotate("text", x = km_4$centers[3,1], y = km_4$centers[3,3]+0.2, label="cluster 3", size = 8) +
  annotate("text", x = km_4$centers[4,1], y = km_4$centers[4,3]+0.2, label="cluster 4", size = 8)




이상으로 위의 (1) 군집별 중심 좌표 (평균), (2) 군집별 다변량 변수별 평행 좌표 그림, (3) (차원 축소 후) 군집별 산점도를 통해 군집 1 ~ 4 번까지의 특성을 파악해 본 결과,


* 군집 1 : 범죄(살인, 폭행, 강간)도 낮고, 도시인구수도 낮은 도시군 (예: Vermont, Wisconsin 등)

* 군집 2 : 범죄도 높고, 도시인구수도 높은 도시군 (예: New York, Flolida 등)

* 군집 3 : 범죄는 높고, 도시인구수는 낮은 도시군 (예: Mississippi, South Carolina 등)

* 군집 4 : 범죄는 낮고, 도시인구수는 높은 도시군 (예: Utah, Massachusetts 등)


으로 해석할 수 있겠네요.

이번 포스팅이 많은 도움이 되었기를 바랍니다.
행복한 데이터 과학자 되세요. :-)


728x90
반응형
Posted by Rfriend
,