R:组中对象之间的欧几里德距离

时间:2014-08-05 09:25:06

标签: r euclidean-distance

我想基于两个标识符创建一个具有相似性的矩阵,请考虑以下矩阵:

x1  <- c(2,2,2,3,1,2,4,6,4)
y1  <- c(5,4,3,3,4,2,1,6,3)
x2  <- c(8,2,7,3,1,2,2,2,6)
y2  <- c(1,3,3,3,1,2,4,3,8)
x3  <- c(4,4,1,2,4,6,3,2,9)
y3  <- c(1,2,3,3,1,2,4,6,1)
id1 <- c("a","a","a","a","b","b","b","b","b")
id2 <- c(2002,2002,2003,2003,2002,2002,2003,2003,2003)
dat <- data.frame(x1,y1,x2,y2,x3,y3,id1,id2)

对于标有id1id2的群组,我想在数据集中的行之间创建欧几里德距离(sqrt((x1a-x1b)^2+(y1a-y1b)^2 + ... + (y3a-y3b)^2))。在最好的情况下,会有一个新变量指示每条线与相同id1id2的每条线的距离。请注意,每组中可以有不同数量的成员,例如在2003年的b组中有三种情况。 任何建议都会很棒!!!

2 个答案:

答案 0 :(得分:0)

我认为首先要区分想要计算距离的线是个好主意。例如,对于id1 == b和id2 == 2003,您有3行,并且您想要计算3个不同的距离(每个可能的对之间)。因此,让我们首先为每个ID分配一个唯一ID。

f <- function(n) {
    # Returns a vector 
    # 1, 2, 1, 3, ..., 1, n, 2, 3, 2, 4, ..., 2, n, ..., (n-1), n
    m <- matrix(ncol = 2, nrow = n * (n-1) / 2)
    m[, 1] <- rep(1:(n-1), (n-1):1)
    m[, 2] <- unlist(lapply(2:n, function(x) x:n))
    as.numeric(t(m))
}
# Alternatively,
# f <- function(n) {
#     d <- expand.grid(a = 1:n, b = 1:n)
#     d <- d[d$a < d$b, ]
#     unlist(d)
# }
# but this is slower



# Using plyr...
library(plyr)
dat <- ddply(dat, .(id1, id2), function(d) {
    d <- d[f(nrow(d)), ]
    d$id3 <- paste0(d$id1, rep(1:(nrow(d) / 2), each = 2))
    d
})

# ...or using base R
dat <- do.call(rbind, 
     by(dat, list(dat$id1, dat$id2), function(d) {
     d <- d[f(nrow(d)), ]
     d$id3 <- paste0(d$id1, rep(1:(nrow(d) / 2), each = 2))
     d
}))

现在每个(id3,id2)对只有两行,你可以按如下方式计算差异

# Using plyr
result <- ddply(dat, .(id3, id2), function(d) {
    d <- d[paste0(rep(c("x", "y"), 3), 1:3)]
    d$dist <- sqrt(sum((d[1, ] - d[2, ])^2))
    d
})

# Base R
result <- do.call(rbind, 
    by(dat[paste0(rep(c("x", "y"), 3), 1:3)],
        list(dat$id3, dat$id2), 
        function(d){
            d$dist <- sqrt(sum((d[1, ] - d[2, ])^2))
            d
        }
))
result[c("id3", "id2")] <- dat[c("id3", "id2")]
result
#     x1 y2 x3 y1 x2 y3      dist id3  id2
# 1    2  1  4  5  8  1  6.480741  a1 2002
# 2    2  3  4  4  2  2  6.480741  a1 2002
# 5    1  1  4  4  1  1  3.464102  b1 2002
# 6    2  2  6  2  2  2  3.464102  b1 2002
# 3    2  3  1  3  7  3  4.242641  a1 2003
# 4    3  3  2  3  3  3  4.242641  a1 2003
# 7    4  4  3  1  2  4  5.916080  b1 2003
# 8    6  3  2  6  2  6  5.916080  b1 2003
# 7.1  4  4  3  1  2  4  9.000000  b2 2003
# 9    4  8  9  3  6  1  9.000000  b2 2003
# 8.1  6  3  2  6  2  6 11.313708  b3 2003
# 9.1  4  8  9  3  6  1 11.313708  b3 2003

答案 1 :(得分:0)

也许这可能会有所帮助。

dist(dat [which(dat [,&#34; id1&#34;] ==&#34; a&#34;&amp; dat [,&#34; id2&#34;] ==&#34 ; 2002&#34;),],方法=&#34;欧几里德&#34;) dist(dat [which(dat [,&#34; id1&#34;] ==&#34; b&#34;&amp; dat [,&#34; id2&#34;] ==&#34; 2003&# 34;),],方法=&#34;欧几里德&#34;)