# 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
 # 데이터 준비 (iris 데이터에서 품종 제거)
data(iris)
#glimpse(iris)
df <- iririsdf <- iris[, -5]  # 군집용 수치형 데이터만 사용

# K-평균 군집 수행 (예: K=3)
set.seed(123)
km_result <- kmeans(df, centers = 3, nstart = 25)

# K-평균 알고리즘은 초기 중심점(centroid)을 무작위로 선택
# 초기 위치에 따라 결과가 좋기도 하고, 나쁘기도 합니다.
 # 25번 서로 다른 초기화 시도
# 그 중에서 가장 좋은(오차 제곱합 SSE가 가장 낮은) 결과를 선택합니다.
 # 군집 결과 확인
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
#glimpse(iris)
#iris %>% count(Species)

# 이 코드를 실행하면:
# 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_result <- kmeans(df, centers = 2, nstart = 25)
 sil <- silhouette(km_result$cluster, dist(df))
 # 실루엣 결과 시각화
fviz_silhouette(sil)
##   cluster size ave.sil.width
## 1       1   53          0.77
## 2       2   97          0.63

 # 실습 
# datarium 패키지에 포함된 예제 데이터
#변수명       
#설명
#YouTube    
#Facebook    
#Newspaper  
#YouTube 광고비 (단위: 1000달러)
# Facebook 광고비 (단위: 1000달러)
#신문광고비 (단위: 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)
## 
## 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
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)

 # 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
 # 3개의 군집이 모두:
 # 타원형 분포
# 같은 크기(volume), 같은 모양(shape), 같은 방향(orientation)
 # → 군집이 비슷한 구조로 형성되었음을 의미
# 실용적 해석 예시 (가능한 가설)
 #군집 1: 짧은 분출 + 짧은 대기 (아주 빠른 작동)
 #군집 2: 중간 분출 + 대기 (중간 유형)
 #군집 3: 긴 분출 + 긴 대기 (일반적인 작동 패턴)
 #(→ faithful은 사실 2개 혼합구조로 알려졌지만, 3개로도 충분히 유의미한 구분 가능)
 # 로그 가능도는 클수록(=덜 음수일수록) 좋습니다.
 # 로그 가능도 최대 도달: EM 알고리즘이 더 이상 개선 불필요하다고 판단 → 수렴 완료
# 4. 군집 결과 시각화
plot(model, what = "classification")  # 각 관측치를 군집별 색상으로