如何生成组间成对共享观测计数矩阵并实现可视化?
解决方案:生成组间共享观测计数矩阵并可视化
针对你的需求,我会分步骤用dplyr/tidyr和Base R两种方式实现,最后用热力图展示结果:
第一步:准备示例数据
先把你提供的数据转换成可测试的格式:
library(dplyr) library(tidyr) library(ggplot2) # 你的原始数据 df <- tibble( Animal = c("Cat", "Cat", "Cat", "Bat", "Bat", "Bat", "Bat", "Mouse", "Mouse", "Mouse", "Deer", "Deer", "Deer"), Sector = c(1,1,2,2,3,3,3,1,2,2,2,2,2), Time = c("Night", "Night", "Night", "Night", "Night", "Night", "Night", "Day", "Night", "Night", "Day", "Night", "Night"), Group = c("A", "B", "B", "A", "C", "A", "B", "B", "A", "B", "A", "B", "C") )
方法1:用dplyr实现
步骤1:标记每个观测所属的组
先把Animal+Sector+Time作为唯一观测标识,收集每个观测对应的所有组:
obs_groups <- df %>% distinct(Animal, Sector, Time, Group) %>% # 确保组内观测不重复(题目已说明,这里做双重保障) group_by(Animal, Sector, Time) %>% summarise(groups = list(Group), .groups = "drop")
步骤2:生成所有组对并计算共享数
先提取所有唯一组,再生成所有可能的组对,最后统计每对组的共享观测数量:
# 获取所有唯一组 all_groups <- unique(df$Group) # 生成所有组的笛卡尔积(包括组自身配对) group_pairs <- expand.grid(Group1 = all_groups, Group2 = all_groups, stringsAsFactors = FALSE) # 计算每对组的共享观测数 shared_counts <- group_pairs %>% rowwise() %>% mutate( count = sum(obs_groups$groups %>% purrr::map_lgl(~ all(c(Group1, Group2) %in% .x))) ) %>% ungroup()
步骤3:转换为矩阵格式
如果需要得到矩阵形式的结果:
shared_matrix <- shared_counts %>% pivot_wider(names_from = Group2, values_from = count) %>% column_to_rownames("Group1") %>% as.matrix() # 输出结果 shared_matrix #> A B C #> A 4 3 1 #> B 3 5 2 #> C 1 2 2
注:矩阵中A-A的值是组A的总观测数,A-B是两组共享的3个观测,和你的示例完全一致。
方法2:用Base R实现(更高效)
利用矩阵乘法的特性,一步得到组间共享计数矩阵,适合大数据量:
# 1. 生成观测的唯一标识 df$obs_id <- with(df, paste(Animal, Sector, Time, sep = "_")) # 2. 创建交叉表:行=观测,列=组,值为1表示该观测属于对应组 cross_tab <- table(df$obs_id, df$Group) cross_tab <- (cross_tab > 0) * 1 # 转换为二进制(消除组内重复的影响) # 3. 矩阵乘法计算共享数:转置交叉表 × 交叉表,得到组间共享计数矩阵 shared_matrix_base <- t(cross_tab) %*% cross_tab # 输出结果 shared_matrix_base #> A B C #> A 4 3 1 #> B 3 5 2 #> C 1 2 2
这个方法的核心逻辑是:两组的共享观测数 = 两组观测向量的点积,矩阵乘法会自动完成所有组对的计算,效率很高。
可视化:带0值的热力图
用ggplot2绘制热力图,清晰展示所有组对的共享计数(包括0值):
shared_counts %>% ggplot(aes(x = Group1, y = Group2, fill = count)) + geom_tile(color = "white") + # 白色边框区分tile geom_text(aes(label = count), color = "black", size = 5) + # 显示计数数值 scale_fill_gradient(low = "white", high = "steelblue") + # 颜色渐变 labs(title = "Group Shared Observations Count", x = "Group", y = "Group") + theme_minimal()
如果想用Base R的热力图工具,可以用gplots包的heatmap.2:
library(gplots) heatmap.2(shared_matrix_base, cellnote = shared_matrix_base, # 显示每个tile的计数 notecol = "black", col = colorRampPalette(c("white", "steelblue"))(100), trace = "none", # 关闭不必要的线条 dendrogram = "none", # 不需要聚类树 main = "Group Shared Observations Count", xlab = "Group", ylab = "Group")
为什么你的之前代码不符合需求?
你之前的代码是筛选出被至少两个组共享的观测,然后直接绘制观测×组的交叉表,这展示的是哪些观测被哪些组共享,而不是组与组之间共享了多少观测。我们的方案是先计算组对的共享计数,再可视化这个计数矩阵,完全匹配你的需求。
内容的提问来源于stack exchange,提问作者user964689
相关产品推荐
相关产品推荐

