2017-08-10 102 views
0

我有一個包含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()相比,這種方法計算速度較慢。聽更快的方法會更開心。

+1

您可能要添加過濾器(ID.x

+1

一般不好使用標籤只是爲了「獲得關注」。如果你的問題是關於data.table或至少使用它,那麼我認爲它更合適。 – Frank

+0

@Frank是的,我已經使用'data.table'方法來獲得一些建議(我認爲它們通常比數據框架方法更快)。 – Prradep

回答

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對象而不是將其轉換爲矩陣,可以使代碼更有效。

+0

如果我們需要使用自定義距離函數,該怎麼辦? –

+0

添加'過濾器(ID.x Prradep

+0

當'ID'與序列'1:10'不同時,你如何調整解決方案?而不是'rowid_to_column(var =「ID.x」)',我嘗試使用'mutate(「ID.x」= df $ ID)''。但是,對於在'gather(key = ID.y,value = dist,-ID.x)''中創建'ID.y''的備選方案,我沒有清楚的想法。 – Prradep

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 
... 
+0

它與[上一個回答](https://stackoverflow.com/a/45613743/4836511)或多或少相同。我認爲'過濾器(ID.x Prradep

+0

此答案只使用baseR。以前的答案使用(幾個?)未聲明的軟件包 – trosendal