rm(list = ls())
# 실루엣 계수
# 필요한 패키지 설치
# install.packages("cluster")
# install.packages("factoextra")
# 패키지 로드
library(cluster)
library(factoextra)
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# 데이터 준비 (iris 데이터에서 품종 제거)
data(iris)
df <- iris[, -5] # 군집용 수치형 데이터만 사용
# K-평균 군집 수행 (예: K=3)
set.seed(123)
km_result <- kmeans(df, centers = 3, nstart = 25)
# K-평균 알고리즘은 초기 중심점(centroid)을 무작위로 선택
# 초기 위치에 따라 결과가 좋기도 하고, 나쁘기도 합니다.
# 25번 서로 다른 초기화 시도
# 그 중에서 가장 좋은(오차 제곱합 SSE가 가장 낮은) 결과를 선택합니다.
# nstart의 값을 달리하면 다른 결과가 나올 수 있음
# 군집 결과 확인
km_result$cluster
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [75] 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 3 3 3 3 2 3 3 3 3
## [112] 3 3 2 2 3 3 3 3 2 3 2 3 2 3 3 2 2 3 3 3 3 3 2 3 3 3 3 2 3 3 3 2 3 3 3 2 3
## [149] 3 2
iris %>% count(Species)
## Species n
## 1 setosa 50
## 2 versicolor 50
## 3 virginica 50
# 이 코드를 실행하면:
# df 데이터셋의 각 관측치(행)가
# 군집 번호 1, 2, 3 중 어디에 속하는지
# 그 결과가 벡터 형태로 출력됩니다.
# 실루엣 계수 계산 및 시각화
# 실루엣 계산을 위해 군집 결과를 기반으로 silhouette() 함수 사용
sil <- silhouette(km_result$cluster, dist(df))
# 실루엣 결과 시각화
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 50 0.80
## 2 2 62 0.42
## 3 3 38 0.45

# 평균 실루엣 계수 (Average silhouette width): 0.55
# 0.5 이상 → 꽤 잘 분리된 군집
# 색상 (빨강, 초록, 파랑) : 군집 번호 (Cluster 1, 2, 3)
# 붉은 점선: 전체 데이터의 평균 실루엣 계수 (0.55) 기준선
# Cluster 3 (파랑)
# 파란색 군집은 setosa로 의사결정나무에서도 쉽게 구분되는 품종이었음
# 대부분 실루엣 계수가 0.6~0.8 이상
# ▶ 가장 응집력 좋고, 잘 분리된 군집으로 판단
# 결론
# 군집 수(K=3)는 꽤 타당하지만, 더 나은 K가 있을 수도 있음
# k=2일때 실루엣 계수를 계산하시오?
# K-평균 군집 수행 (예: K=3)
set.seed(123)
km_result1 <- kmeans(df, centers = 2, nstart = 25)
sil <- silhouette(km_result1$cluster, dist(df))
# 실루엣 결과 시각화
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 53 0.77
## 2 2 97 0.63

