31  Conversion Monthly to Weekly bucket customized

Let’s upload the libraries we’re going to use :

# ETL
library(tidyverse)

# Charts
library(highcharter)

# Tables
library(gt)

# Supply Chain
library(planr)

We’re going to present here how to use the month_to_weekx() function from the R package planr.

This function allows to :

We need a data frame with the 3 variables to use this function :

And also 4 variables, which are coefficients :

32 Demo dataset

Let’s create a data frame with 4 products (A, B, C , D) with an identical Demand expressed in monthly bucket.

We’re going to transform the Monthly Demand into Weekly Bucket, using as example 4 types of distributions :

  • demand evenly distributed among each week of the month.

  • demand following a “L pattern” (occurring mainly during the beginning of the month).

  • demand following a “J pattern” (occurring mainly during the end of the month).

  • demand following a random pattern (with some peaks during some weeks).

Let’s assemble the demand of those 4 products :

32.1 Even pattern

It will be our Product A.

#--------------------------------
# Input values for the test
#--------------------------------

# Create a vector of Monthly Period
Period <- c("2023-06-01", "2023-07-01", "2023-08-01")


# Create a vector of Demand
Demand <- c(1000, 2000, 1000)


# assemble
input <- data.frame(Period,
                      Demand)

# let's add a Product
input$DFU <- "Product A"

# format the Period as a date
input$Period <- as.Date(as.character(input$Period), format = '%Y-%m-%d')



# define weekly distribution values
input$W1 <- 0.25
input$W2 <- 0.25
input$W3 <- 0.25
input$W4 <- 0.25


# keep results
input_ProdA <- input

glimpse(input_ProdA)
Rows: 3
Columns: 7
$ Period <date> 2023-06-01, 2023-07-01, 2023-08-01
$ Demand <dbl> 1000, 2000, 1000
$ DFU    <chr> "Product A", "Product A", "Product A"
$ W1     <dbl> 0.25, 0.25, 0.25
$ W2     <dbl> 0.25, 0.25, 0.25
$ W3     <dbl> 0.25, 0.25, 0.25
$ W4     <dbl> 0.25, 0.25, 0.25

32.2 L pattern

This will be the Product B.

#--------------------------------
# Input values for the test
#--------------------------------

# Create a vector of Monthly Period
Period <- c("2023-06-01", "2023-07-01", "2023-08-01")


# Create a vector of Demand
Demand <- c(1000, 2000, 1000)


# assemble
input <- data.frame(Period,
                      Demand)

# let's add a Product
input$DFU <- "Product B"

# format the Period as a date
input$Period <- as.Date(as.character(input$Period), format = '%Y-%m-%d')


# define weekly distribution values
input$W1 <- 0.75
input$W2 <- 0.15
input$W3 <- 0.05
input$W4 <- 0.05


# keep results
input_ProdB <- input

glimpse(input_ProdB)
Rows: 3
Columns: 7
$ Period <date> 2023-06-01, 2023-07-01, 2023-08-01
$ Demand <dbl> 1000, 2000, 1000
$ DFU    <chr> "Product B", "Product B", "Product B"
$ W1     <dbl> 0.75, 0.75, 0.75
$ W2     <dbl> 0.15, 0.15, 0.15
$ W3     <dbl> 0.05, 0.05, 0.05
$ W4     <dbl> 0.05, 0.05, 0.05

32.3 J pattern

It will be Product C.

#--------------------------------
# Input values for the test
#--------------------------------

# Create a vector of Monthly Period
Period <- c("2023-06-01", "2023-07-01", "2023-08-01")


# Create a vector of Demand
Demand <- c(1000, 2000, 1000)


# assemble
input <- data.frame(Period,
                      Demand)

# let's add a Product
input$DFU <- "Product C"

# format the Period as a date
input$Period <- as.Date(as.character(input$Period), format = '%Y-%m-%d')


# define weekly distribution values
input$W1 <- 0.05
input$W2 <- 0.05
input$W3 <- 0.15
input$W4 <- 0.75


# keep results
input_ProdC <- input

glimpse(input_ProdC)
Rows: 3
Columns: 7
$ Period <date> 2023-06-01, 2023-07-01, 2023-08-01
$ Demand <dbl> 1000, 2000, 1000
$ DFU    <chr> "Product C", "Product C", "Product C"
$ W1     <dbl> 0.05, 0.05, 0.05
$ W2     <dbl> 0.05, 0.05, 0.05
$ W3     <dbl> 0.15, 0.15, 0.15
$ W4     <dbl> 0.75, 0.75, 0.75

