[英]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.