# 결론 -> 군집 수 K는 2개로 하는게 3개로 하는 것보다 더 좋을 수 있다.
# 실습
# datarium 패키지에포함된 예제 데이터
# 변수명 설명
# Youtube Youtube 광고비(단위 : 1000달러)
# Facebook Facebook 광고비(단위 : 1000달러)
# Newspaper Newspaper 광고비(단위 : 1000달러)
# Sales 해당 캠페인의 결과 매출액 (단위: 1000달러)
# 군집 결과가 의미하는 것 (예시)
# Cluster1 : YouTube 비중이 높고, Facebook/신문은 적음 매출(Sales) 평균높음
# -> YouTube 중심 전략이 매우 효과적
# Cluster2 : Facebook 위주, YouTube/신문은 적음 매출(Sales) 낮음
# -> SNS 광고 단독 전략은 효과 미흡
# Cluster3 : 신문광고 비중이 높고 YouTube/Facebook 적음 매출액 중간
# -> 오래된 방식의 전략, 비용 대비 효과 낮음
# marketing 데이터의 군집 분석 결과는 광고 채널 사용 패턴에 따라
# 마케팅 캠페인을 분류하고,
# 각 그룹의 성과를 비교함으로써, 향후 더 효율적인 마케팅
# 전략을 수립하는 근거를 제공
# 패키지 설치 (최초 1회만)
# install.packages("datarium")
# install.packages("factoextra")
# 패키지 로드
library(datarium)
library(factoextra)
# 데이터 불러오기
data("marketing")
df <- marketing
library(dplyr)
glimpse(df)
## Rows: 200
## Columns: 4
## $ youtube <dbl> 276.12, 53.40, 20.64, 181.80, 216.96, 10.44, 69.00, 144.24, …
## $ facebook <dbl> 45.36, 47.16, 55.08, 49.56, 12.96, 58.68, 39.36, 23.52, 2.52…
## $ newspaper <dbl> 83.04, 54.12, 83.16, 70.20, 70.08, 90.00, 28.20, 13.92, 1.20…
## $ sales <dbl> 26.52, 12.48, 11.16, 22.20, 15.48, 8.64, 14.16, 15.84, 5.76,…
# 광고비만 선택 (Sales는 제외)
df_cluster <- df[,c("youtube", "facebook", "newspaper")]
# 정규화 (평균 0, 표준편차 1)
df_scaled <- scale(df_cluster)
set.seed(123) # 재현 가능성 확보
km_result <- kmeans(df_scaled, centers = 3, nstart = 25)
# 군집 결과 확인
km_result$cluster # 각 관측치의 군집 번호
## [1] 1 1 1 1 1 1 3 3 3 2 3 2 1 3 1 1 1 1 3 2 1 2 3 2 3 2 2 2 2 3 2 3 3 2 3 2 2
## [38] 1 3 1 2 1 2 2 3 2 3 2 2 3 2 3 1 1 2 1 3 3 1 2 3 1 2 3 1 3 3 3 2 1 1 3 3 3
## [75] 2 1 3 3 3 3 3 2 3 1 1 1 3 1 1 1 3 3 1 1 3 1 2 2 1 1 2 1 2 2 2 1 3 3 3 2 2
## [112] 2 2 2 1 1 3 3 1 3 1 3 2 3 1 3 1 3 2 3 3 2 3 1 1 3 3 1 3 2 3 1 1 3 3 3 2 1
## [149] 3 3 2 3 2 1 2 3 1 3 1 3 2 1 2 2 3 1 3 2 1 2 3 1 3 2 2 1 2 2 2 2 2 2 3 1 2
## [186] 1 3 2 2 3 3 3 3 2 2 3 3 2 1 2
fviz_cluster(km_result, data = df_scaled,
palette = "jco",
ggtheme = theme_minimal(),
main = "K=3 광고비 기준 K-Means 군집 결과")

# 6. 원본 데이터에 군집 번호 추가
df$Cluster <- as.factor(km_result$cluster)
# 7. dplyr로 군집별 평균 광고비 + 매출 요약
df %>%
group_by(Cluster) %>%
summarise(across(c(youtube, facebook, newspaper, sales),
mean, .names = "avg_{.col}")) %>%
arrange(Cluster)
## # A tibble: 3 × 5
## Cluster avg_youtube avg_facebook avg_newspaper avg_sales
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 198. 45.2 66.3 21.3
## 2 2 264. 22.1 22.4 18.9
## 3 3 83.4 19.1 25.3 11.5
# 실무적 해석
# Cluster 1: YouTube 광고 중심 → 매출도 가장 높음
# Cluster 2: Facebook + Newspaper 혼합 → 중간 매출
# Cluster 3: 신문 위주 전통형 광고 → 가장 낮은 매출
# 실루엣 계수
# 1. 거리 행렬 계산
dist_matrix <- dist(df_scaled)
# 2. 실루엣 객체 계산
library(cluster)
sil <- silhouette(km_result$cluster, dist_matrix)
# 3. 실루엣 시각화
library(factoextra)
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 60 0.26
## 2 2 65 0.31
## 3 3 75 0.33