32.4 Random pattern

We will associate it to the Product D.

#--------------------------------
# Input values for the test
#--------------------------------

# Create a vector of Monthly Period
Period <- c("2023-06-01", "2023-07-01", "2023-08-01")


# Create a vector of Demand
Demand <- c(1000, 2000, 1000)


# assemble
input <- data.frame(Period,
                      Demand)

# let's add a Product
input$DFU <- "Product D"

# format the Period as a date
input$Period <- as.Date(as.character(input$Period), format = '%Y-%m-%d')


# define weekly distribution values
input$W1 <- 0.5
input$W2 <- 0.1
input$W3 <- 0.3
input$W4 <- 0.1


# keep results
input_ProdD <- input

glimpse(input_ProdD)
Rows: 3
Columns: 7
$ Period <date> 2023-06-01, 2023-07-01, 2023-08-01
$ Demand <dbl> 1000, 2000, 1000
$ DFU    <chr> "Product D", "Product D", "Product D"
$ W1     <dbl> 0.5, 0.5, 0.5
$ W2     <dbl> 0.1, 0.1, 0.1
$ W3     <dbl> 0.3, 0.3, 0.3
$ W4     <dbl> 0.1, 0.1, 0.1

Assemble

Now let’s combine the demand and weekly distribution values of those 4 products into one data frame that we will call input .

df1 <- rbind(input_ProdA, input_ProdB, input_ProdC, input_ProdD)

# keep results
input <- df1

input
       Period Demand       DFU   W1   W2   W3   W4
1  2023-06-01   1000 Product A 0.25 0.25 0.25 0.25
2  2023-07-01   2000 Product A 0.25 0.25 0.25 0.25
3  2023-08-01   1000 Product A 0.25 0.25 0.25 0.25
4  2023-06-01   1000 Product B 0.75 0.15 0.05 0.05
5  2023-07-01   2000 Product B 0.75 0.15 0.05 0.05
6  2023-08-01   1000 Product B 0.75 0.15 0.05 0.05
7  2023-06-01   1000 Product C 0.05 0.05 0.15 0.75
8  2023-07-01   2000 Product C 0.05 0.05 0.15 0.75
9  2023-08-01   1000 Product C 0.05 0.05 0.15 0.75
10 2023-06-01   1000 Product D 0.50 0.10 0.30 0.10
11 2023-07-01   2000 Product D 0.50 0.10 0.30 0.10
12 2023-08-01   1000 Product D 0.50 0.10 0.30 0.10

This data frame has 7 variables :

  • 3 variables related to the Monthly Demand :

    • a Product: it’s an item, a SKU (Storage Keeping Unit), or a SKU at a location, also called a DFU (Demand Forecast Unit).

    • a Period of time : here in monthly buckets only.

    • a Demand : could be some sales forecasts, expressed in units.

And also 4 variables, which are coefficients :

  • W1 : percentage of Demand of the month occurring during the first week.

  • W2 : percentage of Demand of the month occurringduring the second week.

  • W3 : percentage of Demand of the month occurring during the third week.

  • W4 : percentage of Demand of the month occurring during the fourth week.

It’s the template that we will use to apply the function month_to_weekx() and split the monthly demand into weekly bucket, with a customized weekly distribution.

For each product, the monthly demand is the same, only the weekly coefficients change.

33 Summary Table

We could summarize those weekly patterns into the following table.

To illustrate it, we display a nanoplots Table, using the library gt . We create first a data frame, and then display it using through gt table.

# create vectors
pattern <- c("even distribution", "L pattern", "J pattern", "random")

W1 <- c(0.25, 0.75, 0.05, 0.5)
W2 <- c(0.25, 0.15, 0.05, 0.1)
W3 <- c(0.25, 0.05, 0.15, 0.3)
W4 <- c(0.25, 0.05, 0.75, 0.1)

# create a data frame
patterns_data <- data.frame(pattern,
                            W1,
                            W2,
                            W3,
                            W4)

# display table
patterns_data
            pattern   W1   W2   W3   W4
1 even distribution 0.25 0.25 0.25 0.25
2         L pattern 0.75 0.15 0.05 0.05
3         J pattern 0.05 0.05 0.15 0.75
4            random 0.50 0.10 0.30 0.10

Now let’s display the nanoplots Table :

