对于数据框中的每个点(x,y),我想计算从该点到数据框中没有相同“组”标签的所有其他点的欧氏距离之和。这是我想要实现的hacky for-loop版本:
# some fake data
d <- data.frame(group=rep(c('a','b','c'),each=3), x=sample(1:9), y=sample(1:9), z=NA)
for (i in 1:nrow(d)) {
d2 <- subset(d,group!=d$group[i])
d$z[i] <- sum(sqrt((d$x[i]-d2$x)^2 + (d$y[i]-d2$y)^2))
}
例如,点a1的期望值应该是从a1到b1,b2,b3,c1,c2,c3中的每一个的距离之和,但不包括距离a1-a2或a1-a3。有没有矢量化的方法来实现这一目标?我确信这是一个明显的解决方案......我尝试了by()
和apply()
的各种配置,但似乎无法找到答案。
答案 0 :(得分:3)
有一种非常好的方法可以有效地解决这个问题:预先计算所有距离并对它们进行子集而不是点,以避免重复相同的计算。
dists <- as.matrix(dist(d[2:3]))
d$z <- sapply(seq(d$group), function(i) sum(dists[i, !d$group %in% d$group[i]]))
答案 1 :(得分:1)
对Backlin的解决方案与循环进行基准测试的结果(使样本数据更大一些以扩大差异):
d <- data.frame(group=rep(letters[1:10],each=100), x=sample(1:1000), y=sample(1:1000), z=NA)
loopMethod <- function(d) {
for (i in 1:nrow(d)) {
d2 <- subset(d,group!=d$group[i])
d$z[i] <- sum(sqrt((d$x[i]-d2$x)^2 + (d$y[i]-d2$y)^2))
}
}
backlinMethod <- function(d) {
dists <- as.matrix(dist(d[2:3]))
d$z <- sapply(seq(d$group), function(i) sum(dists[i, !d$group %in% d$group[i]]))
}
system.time(loopMethod(d))
user system elapsed
1.020 0.004 1.021
system.time(backlinMethod(d))
user system elapsed
0.472 0.052 0.525