# 4. 평균 실루엣 계수 출력
mean(sil[, 3]) # 세 번째 열이 실루엣 계수 Si
## [1] 0.3050502
# 엘보우 기법
library(factoextra)
# 엘보우 기법으로 최적 군집 수 찾기
fviz_nbclust(df_scaled, kmeans, method = "wss") +
geom_vline(xintercept = 3, linetype = 2, color = "red") +
labs(title = "엘보우 기업을 통한 최적 군지비 수 찾기(WSS 기준)",
x = "군지비 수 K", y = "군집 내 제곱합(WSS)")

# 혼합분포군집
# 1. 패키지 로드 및 데이터 준비
# install.packages("mclust")
library(mclust)
## Package 'mclust' version 6.1.1
## Type 'citation("mclust")' for citing this R package in publications.
data("faithful")
glimpse(faithful)
## Rows: 272
## Columns: 2
## $ eruptions <dbl> 3.600, 1.800, 3.333, 2.283, 4.533, 2.883, 4.700, 3.600, 1.95…
## $ waiting <dbl> 79, 54, 74, 62, 85, 55, 88, 85, 51, 85, 54, 84, 78, 47, 83, …
# eruptions 분출 시간 (분 단위) –
# Old Faithful 간헐천이 한 번 분출하는 데 걸리는 시간
# waiting 다음 분출까지의 대기 시간 (분 단위) –
# 분출이 끝난 뒤 다음 분출까지 기다리는 시간
# 데이터 로드
data(faithful)
# 산점도 시각화
plot(faithful,
main = "Old Faithful 간헐천 분출 유형 시각화",
xlab = "분출 시간 (minutes)",
ylab = "대기 시간 (minutes)",
pch = 19,
col = "steelblue")

# 좌하단: 짧은 분출, 짧은 대기
# 우상단: 긴 분출, 긴 대기
# 두 개의 뚜렷한 패턴(=혼합 분포 구조)이 시각적으로 확인
# -> 혼합분포 군집
# 의미 간헐천 활동이 약한 경우-> 다음도 짧을 가능성 높음
# 예측 긴 분출 후 → 다음도 긴 대기 예상
# ➡ 운영·예측·관광 안내 등 실용적 응용 가능
# 2. 혼합모형 군집(Gaussian Mixture Model) 수행
model <- Mclust(faithful)
# 혼합분포군집(Mixture Model Clustering)을 실행하는 핵심 명령어
# 3. 모델 요약
summary(model)
## ----------------------------------------------------
## Gaussian finite mixture model fitted by EM algorithm
## ----------------------------------------------------
##
## Mclust EEE (ellipsoidal, equal volume, shape and orientation) model with 3
## components:
##
## log-likelihood n df BIC ICL
## -1126.326 272 11 -2314.316 -2357.824
##
## Clustering table:
## 1 2 3
## 40 97 135
# mclust EEE (ellipsoidal, equal volume, shape and orientation) model with 3 components:
# 3개의 군집이 모두 : 타원형 분포
# 같은 크기(volume), 같은 모양(shape), 같은 방향(orientation)
# → 군집이 비슷한 구조로 형성되었음을 의미
# 실용적 해석 예시 (가능한 가설)
# 군집 1: 짧은 분출 + 짧은 대기 (아주 빠른 작동)
# 군집 2: 중간 분출 + 대기 (중간 유형)
# 군집 3: 긴 분출 + 긴 대기 (일반적인 작동 패턴)
# (→ faithful은 사실 2개 혼합구조로 알려졌지만, 3개로도 충분히 유의미한 구분 가능)
# 로그 가능도는 클수록(=덜 음수일수록) 좋습니다.
# 로그 가능도 최대 도달: EM 알고리즘이 더 이상 개선 불필요하다고 판단 → 수렴 완료
# 4. 군집 결과 시각화
plot(model, what = "classification") # 각 관측치를 군집별 색상으로
