当前位置: 首页 > news >正文

层次聚类R复现

在模型建立的过程中,我们一般都要把许多X变量进行聚类,进而分析模型的实际意义。

其中大概可分为3类

1. K-Means聚类

2. 层次聚类

3. DBSCAN聚类

在这里,我们以层次聚类为例子进行分享

一 安装所需包

#================================================================
# R内置数据集变量聚类分析示例
# 目的:通过层次聚类识别冗余变量并从每个聚类选择代表性变量
#================================================================

# 安装并加载所需包
if(!require(cluster)) install.packages("cluster")
if(!require(corrplot)) install.packages("corrplot")
if(!require(dendextend)) install.packages("dendextend")
if(!require(ggplot2)) install.packages("ggplot2")
if(!require(dplyr)) install.packages("dplyr")
if(!require(factoextra)) install.packages("factoextra")
if(!require(MASS)) install.packages("MASS")  # 包含Boston数据集

library(cluster)# 聚类分析
library(corrplot)# 可视化相关性矩阵
library(dendextend)# 树状图可视化
library(ggplot2)# 数据可视化
library(dplyr)# 数据处理
library(factoextra)# 最佳聚类数量选择
library(MASS)# 包含Boston数据集

二 载入和介绍数据包

#================================================================
# 1. 数据准备
#================================================================

# 加载数据 (Boston数据集包含波士顿郊区房价及相关特征)
data(Boston)

# 查看数据结构
str(Boston)

# 清理数据 (移除缺失值)
boston_clean <- na.omit(Boston)

# 数据简单描述
summary(boston_clean)

# Boston数据集变量解释
# crim: 犯罪率 per capita by town
# zn: 住宅用地比例 for lots over 25,000 sq. ft.
# indus: 非零售业务用地比例 per town
# chas: Charles River(贫民区) dummy variable (= 1 if tract bounds river; 0 otherwise)
# nox: 氮氧化物浓度 (parts per 10 million)
# rm: 每个住宅的平均房间数
# age: 1940年之前建成的自住单位比例
# dis: 距离五个波士顿就业中心的加权距离
# rad: 距离高速公路的便利指数
# tax: 每 10,000 美元的全值财产税率
# ptratio: 每个镇的师生比例
# black: 1000(Bk - 0.63)^2,其中 Bk 是每个镇的黑人比例
# lstat: 低收入人口比例
# medv: 自住房的中位数价值 (以千美元计)

使用较为经典的Boston数据包,包含波士顿房价等因素

如图所示

三 变量相关性分析

#================================================================
# 2. 相关性分析
#================================================================

# 计算变量间的相关性矩阵
corr_matrix <- cor(boston_clean, use = "pairwise.complete.obs")

# 可视化相关性矩阵
corrplot(corr_matrix, 
         method = "color", 
         type = "upper", 
         order = "hclust", 
         tl.col = "black", 
         tl.cex = 0.7,
         title = "波士顿房价数据变量相关性矩阵",
         mar = c(0,0,2,0))

如图,得到了不同变量之间的相关性,我们的目的就是基于这些相关性,将变量分为不同的组

四 层次聚类分析

#================================================================
# 3. 层次聚类分析
#================================================================

# 计算变量间的距离矩阵 (基于1-|相关系数|)
dist_matrix <- as.dist(1 - abs(corr_matrix))

# 应用层次聚类
hc <- hclust(dist_matrix, method = "complete")

# 转换为树状图对象
dend <- as.dendrogram(hc)

# 可视化树状图
par(mar = c(5, 4, 4, 10)) #控制绘图边距
plot(dend, 
     main = "波士顿房价数据变量层次聚类",
     ylab = "高度",
     horiz = TRUE)

可以看到,我们依据变量之间的相关性,绘制出树状图。但是我们如何确定最佳的聚类数呢?这就引出了不同的筛选标准

五 最佳聚类数筛选标准 手肘法则&AIC判别

手肘法则

 手肘法则:WSS(簇内方差平方和)关于聚类数k的曲线,选择梯度发生变化的那个点,如图所示

#================================================================
# 4. 确定最佳聚类数量
#================================================================

# 使用肘部法则确定最佳聚类数量
wss <- fviz_nbclust(t(as.matrix(boston_clean)), 
                   FUNcluster = hcut,
                   method = "wss", 
                   k.max = 10)
print(wss)

在这里可以把k选作2、也可以选为3

AIC判别法则

AIC判别:AIC(Akaike Information Criterion)即赤池信息准则,其计算公式为:AIC = 2k - 2ln(L)

K:模型内自由参数的数量

ln(L):似然函数的自然对数

AIC越小,说明效果越好

# 测试不同聚类数量的AIC
k_max <- 10
aic_values <- numeric(k_max)

for(k in 1:k_max) {
  clusters <- cutree(hc, k = k)
  
  # 计算每个聚类的组内方差
  wss_cluster <- 0
  for(i in 1:k) {
    if(sum(clusters == i) > 0) {
      cluster_vars <- names(clusters[clusters == i])
      if(length(cluster_vars) > 1) {
        cluster_data <- boston_clean[, cluster_vars]
        wss_cluster <- wss_cluster + sum(scale(cluster_data, center = TRUE, scale = FALSE)^2)
      }
    }
  }
  
  # AIC = WSS + 2 * k * p (p是参数数量,这里简化为变量数)
  aic_values[k] <- wss_cluster + 2 * k * ncol(boston_clean)
}

