在 R 中,像 Solver 这样的计算题

In R , a calculation question like Solver

下面dataframe中有仓库数字,目前知道数据ship_inship_out_forecast。 现在我想修正 ship_out_forecast 个数字,使其合理(结果如附图中的 'ship_out_forecast_checked')

约束条件如下:

  1. cumsum(ship_in)-cumsum(ship_out_forecast_checked)>= 0
  2. ship_out_forecast_checked>0
  3. 'ship_out_forecast_checked'<='ship_out_forecast'
library(tidyverse)
mdate <- c(44593,44594,44595,44596,44597,44598,44599,44600,44601,44602,44603,44604,44605,44606,44607,44593,44594,44595,44596,44597,44598,44599,44600,44601,44602,44603,44604,44605,44606,44607)
category <- c("A","A","A","A","A","A","A","A","A","A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B","B","B","B","B","B")
ship_in <- c(20,0,0,0,5,0,0,0,0,7,0,0,0,0,0,1,0,0,7,30,0,0,0,0,25,0,0,0,0,0)
ship_out_forecast <- c(12,15,13,11,3,5,8,14,8,11,1,9,16,9,3,29,10,28,0,21,12,23,22,23,19,1,2,16,15,9)

warehouse_data <- data.frame(mdate,category,ship_in,ship_out_forecast) %>% 
  mutate(mdate=as.Date(mdate,origin='1900-1-1'))

使用 作为起点 Reduce_frame:

Reduce_frame <- function(data, expr, init) {
  expr <- substitute(expr)
  out <- rep(init[1][NA], nrow(data))
  for (rn in seq_len(nrow(data))) {
    out[rn] <- init <- eval(expr, envir = data[rn,])
  }
  out
}

假设你想按 category 进行分组(如果没有,可以很容易地删除),我们可以这样做:

warehouse_data %>%
  group_by(category) %>%
  mutate(
    ending_inventory = Reduce_frame(cur_data(), max(0, init + ship_in - ship_out_forecast), init = 0)
  ) %>%
  ungroup()
# # A tibble: 30 x 5
#    mdate      category ship_in ship_out_forecast ending_inventory
#    <date>     <chr>      <dbl>             <dbl>            <dbl>
#  1 2022-02-03 A             20                12                8
#  2 2022-02-04 A              0                15                0
#  3 2022-02-05 A              0                13                0
#  4 2022-02-06 A              0                11                0
#  5 2022-02-07 A              5                 3                2
#  6 2022-02-08 A              0                 5                0
#  7 2022-02-09 A              0                 8                0
#  8 2022-02-10 A              0                14                0
#  9 2022-02-11 A              0                 8                0
# 10 2022-02-12 A              7                11                0
# # ... with 20 more rows