patterns_data |>
  gt(rowname_col = "pattern") |>
  tab_header("Examples of Weekly Distribution patterns") |>
  tab_stubhead(label = md("**Pattern**")) |>
  #cols_hide(columns = c(starts_with("norm"), units)) |>
  cols_nanoplot(
    columns = starts_with("W"),
    new_col_name = "nanoplots",
    new_col_label = md("*Distribution*")
  ) |>
  cols_align(align = "center", columns = nanoplots) |>
  tab_footnote(
    footnote = "Sales Forecasts from Week1 through Week4.",
    locations = cells_column_labels(columns = nanoplots)
  )
Examples of Weekly Distribution patterns
Pattern Distribution1
even distribution
0.30 0.20 0.25 0.25 0.25 0.25
L pattern
0.75 0.050 0.75 0.15 0.050 0.050
J pattern
0.75 0.050 0.050 0.050 0.15 0.75
random
0.50 0.10 0.50 0.10 0.30 0.10
1 Sales Forecasts from Week1 through Week4.

Our example will create those 4 different patterns of weekly distribution.

34 Transform into Weekly Buckets

We now apply the month_to_weekx() function to the demo dataset input.

It will transform the Demand initially expressed in monthly buckets into weekly buckets, following the weekly coefficients W1 | W2 | W3 | W4 .

# calculate
df1 <- planr::month_to_weekx(dataset = input,
                             DFU = DFU,
                             W1 = W1,
                             W2 = W2,
                             W3 = W3,
                             W4 = W4,
                             Period = Period,
                             Demand = Demand
                             )

# keep results
calculated_data <- df1

# display results
head(calculated_data)
        DFU     Period   Demand
1 Product A 2023-05-28 107.1429
2 Product A 2023-06-04 250.0000
3 Product A 2023-06-11 250.0000
4 Product A 2023-06-18 250.0000
5 Product A 2023-06-25 214.2857
6 Product A 2023-07-02 500.0000

We obtain a period of time now in weekly bucket, and its associated weekly demand.

Let’s look at it through 4 different charts, one for each pattern.

35 Charts Weekly Demand

35.1 Even pattern

This is the Product A. The monthly demand is evenly split across the different weeks of the month.

# select Product A
df1 <- calculated_data |> filter(DFU == "Product A")

# chart
highchart() |> 
  
  hc_add_series(name = "Weekly Demand", 
                color = "mediumseagreen",
                type = 'spline',
                #dataLabels = list(align = "center", enabled = TRUE),
                data = df1$`Demand`) |> 
  
  hc_title(text = "Even Distribution") |>
  hc_subtitle(text = "in units") |> 
  
  hc_xAxis(categories = df1$Period) |>
  hc_add_theme(hc_theme_google())

35.2 L pattern

This is the Product B. The weekly demand shows higher volumes at the beginning of the month.

# select Product B
df1 <- calculated_data |> filter(DFU == "Product B")

# chart
highchart() |> 
  
  hc_add_series(name = "Weekly Demand", 
                color = "salmon",
                type = 'spline',
                #dataLabels = list(align = "center", enabled = TRUE),
                data = df1$`Demand`) |> 
  
  hc_title(text = "L Pattern") |>
  hc_subtitle(text = "in units") |> 
  
  hc_xAxis(categories = df1$Period) |>
  hc_add_theme(hc_theme_google())

35.3 J pattern

This is the Product C. The weekly demand shows higher volumes at the end of the month.

# select Product B
df1 <- calculated_data |> filter(DFU == "Product C")

# chart
highchart() |> 
  
  hc_add_series(name = "Weekly Demand", 
                color = "steelblue",
                type = 'spline',
                #dataLabels = list(align = "center", enabled = TRUE),
                data = df1$`Demand`) |> 
  
  hc_title(text = "J Pattern") |>
  hc_subtitle(text = "in units") |> 
  
  hc_xAxis(categories = df1$Period) |>
  hc_add_theme(hc_theme_google())

35.4 Random pattern

This is the Product D. The weekly demand follows the custom weekly pattern that we defined.

# select Product D
df1 <- calculated_data |> filter(DFU == "Product D")

# chart
highchart() |> 
  
  hc_add_series(name = "Weekly Demand", 
                color = "gold",
                type = 'spline',
                #dataLabels = list(align = "center", enabled = TRUE),
                data = df1$`Demand`) |> 
  
  hc_title(text = "Random Pattern") |>
  hc_subtitle(text = "in units") |> 
  
  hc_xAxis(categories = df1$Period) |>
  hc_add_theme(hc_theme_google())

Choosing the appropriate distribution pattern when converting the Demand from Monthly into Weekly bucket can provide a more accurate calculation of :

  • projected inventories & coverages.

  • replenishment plan.