【问题标题】:Check if column value is in between (range) of two other column values检查列值是否在其他两个列值之间(范围)
【发布时间】:2019-03-23 22:27:55
【问题描述】:

我有一个看起来像这样的数据框(Dataframe X):

id  number  found
1   5225    NA
2   2222    NA
3   3121    NA

我有另一个看起来像这样的数据框(数据框 Y):

id  number1  number2    
1   4000     6000
3   2500     3300
3   7000     8000

我想要做的是:对于 Dataframe X“number”列中的每个值,搜索它是否等于或介于 Dataframe Y 的“number1”和“number2”对值中的任何一个。此外,对于这个“number1”和“number2”对值,其各自的“id”必须与Dataframe X中的“id”匹配。如果这都是真的,那么我想在相应行的“found”列中插入一个“YES”在数据框 X 中:

id  number  found
1   5225    YES
2   2222    NA
3   3121    YES

我该怎么做呢?感谢您的帮助。

【问题讨论】:

标签: r


【解决方案1】:

这是一个使用fuzzy_join的选项

library(fuzzy_join)
library(dplyr)
fuzzy_left_join(X, Y[-1], by = c("number" = "number1", "number" = "number2"), 
     match_fun  =list(`>=`, `<=`)) %>% 
    mutate(found = c(NA, "YES")[(!is.na(number1)) + 1]) %>% 
    select(names(X))
#    id number found
#1  1   5225   YES
#2  2   2222  <NA>
#3  3   3121   YES

或者另一种选择是与data.table 的非等连接

library(data.table)
setDT(X)[, found := NULL]
X[Y, found := "YES", on = .(number >= number1, number <= number2)]
X
#   id number found
#1:  1   5225   YES
#2:  2   2222  <NA>
#3:  3   3121   YES

数据

X <- structure(list(id = 1:3, number = c(5225L, 2222L, 3121L), found = c(NA, 
  NA, NA)), class = "data.frame", row.names = c(NA, -3L))

Y <- structure(list(id = 1:3, number1 = c(4000L, 2500L, 7000L), number2 = c(6000L, 
    3300L, 8000L)), class = "data.frame", row.names = c(NA, -3L))

【讨论】:

  • 如果我想确保两个表中的 id 也匹配,我将如何使用您的解决方案?
【解决方案2】:

我们可以使用sapply 遍历每个x$number 并检查它是否位于y$number1y$number2any 范围内,并相应地给出值。

x$found <- ifelse(sapply(x$number, function(p) 
                 any(y$number1 <= p & y$number2 >= p)),"YES", NA)
x

#  id number found
#1  1   5225   YES
#2  2   2222  <NA>
#3  3   3121   YES

使用相同的逻辑,但使用replace

x$found <- replace(x$found, 
         sapply(x$number, function(p) any(y$number1 <= p & y$number2 >= p)), "YES")

编辑

如果我们还想比较 id 的值,我们可以这样做

x$found <- ifelse(sapply(seq_along(x$number), function(i) {
           inds <- y$number1 <= x$number[i] & y$number2 >= x$number[i]
           any(inds) & (x$id[i] == y$id[which.max(inds)])
           }), "YES", NA)

x$found
#[1] "YES" NA    "YES"

【讨论】:

  • 如果我想确保两个表中的 id 也匹配,我将如何使用您的解决方案?
  • @Tony 不太确定我是否理解正确。您能否更新您的问题并解释您要在这里实现的目标?
  • 我刚刚更新了问题。我想确保每个数据帧的“id”值也匹配。因此,数据帧 X 中的“数字”值必须介于数据帧 Y 的任何“数字1”和“数字2”值之间,并且每个数据帧中的“id”值也必须匹配,才能将“是”添加到“找到”列。
  • 嗨@Ronak。谢谢你的回答,我明白了,除了最后一行any(inds) &amp; (x$id[i] == y$id[which.max(inds)])。这是做什么的?我知道它正在匹配 id,但它是如何通过取最大值来做到这一点的?
  • @ManasiShah indsTRUE/FALSE 值的向量,使用which.max 我们得到第一个TRUE 值的索引。检查which.max(c(FALSE, TRUE, TRUE)) 所以我们将xs id 与y 中的第一个id 匹配。
【解决方案3】:

使用tidyverse 函数,尤其是map_chr 来遍历每个数字:

library(tidyverse)
tbl1 <- read_table2(
"id   number  found
1    5225     NA
2    2222     NA
3    3121     NA"
)
tbl2 <- read_table2(
"id  number1  number2
1    4000   6000
2    2500   3300
3    7000   8000"
)

tbl1 %>%
  mutate(found = map_chr(
    .x = number,
    .f = ~ if_else(
      condition = any(.x > tbl2$number1 & .x < tbl2$number2),
      true = "YES",
      false = NA_character_
    )
  ))
#> # A tibble: 3 x 3
#>      id number found
#>   <int>  <int> <chr>
#> 1     1   5225 YES  
#> 2     2   2222 <NA> 
#> 3     3   3121 YES

reprex package (v0.2.0) 于 2018 年 10 月 18 日创建。

【讨论】:

  • @Tony - Calum 只是在重新创建您的数据,以便他们可以使用。如果您已经导入了数据,则可以忽略开头的 read_table 位。
  • 如果我想确保两个表中的 id 也匹配,我将如何使用您的解决方案?
  • 我看到您编辑了问题文本但没有更改提供的数据?在什么情况下它们不会对齐(id 是否重复、丢失或两者之间只是不同?)在这些情况下应该返回什么?
  • 这太棒了!有没有办法以编程方式选择number1number2?也可以为tbl1 中的每一行选择不同的tbl2,或者如果我要为每一行添加潜在阈值,我可以直接使用number1number2
【解决方案4】:

使用sqldf

library(sqldf)
sql <- "SELECT DISTINCT x.id, x.number, "
sql <- paste0(sql, "CASE WHEN y.id IS NOT NULL THEN 'YES' END AS found ")
sql <- paste0(sql, "FROM X x LEFT JOIN Y y ON x.number BETWEEN y.number1 AND y.number2")
X <- sqldf(sql)

【讨论】:

  • 请注意,在 R 中,字符常量可以跨越多行,因此您不必将 sql 语句从各个部分粘贴在一起。例如,请参阅此答案中的 (2),这是一个不相关的问题,但说明了一个跨多行运行的 sql 语句:stackoverflow.com/questions/52797665/…
  • @G.Grothendieck 我来自 Java/app 语言背景。知道一个字符串可以跨越多行的好技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-05
  • 2021-08-26
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多