Есть ли какой-либо способ объединить два фрейма данных по диапазонам дат?

#r #tidyverse

#r #tidyverse

Вопрос:

У меня есть два фрейма данных, первый набор данных — это запись для прогнозируемого спроса в следующие 27 дней для каждого элемента компании, показанного ниже:

 library(tidyverse)
library(lubridate)

daily_forecast <- data.frame(
  item=c("A","B","A","B"),
  date_fcsted=c("2020-8-1","2020-8-1","2020-8-15","2020-8-15"),
  fcsted_qty=c(100,200,200,100)
) %>% 
  mutate(date_fcsted=ymd(date_fcsted)) %>% 
  mutate(extended_date=date_fcsted days(27))
  

а другой набор дат — это фактический ежедневный спрос на каждый элемент:

 actual_orders <- data.frame(
  order_date=rep(seq(ymd("2020-8-3"),ymd("2020-9-15"),by = "1 week"),2),
  item=rep(c("A","B"),7),
  order_qty=round(rnorm(n=14,mean=50,sd=10),0)
)

  

Чего я пытаюсь достичь, так это получить фактический общий спрос на каждый элемент в date_fcsted и extended_date в первом наборе данных, а затем объединить их для вычисления точности прогноза.

Решения с tidyverse будут высоко оценены.

Комментарии:

1. fuzzyjoin Пакет делает это.

Ответ №1:

Вы можете попробовать следующее :

 library(dplyr)

daily_forecast %>%
  left_join(actual_orders, by = 'item') %>%
  filter(order_date >= date_fcsted amp; order_date <= extended_date) %>%
  group_by(item, date_fcsted, extended_date, fcsted_qty) %>%
  summarise(value = sum(order_qty))

#  item  date_fcsted extended_date fcsted_qty value
#  <chr> <date>      <date>             <dbl> <dbl>
#1 A     2020-08-01  2020-08-28           100   179
#2 A     2020-08-15  2020-09-11           200   148
#3 B     2020-08-01  2020-08-28           200   190
#4 B     2020-08-15  2020-09-11           100   197
  

Комментарии:

1. Привет, Роак, большое спасибо за ваш быстрый ответ, и это блестящее решение! Спасибо!

Ответ №2:

Вы также можете попробовать fuzzy_join , как предложил @Gregor Thomas. Я добавил столбец с номером строки, чтобы убедиться, что у вас есть уникальные строки, независимые от item диапазонов дат и (но это может и не понадобиться).

 library(fuzzyjoin)
library(dplyr)

daily_forecast %>%
  mutate(rn = row_number()) %>%
  fuzzy_left_join(actual_orders,
                  by = c("item" = "item",
                         "date_fcsted" = "order_date",
                         "extended_date" = "order_date"),
                  match_fun = list(`==`, `<=`, `>=`)) %>%
  group_by(rn, item.x, date_fcsted, extended_date, fcsted_qty) %>%
  summarise(actual_total_demand = sum(order_qty))
  

Вывод

      rn item.x date_fcsted extended_date fcsted_qty actual_total_demand
  <int> <chr>  <date>      <date>             <dbl>               <dbl>
1     1 A      2020-08-01  2020-08-28           100                 221
2     2 B      2020-08-01  2020-08-28           200                 219
3     3 A      2020-08-15  2020-09-11           200                 212
4     4 B      2020-08-15  2020-09-11           100                 216
  

Комментарии:

1. Спасибо, Бен, за вашу помощь, и я также пытался использовать fuzzy_join. Но он постоянно выдавал мне сообщения об ошибках, и теперь с вашим кодом я понимаю, что я сделал не так. Большое вам спасибо!