Проверьте, находится ли значение столбца между (диапазоном) двух других значений столбца - PullRequest
0 голосов
/ 19 октября 2018

У меня есть кадр данных, который выглядит следующим образом (Dataframe X):

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

У меня есть другой кадр данных, который выглядит следующим образом (Dataframe Y):

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

ЧтоЯ хочу сделать это: Для каждого значения в столбце «число» в Dataframe X найдите, равно ли оно ЛЮБОМУ значению пары «число1» и «число2» в кадре «Дата», или между ними. Кроме того, для этого «число1»и значения пары «number2», соответствующий ей «id» должен совпадать с «id» в Dataframe X. Если все это правда, то я хочу вставить «YES» в столбец «found» соответствующей строки в Dataframe X:

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

Как мне поступить? Спасибо за помощь.

Ответы [ 4 ]

0 голосов
/ 19 октября 2018

Вот вариант, использующий 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

data

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))
0 голосов
/ 19 октября 2018

Использование 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)

enter image description here

0 голосов
/ 19 октября 2018

Использование 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

Создано в 2018-10-18 пакетом Представить (v0.2.0).

0 голосов
/ 19 октября 2018

Мы можем выполнить цикл по каждому x$number, используя sapply, и проверить, находится ли он в диапазоне any, y$number1 и y$number2, и соответственно присвоить значение.

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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...