R сравнивает значения из одного кадра данных со значениями из другого кадра данных - PullRequest
0 голосов
/ 13 ноября 2018

Я довольно новичок в R, поэтому все еще учусь многому. Я искал вокруг, но я не могу найти подходящий ответ на мою проблему. У меня есть эти два набора данных:

d1
    Criteria Order Low High
1        a     1   0   10
2        a     1  11   20
3        a     1  21   30
4        b     1   0   13
5        b     1  14   32
6        a     2   5   22
7        a     2   0    4
8        b     2   0   18

, а затем d2

 Criteria Order Final
1        a     1    13
2        b     2    12
3        a     1     8
4        a     2     2 

Мне было интересно, есть ли способ добавить дополнительный столбец к d1, когда d2$Final находится в пределах d1$Low и d1$High, а критерии и порядок совпадают. То, что я ожидаю получить, будет примерно таким:

 Criteria Order Low High Final
1        a     1   0   10     8
2        a     1  11   20    13
3        a     1  21   30    NA
4        b     1   0   13    NA
5        b     1  14   32    NA
6        a     2   5   22    NA
7        a     2   0    4     2
8        b     2   0   18    12  

Или даже числовой вывод 1/0 для true или false в столбце Final будет в порядке.

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

Используется SQL для создания сложного соединения.Потребность в [...] вокруг Order состоит в том, чтобы отличить его от ключевого слова с тем же именем.

library(sqldf)

sqldf("select d1.*, d2.Final
  from d1 
  left join d2 on d1.Criteria = d2.Criteria and
                  d1.[Order] = d2.[Order] and
                  d2.Final between d1.Low and d1.High")

, что дает тот же результат, показанный в вопросе:

  Criteria Order Low High Final
1        a     1   0   10     8
2        a     1  11   20    13
3        a     1  21   30    NA
4        b     1   0   13    NA
5        b     1  14   32    NA
6        a     2   5   22    NA
7        a     2   0    4     2
8        b     2   0   18    12

Примечание

Данные в воспроизводимом виде:

Lines1 <- "
    Criteria Order Low High
1        a     1   0   10
2        a     1  11   20
3        a     1  21   30
4        b     1   0   13
5        b     1  14   32
6        a     2   5   22
7        a     2   0    4
8        b     2   0   18"

Lines2 <- "
  Criteria Order Final
1        a     1    13
2        b     2    12
3        a     1     8
4        a     2     2"

d1 <- read.table(text = Lines1)
d2 <- read.table(text = Lines2)
0 голосов
/ 13 ноября 2018

Если ваши данные «большого размера», это решение не будет для вас: декартово соединение взорвется за пределы того, что «стандартный» компьютер допустит в отношении памяти.

Если, однако, вашданные достаточно малы (очень относительный термин), тогда вы можете выполнить cartesian-join (также известный как полное или полное внешнее объединение) и отфильтровать результаты.(Это решение является реализацией одного раздела из https://www.mango -solutions.com / blog / in -ween-a-rock-and-a-conditional-join . Существуют и другие разделы, в которых обсуждается SQL иfuzzyjoin, оба достойных кандидата.)

Три диалекта, в зависимости от ваших предпочтений.

Base R

a <- merge(d2, d1, all.x=T)
a <- transform(a, Final = ifelse(Low <= Final & Final <= High, Final, NA))
a[!duplicated(a),]
#   Criteria Order Final Low High
# 1        a     1    NA   0   10
# 2        a     1    13  11   20
# 3        a     1    NA  21   30
# 4        a     1     8   0   10
# 5        a     1    NA  11   20
# 7        a     2    NA   5   22
# 8        a     2     2   0    4
# 9        b     2    12   0   18

У него есть дополнительный ряд, пытающийся работать элегантно ...

dplyr

library(dplyr)
full_join(d1, d2) %>%
  mutate(Final = if_else(between(Final, Low, High), Final, NA_integer_)) %>%
  group_by(Criteria, Order, Low, High) %>%
  summarise(Final = coalesce(Final)[1]) %>%
  ungroup()
# Joining, by = c("Criteria", "Order")
# # A tibble: 8 x 5
#   Criteria Order   Low  High Final
#   <chr>    <int> <int> <int> <int>
# 1 a            1     0    10    NA
# 2 a            1    11    20    13
# 3 a            1    21    30    NA
# 4 a            2     0     4     2
# 5 a            2     5    22    NA
# 6 b            1     0    13    NA
# 7 b            1    14    32    NA
# 8 b            2     0    18    12

data.table

library(data.table)
as.data.table(d2)[d1, on = .(Final > Low, Final < High, Criteria, Order),
                  .(Criteria, Order, Low, High, x.Final)]
#    Criteria Order Low High x.Final
# 1:        a     1   0   10       8
# 2:        a     1  11   20      13
# 3:        a     1  21   30      NA
# 4:        b     1   0   13      NA
# 5:        b     1  14   32      NA
# 6:        a     2   5   22      NA
# 7:        a     2   0    4       2
# 8:        b     2   0   18      12

(Существует также решение, использующее data.table::foverlaps, которое может быть быстрее или более экономным для памяти. Прочитайте ссылку, это очень полезно.)


Данные:

d1 <- structure(list(Criteria = c("a", "a", "a", "b", "b", "a", "a", 
"b"), Order = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L), Low = c(0L, 
11L, 21L, 0L, 14L, 5L, 0L, 0L), High = c(10L, 20L, 30L, 13L, 
32L, 22L, 4L, 18L)), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8"))
d2 <- structure(list(Criteria = c("a", "b", "a", "a"), Order = c(1L, 
2L, 1L, 2L), Final = c(13L, 12L, 8L, 2L)), class = "data.frame", row.names = c("1", 
"2", "3", "4"))
...