R | Слияние строк до и после

#r

#r

Вопрос:

У меня есть два набора данных, которые выглядят так

 df
Region   Quarter   Review Date
North    Q1        2019-02-01
North    Q2        2019-05-01
South    Q1        2019-01-15
South    Q3        2019-08-20

sales
Region   Date          Sales
North    2019-01-25    20,500
North    2019-01-27    17,450
North    2019-02-01    31,000
North    2019-02-05    16,700
...
South    2019-08-16    2,300
South    2019-08-17    1,560
South    2019-08-20    3,400
South    2019-08-25    7,200     
  

Я хочу создать новый фрейм данных, который принимает ‘df’, добавляет новый столбец Sales, а также выбирает продажи за два дня до и после даты проверки из фрейма данных ‘sales’. Даты в «продажах» не расположены последовательно и являются случайными для разных регионов и кварталов. Результирующий фрейм данных должен выглядеть следующим образом

 final df
    Region   Quarter   Review Date   Sales
    North    Q1        2019-01-25    20,500
    North    Q1        2019-01-27    17,450
    North    Q1        2019-02-01    31,000
    North    Q1        2019-02-05    16,700
    North    Q1        2019-02-07    23,400
    ...
    South    Q3        2019-08-16    2,300
    South    Q3        2019-08-17    1,560
    South    Q3        2019-08-20    3,400
    South    Q3        2019-08-25    7,200
    South    Q3        2019-08-29    4,350
  

Я могу получить данные о продажах на дату проверки с помощью слияния, но не знаю, как я могу получить даты и продажи выше и ниже из второго фрейма данных.

Ответ №1:

Вы можете попробовать присоединиться df df2 'Region' к столбцу by и для каждого Region , Quarter и ReviewDate значение выберите 2 строки выше и ниже, где ReviewDate == Date .

 library(dplyr)

df %>%
  left_join(df2, by = 'Region') %>%
  group_by(Region, Quarter, ReviewDate) %>%
  slice({i <- which(ReviewDate == Date);(i-2):(i 2)})
  

Ответ №2:

Я уже некоторое время использую самодельную leadlag функцию, думаю, ее можно использовать здесь. Это позволяет произвольно опережать и отставать.

 leadlag <- function(lgl, bef = 1, aft = bef) {
  n <- length(lgl)
  bef <- min(n, max(0, bef))
  aft <- min(n, max(0, aft))
  befx <- if (bef > 0) sapply(seq_len(bef), function(b) c(tail(lgl, n = -b), rep(FALSE, b)))
  aftx <- if (aft > 0) sapply(seq_len(aft), function(a) c(rep(FALSE, a), head(lgl, n = -a)))
  rowSums(cbind(befx, lgl, aftx), na.rm = TRUE) > 0
}
  

Простой пример:

 vec <- 1:20
vec[leadlag(vec %% 10 == 1)] # 1, 11, as well as  /- 1
# [1]  1  2 10 11 12
vec[leadlag(vec %% 10 == 1, 2)] # 1, 11, as well as  /- 2
# [1]  1  2  9 10 11 12
vec[leadlag(vec %% 10 == 1, 0, 2)] # 1, 11, as well as none before and 2 after
# [1]  1  2  3 11 12 13
  

В этом приложении, аналогичном @RonakShah,

 df %>%
  left_join(df2, by = 'Region') %>%
  group_by(Region, Quarter, ReviewDate) %>%
  filter(leadlag(ReviewDate == Date))