используя roll в соединении data.table, могу ли я форсировать одно совпадение - PullRequest
1 голос
/ 06 июля 2019

У меня есть две таблицы для объединения на основе полей даты и времени.Чтобы воссоздать сценарий, давайте возьмем пример рекламы против продажи.Мы хотим знать, какая продажа связана с какой рекламой.

Продажа может быть помечена только для последней рекламы и только в том случае, если она произошла после рекламы.

Кроме того, если продажа произошла после несколькихрекламные ролики, мы можем пометить продажу только последним рекламным роликом;предыдущие объявления будут иметь нулевое значение в соединении.

Я не могу получить эту последнюю часть.Если после нескольких рекламных роликов происходит продажа, то все такие рекламные объявления объединяются с этой продажей;который я не хочу.В моем примере продажа, которая произошла в «2017-01-01 02:05:00», должна объединяться с рекламой, которая транслировалась в «2017-01-01 02:00:00», а не с предыдущими рекламными роликами.

вывод кода

library(lubridate)
library(data.table)

ts <- seq(as.POSIXct("2017-01-01", tz = "UTC"),
          as.POSIXct("2017-01-02", tz = "UTC"),
          by = "30 min")

commercial <-
  data.table(
    c_row_number = 1:10,
    c_time       = ts[1:10],
    c_time_roll  = ts[1:10]
  )

sale <-
  data.table(
    s_row_number = 1:4,
    s_time       = ts[5:8] + minutes(5),
    s_time_roll  = ts[5:8] + minutes(5)
  )

setkey(commercial, c_time_roll)
setkey(sale, s_time_roll)

tbl_joined <- sale[commercial, roll = -Inf] # , mult = 'last']

Любая идея, как мы можем получить NA, где c_row_number равен 1, 2, 3 и 4. Спасибо.

Ответы [ 2 ]

1 голос
/ 07 июля 2019

Если ваши коммерческие времена отсортированы или вы можете их отсортировать, то вы можете использовать неэквивалентное объединение со вспомогательным столбцом со смещенными временами:

library(lubridate)
library(data.table)

ts <- seq(as.POSIXct("2017-01-01", tz = "UTC"),
          as.POSIXct("2017-01-02", tz = "UTC"),
          by = "30 min")

commercial <-
  data.table(
    c_row_number = 1:10,
    c_time       = ts[1:10],
    c_next_time  = shift(ts[1:10], type = "lead", fill = max(ts))
  )

sale <-
  data.table(
    s_row_number = 1:4,
    s_time       = ts[5:8] + minutes(5),
    s_time_join  = ts[5:8] + minutes(5)
  )

tbl_joined <- sale[commercial, on = .(s_time_join >= c_time, s_time_join < c_next_time)]

И если вы хотите использовать эта идиома :

commercial[, s_time := sale[.SD,
                            .(s_time),
                            on = .(s_time_join >= c_time, s_time_join < c_next_time)]]
print(commercial)
    c_row_number              c_time         c_next_time              s_time
 1:            1 2017-01-01 00:00:00 2017-01-01 00:30:00                <NA>
 2:            2 2017-01-01 00:30:00 2017-01-01 01:00:00                <NA>
 3:            3 2017-01-01 01:00:00 2017-01-01 01:30:00                <NA>
 4:            4 2017-01-01 01:30:00 2017-01-01 02:00:00                <NA>
 5:            5 2017-01-01 02:00:00 2017-01-01 02:30:00 2017-01-01 02:05:00
 6:            6 2017-01-01 02:30:00 2017-01-01 03:00:00 2017-01-01 02:35:00
 7:            7 2017-01-01 03:00:00 2017-01-01 03:30:00 2017-01-01 03:05:00
 8:            8 2017-01-01 03:30:00 2017-01-01 04:00:00 2017-01-01 03:35:00
 9:            9 2017-01-01 04:00:00 2017-01-01 04:30:00                <NA>
10:           10 2017-01-01 04:30:00 2017-01-02 00:00:00                <NA>
1 голос
/ 07 июля 2019

Нет способа сделать это напрямую - x[i] использует i для поиска строк в x. mult используется для обратного - когда несколько строк в x соответствуют одной строке в i. Здесь несколько строк в i соответствуют одной строке в x.

Тогда вам лучше всего использовать post-join на итоговой таблице. Например, чтобы удалить эти строки, вы можете использовать unique:

unique(sale[commercial, roll = -Inf], by = 's_row_number', fromLast = TRUE)
#    s_row_number              s_time         s_time_roll c_row_number
# 1:            1 2017-01-01 02:05:00 2017-01-01 02:00:00            5
# 2:            2 2017-01-01 02:35:00 2017-01-01 02:30:00            6
# 3:            3 2017-01-01 03:05:00 2017-01-01 03:00:00            7
# 4:            4 2017-01-01 03:35:00 2017-01-01 03:30:00            8
# 5:           NA                <NA> 2017-01-01 04:30:00           10
#                 c_time
# 1: 2017-01-01 02:00:00
# 2: 2017-01-01 02:30:00
# 3: 2017-01-01 03:00:00
# 4: 2017-01-01 03:30:00
# 5: 2017-01-01 04:30:00

Я подозреваю, что вы создаете {s,c}_row_number только для этой задачи; чтобы сделать это без этих столбцов, вы можете сделать:

sale[commercial, roll = -Inf][order(-c_time)][rowid(s_time) == 1L]

Мы сортируем в обратном порядке по c_time, чтобы убедиться, что rowid получает самое последнее значение.

Обратите внимание, что в обоих случаях одна из строк is.na(s_time) была удалена.

Надеюсь, это заставит вас двигаться в правильном направлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...