数据帧中任何点之间的唯一成对距离

时间:2017-08-10 12:13:42

标签: r dplyr euclidean-distance

我有一个包含X坐标的十个点的列表。我想计算任意两点之间距离的可能排列。确切地说,应该只存在1-2,2-1中的一个距离。我已设法通过自身移除一个点的距离。但无法实现这种排列距离。

# Data Generation
df <- data.frame(X = runif(10, 0, 1), Y = runif(10, 0, 1), ID = 1:10)

# Temporary key Creation
df <- df %>% mutate(key = 1) 

# Calculating pairwise distances
df %>% full_join(df, by = "key") %>% 
  mutate(dist = sqrt((X.x - X.y)^2 + (Y.x - Y.y)^2)) %>% 
  select(ID.x, ID.y, dist) %>% filter(!dist == 0) %>% head(11)

# Output 
#    ID.x ID.y       dist
# 1     1    2 0.90858911
# 2     1    3 0.71154587
# 3     1    4 0.05687495
# 4     1    5 1.03885510
# 5     1    6 0.93747717
# 6     1    7 0.62070415
# 7     1    8 0.88351690
# 8     1    9 0.89651911
# 9     1   10 0.05079906
# 10    2    1 0.90858911
# 11    2    3 0.27530175

如何实现下面显示的预期输出?

# Expected Output 
#    ID.x ID.y       dist
# 1     1    2 0.90858911
# 2     1    3 0.71154587
# 3     1    4 0.05687495
# 4     1    5 1.03885510
# 5     1    6 0.93747717
# 6     1    7 0.62070415
# 7     1    8 0.88351690
# 8     1    9 0.89651911
# 9     1   10 0.05079906
# 10    2    3 0.27530175
# 11    2    4 0.5415415

但与dist()相比,这种方法计算速度较慢。听听更快的方法会更高兴。

2 个答案:

答案 0 :(得分:2)

我会对数据使用dist,然后将输出处理为所需的格式。您可以将dist替换为任何其他距离函数。在这里,我使用字母而不是数字作为ID来更好地显示正在发生的事情

set.seed(42)
df <- data.frame(X = runif(10, 0, 1), Y = runif(10, 0, 1), ID = letters[1:10])

df %>% 
  column_to_rownames("ID") %>% #make the ID the rownames. dist will use these> NB will not work on a tibble
  dist() %>% 
  as.matrix() %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "ID.x") %>% #capture the row IDs
  gather(key = ID.y, value = dist, -ID.x) %>% 
  filter(ID.x < ID.y) %>% 
  as_tibble()

   # A tibble: 45 x 3
    ID.x  ID.y      dist
   <chr> <chr>     <dbl>
 1     a     b 0.2623175
 2     a     c 0.7891034
 3     b     c 0.6856994
 4     a     d 0.2191960
 5     b     d 0.4757855
 6     c     d 0.8704269
 7     a     e 0.2730984
 8     b     e 0.3913770
 9     c     e 0.5912681
10     d     e 0.2800021
# ... with 35 more rows
与通过计算距离进行循环相比,

dist非常快。 通过直接处理dist对象而不是将其转换为矩阵,可以使代码更有效。

答案 1 :(得分:1)

也许这是一种稍微简单的方法:

df <- data.frame(X = runif(10, 0, 1), Y = runif(10, 0, 1), ID = 1:10)

df2 <- data.frame(ID1 = rep(1:10, each = 10),
                  ID2 = 1:10,
                  distance = as.vector(as.matrix((dist(df)))))

然后摆脱对角线:

df2 <- df2[df2$ID1 != df2$ID2,]

摆脱上三角:

df2 <- df2[df2$ID1 < df2$ID2,]
df2
ID1 ID2 distance
2    1   2 1.000615
3    1   3 2.057813
4    1   4 3.010261
5    1   5 4.039502
6    1   6 5.029982
7    1   7 6.035427
8    1   8 7.012540
9    1   9 8.006249
10   1  10 9.015352
13   2   3 1.099245
14   2   4 2.011664
...