如何优雅创建含第三个变量的点间成对距离data.frame?
优化方案:更简洁的成对距离与Z值提取方法
你可以用tidyverse自连接+过滤的方式实现需求,代码更简洁易读,避免了矩阵索引和多次重复join的繁琐操作:
library(tidyverse) # 原始数据 foo <- data.frame(id = LETTERS[1:5], x = c(3,1,4,1,5), y = c(9,2,6,5,3), z = c(5,8,9,7,9)) # 生成成对组合、计算距离并关联Z值 bar <- foo %>% # 自连接生成所有两两组合,后缀区分两组数据 inner_join(foo, by = character(), suffix = c("_1", "_2")) %>% # 过滤掉重复组合(只保留id_1 < id_2的非重复对) filter(id_1 < id_2) %>% # 直接计算欧氏距离 mutate(dist = sqrt((x_1 - x_2)^2 + (y_1 - y_2)^2)) %>% # 保留需要的列 select(id_1, id_2, dist, z_1, z_2) print(bar)
方案优势:
- 无需先构建距离矩阵再索引,一步完成组合生成、距离计算和Z值关联
- 代码逻辑连贯,符合tidy数据处理风格,可读性更强
- 避免了原代码中两次
inner_join的重复操作,效率更高
如果你习惯用dist函数计算距离,也可以搭配broom::tidy来简化矩阵转数据框的步骤:
library(broom) library(dplyr) foo_dist <- dist(foo[, c("x", "y")], diag = FALSE, upper = FALSE) %>% tidy() %>% left_join(foo, by = c("item1" = "id")) %>% left_join(foo, by = c("item2" = "id"), suffix = c("_1", "_2")) %>% rename(id_1 = item1, id_2 = item2) %>% select(id_1, id_2, distance, z_1, z_2) print(foo_dist)
这个方案利用broom::tidy直接将dist对象转换为整洁的数据框,再一次性关联两组Z值,也比原代码更简洁。
内容的提问来源于stack exchange,提问作者user111024
相关产品推荐
相关产品推荐

