rlinear-programmingpyomoequation-solving

How to allocate a product using R


I want to solve the following problem using R, and I am struggling to find a good way to do so.

I have a sales forecasts for two products (Product 1 & Product 2), of which there are 2 variations each (A & B).

Picture of dataframe of forecast sales

dat_forecast <- data.frame(
  product = c(1,1,2,2),
  variation = c("A", "B", "A", "B"),
  forecast_sales = c(612,238,741,455),
  ratio = c(0.72,0.28,0.6195652,0.3804348)
)

and I have data frame containing the current units in stock:

Picture of dataframe of units in stock

dat_stock <- data.frame(
  product = c(1,1,2,2),
  variation = c("A", "B", "A", "B"),
  current_stock = c(400,268,341,155),
  ratio = c(0.5988024,0.4011976,0.6875,0.3125)
)

Assume we wanted to produce another 100 units of Product 1 and another 200 units of Product 2. The task is to allocate the produced units of product to the different variations (A & B) in such a way, that the ratio of units in stock (highlighted in green) gets as close as possible to the ratio in the original forecast (highlighted in blue).

dat_to_be_produced <- data.frame(
  product = c(1,2),
  units = c(100,200)
)

What is the easiest way to solve this problem? Please note, in case for Product 1, there cannot be a precise solution as there is already more stock of Product 1 - Variation B than forecast (238 forecast, 268 in stock), so obviously one wouldn't allocate any more units to variation B in this case.

Any help as to how to solve this in R would be greatly appreciated.


Solution

  • In R you can use optimize() to find the minimum or max of a function.

    Here is a function that use optimize to allocate N units of product to A and B, given the initial stocks and the forecast. It uses optimize() to find the best number of units to allocate to "A", so that the resulting ratio is the closest to the forecasted one.

    allocate_units <- function(forecast,
                               stocks,
                               units) {
       
      get_error <- function(x) {
        target_ratio <- forecast[1]/sum(forecast)
        updated_stocks <- c(stocks[1]+x,stocks[2]+(units-x))
        ratio <- updated_stocks[1]/sum(updated_stocks)
        abs(target_ratio-ratio)
      }
      
      opt_As <- optimize(f = get_error, 
                         maximum = F, 
                         interval = c(0,units))
      
      As <- round(opt_As$minimum)
      Bs <- units - As
      
      c(A=As,B=Bs)
      
    }
    

    for example:

    allocate_units(forecast = c(A=612,B=238),
                   stocks = c(A=400,B=268),
                   units = 100)
    

    A = 100; B = 0

    allocate_units(forecast = c(A=741,B=455),
                   stocks = c(A=341,B=155),
                   units = 200)
    

    A = 90; B = 110