# 绘制AIC图
# 使用ggplot2创建更美观的AIC图
aic_df <- data.frame(k = 1:k_max, aic = aic_values)
min_aic_k <- which.min(aic_values)

ggplot(aic_df, aes(x = k, y = aic)) +
    geom_line(color = "#3366CC", linewidth = 1) +
    geom_point(color = "#3366CC", size = 3) +
    geom_point(data = aic_df[min_aic_k, ], aes(x = k, y = aic), 
                         color = "#CC3333", size = 4, shape = 18) +
    geom_text(data = aic_df[min_aic_k, ], 
                        aes(label = paste("最小AIC:", round(aic, 1), "(k=", k, ")")),
                        hjust = 0.5, vjust = -1, color = "#CC3333") +
    labs(title = "基于AIC确定最佳聚类数量",
             subtitle = "较低的AIC值表示更好的模型平衡度",
             x = "聚类数量 (k)",
             y = "AIC 值") +
    scale_x_continuous(breaks = 1:k_max) +
    theme_minimal() +
    theme(
        plot.title = element_text(face = "bold", size = 14),
        plot.subtitle = element_text(size = 11, color = "darkgrey"),
        axis.title = element_text(face = "bold"),
        panel.grid.minor = element_blank(),
        panel.grid.major = element_line(color = "gray90"),
        panel.border = element_rect(fill = NA, color = "gray80")
    )

# 基于肘部法则和AIC分析确定最佳聚类数
# 观察肘部法则图形和AIC图后手动设置
# 使用factoextra多种方法确定最佳聚类数量

在这里,可将k选为7

optimal_k_elbow <- 2  # 这里选择3个聚类作为示例
optimal_k_AIC <- 7  # 这里选择4个聚类作为示例

对手肘法则的最佳聚类结果进行展示

#================================================================
# 5A. 基于肘部法则的聚类划分
#================================================================

# 基于肘部法则切割树状图
clusters_elbow <- cutree(hc, k = optimal_k_elbow)

# 为每个聚类着色
dend_colored_elbow <- dend %>%
  set("branches_k_color", k = optimal_k_elbow) %>%
  set("branches_lwd", 2)

# 可视化聚类结果
par(mar = c(5, 4, 4, 10))
plot(dend_colored_elbow, 
     main = paste0("肘部法则聚类结果 (k = ", optimal_k_elbow, ")"),
     horiz = TRUE)

# 查看每个聚类的变量
cluster_vars_elbow <- list()
for(i in 1:optimal_k_elbow) {
  cluster_vars_elbow[[i]] <- names(clusters_elbow[clusters_elbow == i])
  cat("\n肘部法则聚类", i, "包含的变量:\n")
  print(cluster_vars_elbow[[i]])
}

对AIC判别法则的最佳聚类结果进行展示

#================================================================
# 5B. 基于AIC的聚类划分
#================================================================

# 基于AIC切割树状图
clusters_aic <- cutree(hc, k = optimal_k_AIC)

# 为每个聚类着色
dend_colored_aic <- dend %>%
  set("branches_k_color", k = optimal_k_AIC) %>%
  set("branches_lwd", 2)

# 可视化聚类结果
par(mar = c(5, 4, 4, 10))
plot(dend_colored_aic, 
     main = paste0("AIC聚类结果 (k = ", optimal_k_AIC, ")"),
     horiz = TRUE)

# 查看每个聚类的变量
cluster_vars_aic <- list()
for(i in 1:optimal_k_AIC) {
  cluster_vars_aic[[i]] <- names(clusters_aic[clusters_aic == i])
  cat("\nAIC聚类", i, "包含的变量:\n")
  print(cluster_vars_aic[[i]])
}

具体两种法则如何选择,可以分别进行,然后通过最后展示结果进行人工选择

相关文章:

  • 解释器模式
  • 通俗易懂的分类算法之K近邻详解
  • Golang学习笔记_41——观察者模式
  • 依赖注入与控制反转什么关系
  • 删除链表的倒数第N个节点 力扣19
  • 【Linux笔记】基础IO(上)
  • 【MySQL】第十二弹---表连接详解:从内连接到外连接
  • Spark的数据本地性是在哪个环节确定的
  • MongoDB分片集群
  • 第三阶段-产品方面的技术疑难
  • GMAC网络延时性能优化
  • office集成deepseek插件,office集成deepseek教程(附安装包)
  • 人工智能训练物理模拟器 MuJoCo入门教程 常用函数介绍及测试用例
  • 基于 DataEase 的企业数据分析实践
  • centos7操作系统下安装docker,及查看docker进程是否启动
  • 如何用 DeepSeek 和 ChatGPT 打造智能搜索与问答体验
  • 残差收缩模块
  • 大数据测试中,数据仓库表类型有哪些?
  • 深度学习中关于超参数的解释
  • vm+centos虚拟机
  • 面对非专业人士,科学家该如何提供建议
  • 会计江湖|年报披露关注什么:独董给出的“信号”
  • 夜读丨喜马拉雅山的背夫
  • 14岁女生瞒报年龄文身后洗不掉,法院判店铺承担六成责任
  • 早期投资人蜂巧资本清仓泡泡玛特套现超22亿港元,称基金即将到期
  • 外卖员投资失败负疚离家流浪,经民警劝回后泣不成声给父母下跪