Условное объединение в r

Я хотел бы условно соединить две таблицы данных вместе:

library(data.table)
set.seed(1)

key.table <- 
  data.table(
    out = (0:10)/10,
    keyz = sort(runif(11))
  )

large.tbl <- 
  data.table(
    ab = rnorm(1e6),
    cd = runif(1e6)
  )

в соответствии со следующим правилом: соответствие наименьшему значению out в key.table, значение keyz которого больше cd. У меня есть следующее:

library(dplyr)
large.tbl %>%
  rowwise %>%
  mutate(out = min(key.table$out[key.table$keyz > cd]))

который обеспечивает правильный вывод. Проблема в том, что операция rowwise кажется дорогой для large.tbl, которую я фактически использую, сбой ее, если она не находится на определенном компьютере. Есть ли меньше операций, связанных с памятью? Следующее выглядит немного быстрее, но недостаточно для проблемы, которую у меня есть.

large.tbl %>%
    group_by(cd) %>%
    mutate(out = min(key.table$out[key.table$keyz > cd]))

Это пахнет проблемой с ответом data.table, но ответ не должен использовать этот пакет.

Ответ 1

Что вы хотите:

setkey(large.tbl, cd)
setkey(key.table, keyz)
key.table[large.tbl, roll = -Inf]

См. ?data.table > roll:

Применяется к последнему столбцу объединения, обычно к дате, но может быть любой упорядоченной переменной, нерегулярной и включающей пробелы. Если строка roll=TRUE и i соответствует всем, кроме последнего столбца столбца x, а его значение в последнем столбце столбца i попадает в пробел (в том числе после последнего наблюдения в x для этой группы), тогда преобладающее значение в x выполняется вперед. Эта операция особенно быстро используется с измененным двоичным поиском. Операция также известна как последнее наблюдение, перенесенное вперед (LOCF). Обычно в x не должно быть дубликатов, последний ключевой столбец - дата (или время или дата-время) и все столбцы ключа x. Общей идиомой является выбор одновременного регулярного временного ряда (dts) по набору идентификаторов (ids): DT[CJ(ids,dts),roll=TRUE], где DT имеет ключ с двумя столбцами (id,date) и CJ выступает для перекрестного соединения. Когда roll - это положительное число, это ограничивает перенос дальнейших значений. roll=TRUE эквивалентно roll=+Inf. Когда roll - отрицательное число, значения откатываются назад; т.е. последующее наблюдение переносится назад (NOCB). Используйте -Inf для неограниченного возврата назад. Когда roll "nearest", ближайшее значение объединяется.

(честно говоря, я думаю, что это может пойти на некоторое разъяснение, оно довольно плотное)

Ответ 2

Если key.table$out также сортируется, как в примере с вашей игрушкой, следующие будут работать

ind <- findInterval(large.tbl$cd, key.table$keyz) + 1
large.tbl$out <- key.table$out[ind]
head(large.tbl)
#             ab         cd out
#1: -0.928567035 0.99473795  NA
#2: -0.294720447 0.41107393 0.5
#3: -0.005767173 0.91086585 1.0
#4:  2.404653389 0.66491244 0.8
#5:  0.763593461 0.09590456 0.1
#6: -0.799009249 0.50963409 0.5

Если key.table$out не сортируется,

ind <- findInterval(large.tbl$cd, key.table$keyz) + 1
vec <- rev(cummin(rev(key.table$out)))
large.tbl$out <- vec[ind]