[英]Use `dplyr` to avoid `for` loop: calculate distance to observations
我有兩個數據集A
和B
以及用於在每個觀測A
我要計算的距離distance
(例如,歐幾里德距離,L1距離,或其他內容),以在每個觀測B
(該距離的計算是基於所述變量在數據集中)。 然后,來自A
的觀測值應與B
中距離最小的觀測值相關。
例如,如果A
有5000個觀測值,而B
有10000個觀測值,則
for(i in 1:5000)
{
x = data.frame(x = numeric(), y = numeric())
for(j in 1:10000)
{
x[j,] = distance(A[i,], B[j,])
}
A[i,]$associated_row_B = x[which.min(x[1,]),1]
}
基本上可以滿足我的要求(如果觀察距離相同,我仍然必須解決)。 但是由於我使用的是dplyr
所以幾乎dplyr
使用for循環。 我的解決方案甚至需要兩個循環,所以我想知道是否有可能使用dplyr
/ tidyverse
提供的解決方案來避免for循環。
一個非常基本的例子:
A:
i a b
1 -0.5920377 a
2 0.4263199 b
3 0.6737029 a
4 1.3063658 c
5 0.1314103 d
B:
i a b
1 -0.30201541 a
2 -0.07093386 b
3 0.96317764 c
4 -0.33303061 d
5 -1.00834895 d
和距離函數:
distance = function(x,y) return(c((x[2] - y[2])^2 + abs(x[3] - y[3]), y[1])
返回值的第一個元素是實際距離,第二個值是來自B的標識符。
公平的警告:對於大型數據集,這將是非常低效的!
你可以做到這一點使用crossing
從tidyr
和slice
從dplyr
。
首先,讓我們創建兩個虛擬數據幀A_df
和B_df
A_df <- data.frame(
observation_A = runif(100),
id_A = 1:100
)
B_df <- data.frame(
observation_B = runif(50),
id_B = 1:50
)
為了清楚起見,我在A_df
和B_df
之間保留了唯一的列名。 接下來,我們將使用tidyr::crossing
查找兩個數據幀之間的行的每種組合。 接下來,我們使用mutate
來計算距離(在這里,我任意取了它們的差的絕對值,但是您可以在此處應用自定義距離函數)。 最后,我們將id_A
,並使用slice
保留最小值(並以R為which.max
)。
library(tidyverse)
full_df <- A_df %>%
crossing(B_df) %>%
mutate(distance = abs(observation_A-observation_B)) %>%
group_by(id_A) %>%
slice(which.min(distance))
查看full_df
,我們得到了希望的結果:
> full_df
# A tibble: 100 x 5
# Groups: id_A [100]
observation_A id_A observation_B id_B distance
<dbl> <int> <dbl> <int> <dbl>
1 0.826 1 0.851 44 0.0251
2 0.903 2 0.905 3 0.00176
3 0.371 3 0.368 18 0.00305
4 0.554 4 0.577 34 0.0232
5 0.656 5 0.654 10 0.00268
6 0.120 6 0.110 37 0.0101
7 0.991 7 0.988 6 0.00244
8 0.983 8 0.988 6 0.00483
9 0.325 9 0.318 45 0.00649
10 0.860 10 0.864 40 0.00407
# ... with 90 more rows
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.