簡體   English   中英

R:跨多列在彼此的范圍內查找數據框中的行

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM