[英]R: find rows in data frame within range of each other across multiple columns
我有一個看起來像這樣的數據框:
ID lat long score
1 41.5 -62.3 22.4
2 41.0 -70.2 21.9
3 42.2 -63.0 22.7
4 36.7 -72.9 20.0
5 36.2 -62.4 24.1
6 35.8 -61.7 24.7
7 40.8 -61.9 22.1
我想識別此數據幀的行,其中 lat 的值彼此相差 1 個單位,long 的值彼此相差 1 個單位,並且 score 的值彼此相差 0.7 個單位。 為了指示哪些行滿足這些條件,我想添加一個新列 (ID.matches),為滿足上述條件的行提供 ID 值。 最終的數據框可能如下所示:
ID lat long score ID.matches
1 41.5 -62.3 22.4 3, 7
2 41.0 -70.2 21.9 0
3 42.2 -63.0 22.7 1
4 36.7 -72.9 20.0 0
5 36.2 -62.4 24.1 6
6 35.8 -61.7 24.7 5
7 40.8 -61.9 22.1 1
我不確定從哪里開始...我認為某種有條件的 function 使用 dplyr 或 sapply? 我也不確定是否應該為 ID.matches 使用另一種數據結構,因為某些行會有多個匹配項。
謝謝你的幫助!
您可以使用outer
檢查所有條件以形成邏輯矩陣(記住要排除自匹配對角線),並將結果apply
ID 列的子集,將結果一起粘貼到字符串中:
df$ID.matches <- apply(outer(df$lat, df$lat, function(x, y) abs(x - y) < 1) &
outer(df$lon, df$lon, function(x, y) abs(x - y) < 1) &
outer(df$score, df$score, function(x, y) abs(x - y) < 0.7) &
diag(nrow(df)) == 0,
MARGIN = 1,
function(x) paste(df$ID[x], collapse = ", "))
df
#> ID lat long score ID.matches
#> 1 1 41.5 -62.3 22.4 3, 7
#> 2 2 41.0 -70.2 21.9
#> 3 3 42.2 -63.0 22.7 1
#> 4 4 36.7 -72.9 20.0
#> 5 5 36.2 -62.4 24.1 6
#> 6 6 35.8 -61.7 24.7 5
#> 7 7 40.8 -61.9 22.1 1
由代表 package (v0.3.0) 於 2020 年 7 月 7 日創建
另一種方法是使用一些tidyverse
函數filter
到匹配條件的行並pull
匹配行的ID
。
# Create example data
library(tidyverse)
df <- tribble(
~ID, ~lat, ~long, ~score,
1, 41.5, -62.3, 22.4,
2, 41.0, -70.2, 21.9,
3, 42.2, -63.0, 22.7,
4, 36.7, -72.9, 20.0,
5, 36.2, -62.4, 24.1,
6, 35.8, -61.7, 24.7,
7, 40.8, -61.9, 22.1
)
df$ID.match <- sapply(df$ID, function(x){
df %>%
filter(abs(lat- lat[ID == x]) < 1,
abs(long - long[ID == x]) < 1,
abs(score - score[ID == x]) < 0.7,
ID != x) %>%
pull(ID) %>%
paste0(collapse = ',')
})
df
#> # A tibble: 7 x 5
#> ID lat long score ID.match
#> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1 1 41.5 -62.3 22.4 "3,7"
#> 2 2 41 -70.2 21.9 ""
#> 3 3 42.2 -63 22.7 "1"
#> 4 4 36.7 -72.9 20 ""
#> 5 5 36.2 -62.4 24.1 "6"
#> 6 6 35.8 -61.7 24.7 "5"
#> 7 7 40.8 -61.9 22.1 "1"
編輯:這是不使用sapply
和$
的方法(即完全在tidyverse
框架中)
df %>%
mutate(ID.match = map_chr(ID, function(x){
df %>%
filter(abs(lat- lat[ID == x]) < 1,
abs(long - long[ID == x]) < 1,
abs(score - score[ID == x]) < 0.7,
ID != x) %>%
pull(ID) %>%
paste0(collapse = ',')
}))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.