层次聚类R复现

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

其中大概可分为3类

  1. K-Means聚类

  2. 层次聚类

  3. DBSCAN聚类

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

一 安装所需包

R 复制代码
#================================================================
# 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数据集

二 载入和介绍数据包

R 复制代码
#================================================================
# 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数据包,包含波士顿房价等因素

如图所示

三 变量相关性分析

R 复制代码
#================================================================
# 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))

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

四 层次聚类分析

R 复制代码
#================================================================
# 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的曲线,选择梯度发生变化的那个点,如图所示

R 复制代码
#================================================================
# 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)即赤池信息准则,其计算公式为:

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

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

AIC越小,说明效果越好

R 复制代码
# 测试不同聚类数量的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

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

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

R 复制代码
#================================================================
# 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判别法则的最佳聚类结果进行展示

R 复制代码
#================================================================
# 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]])
}

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

相关推荐
找方案5 小时前
AI视频生成对决:Sora vs 可灵 vs Veo,谁能定义未来
人工智能·机器学习·音视频
面朝大海,春不暖,花不开11 小时前
Buat New Trenches, Kalian Bisa Baca Panduan Meta Ini
人工智能·机器学习
VL——MOESR13 小时前
【具身智能】Cosmos Policy论文阅读随笔
论文阅读·人工智能·机器学习·具身智能·cosmospolicy
haon112214 小时前
树模型在信贷风控怎么用——从决策树到 XGBoost
大数据·人工智能·算法·决策树·机器学习·数据挖掘
阳明山水14 小时前
从相关到因果:预测科学的因果转向与可识别性挑战
人工智能·深度学习·算法·机器学习·架构
宣宣猪的小花园.14 小时前
【嵌入式】故障与降级:看门狗、保护机制和工程可靠性的底线
开发语言·人工智能·嵌入式硬件·机器学习
pjj1985414 小时前
深度学习-训练,评估与数据增强
人工智能·深度学习·机器学习
满怀冰雪14 小时前
25-迁移学习入门:加载预训练模型并微调
人工智能·python·机器学习·迁移学习·paddle
派大_星16 小时前
PyTorch CNN图片分类与数据增强实践
人工智能·深度学习·机器学习
海盗123416 小时前
微软技术日报 2026-09-10:Project Zenith 开发者设备亮相,.NET 11 RC1 可投产
microsoft·r语言·.net