R语言planr包进行库存分析

R语言
数据分析
使用R语言planr包进行库存分析
作者

不止BI

发布于

2024年11月23日

planr是一个用于进行R语言库存分析的R包,它可以帮助用户更好地理解和管理库存数据。

单件商品的库存分析

代码
# install.packages('planr')
library(tidyverse)
library(reactable)
library(reactablefmtr)
library(plotly)
library(highcharter)
library(planr)

数据准备

blueprintplanr包中的一个数据集,它包含了一些商品的库存数据。这里我们使用一个单件商品的例子,即Item 000001,选取DFU、Period、Demand、Opening、Supply这5个变量

代码
df_plan_item_000001 <- blueprint |>
  filter(DFU == "Item 000001") |>
  select(DFU, Period, Demand, Opening, Supply)
df_plan_item_000001 |> head()
# A tibble: 6 × 5
  DFU         Period     Demand Opening Supply
  <chr>       <date>      <dbl>   <dbl>  <dbl>
1 Item 000001 2022-07-03    364    6570      0
2 Item 000001 2022-07-10    364       0      0
3 Item 000001 2022-07-17    364       0      0
4 Item 000001 2022-07-24    260       0      0
5 Item 000001 2022-07-31    736       0      0
6 Item 000001 2022-08-07    859       0      0

预估

light_proj_inv是planr包中的一个函数,用于预估期末库存水平(Projected.Inventories.Qty)周期覆盖范围(Calculated.Coverage.in.Periods)

代码
df_inv_proj <- light_proj_inv(dataset = df_plan_item_000001, DFU = DFU, Period = Period, Demand = Demand, Opening = Opening, Supply = Supply)
df_inv_proj |> head()
          DFU     Period Demand Opening Calculated.Coverage.in.Periods
1 Item 000001 2022-07-03    364    6570                           16.8
2 Item 000001 2022-07-10    364       0                           15.8
3 Item 000001 2022-07-17    364       0                           14.8
4 Item 000001 2022-07-24    260       0                           13.8
5 Item 000001 2022-07-31    736       0                           12.8
6 Item 000001 2022-08-07    859       0                           11.8
  Projected.Inventories.Qty Supply
1                      6206      0
2                      5842      0
3                      5478      0
4                      5218      0
5                      4482      0
6                      3623      0

展示

使用reactable包展示预估库存水平及覆盖范围

代码
df_inv_proj <- df_inv_proj |>
  select(
    Period,
    Demand,
    Calculated.Coverage.in.Periods,
    Projected.Inventories.Qty,
    Supply
  ) |>
  mutate(f_colorpal = case_when(
    Calculated.Coverage.in.Periods > 6 ~ "#32CD32",
    Calculated.Coverage.in.Periods > 2 ~ "#FFFF99",
    Calculated.Coverage.in.Periods > 0 ~ "#FFA500",
    TRUE ~ "#FF0000"
  ))
df_inv_proj |>
  reactable(
    resizable = TRUE, showPageSizeOptions = TRUE,
    striped = TRUE, highlight = TRUE, compact = TRUE,
    defaultPageSize = 20,
    columns = list(
      Demand = colDef(
        name = "需求",
        cell = data_bars(df_inv_proj,
          fill_color = "#3fc1c9",
          text_position = "outside-end"
        )
      ),
      Calculated.Coverage.in.Periods = colDef(
        name = "覆盖期数",
        maxWidth = 90,
        cell = color_tiles(df_inv_proj, color_ref = "f_colorpal")
      ),
      f_colorpal = colDef(show = FALSE),
      `Projected.Inventories.Qty` = colDef(
        name = "预计库存",
        format = colFormat(separators = TRUE, digits = 0),
        style = function(value) {
          if (value > 0) {
            color <- "#008000"
          } else if (value < 0) {
            color <- "#e00000"
          } else {
            color <- "#777"
          }
          list(
            color = color
            # fontWeight = "bold"
          )
        }
      ),
      Supply = colDef(
        name = "供应",
        cell = data_bars(df_inv_proj,
          fill_color = "#3CB371",
          text_position = "outside-end"
        )
      )
    ),
    columnGroups = list(
      colGroup(name = "预估", columns = c(
        "Calculated.Coverage.in.Periods",
        "Projected.Inventories.Qty"
      ))
    )
  )
预估
Period
需求
覆盖期数
预计库存
供应
2022-07-03
364
16.8
6,206
0
2022-07-10
364
15.8
5,842
0
2022-07-17
364
14.8
5,478
0
2022-07-24
260
13.8
5,218
0
2022-07-31
736
12.8
4,482
0
2022-08-07
859
11.8
3,623
0
2022-08-14
859
10.8
2,764
0
2022-08-21
859
9.8
1,905
0
2022-08-28
273
8.8
1,632
0
2022-09-04
349
7.8
1,283
0
2022-09-11
349
6.8
934
0
2022-09-18
349
5.8
585
0
2022-09-25
200
4.8
385
0
2022-10-02
14
3.8
371
0
2022-10-09
25
10.8
5,346
5000
2022-10-16
32
9.8
5,314
0
2022-10-23
17
8.8
5,297
0
2022-10-30
367
7.8
4,930
0
2022-11-06
514
6.8
4,416
0
2022-11-13
514
5.8
3,902
0
1–20 of 52 rows
Show

使用柱形图展示库存及短缺情况

代码
df_inv_proj |>
  transmute(
    Period, Projected.Inventories.Qty,
    IsStocked = case_when(Projected.Inventories.Qty > 0 ~ "库存", TRUE ~ "短缺")
  ) |>
  ggplot(aes(x = Period, y = Projected.Inventories.Qty, fill = IsStocked)) +
  geom_bar(stat = "identity") +
  labs(x = "时间", y = "库存/短缺", fill = "库存/短缺", title = "库存/短缺情况") +
  theme_minimal() +
  scale_fill_manual(values = c("库存" = "#008000", "短缺" = "#e00000")) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_date(date_labels = "%Y-%m")

多DFU分析

针对多个DFU进行分析,我们可以构建一个表格来分析一段时间内的库存情况

代码
df_mutil_dfu <- blueprint |>
  filter(Period <= "2022-09-25") |>
  light_proj_inv(DFU = DFU, Period = Period, Demand = Demand, Opening = Opening, Supply = Supply) |>
  group_by(DFU) |>
  summarise(
    DemandList = list(Demand),
    SupplyList = list(Supply),
    Demand = sum(Demand),
    Supply = sum(Supply),
    Opening = sum(Opening),
    IsDelay = if_else(min(Projected.Inventories.Qty) <= 0, "Delay", "OK"),
    PIQuantity = list(Projected.Inventories.Qty)
  ) |>
  ungroup() |>
  mutate(DemandPercent = Demand / sum(Demand))
代码
library(sparkline)
library(htmltools)

status_badge <- function(color = "#aaa", width = "9px", height = width) {
  span(style = list(
    display = "inline-block",
    marginRight = "8px",
    width = width,
    height = height,
    backgroundColor = color,
    borderRadius = "50%"
  ))
}

df_mutil_dfu |>
  reactable(
    compact = TRUE,
    defaultSortOrder = "desc",
    defaultSorted = c("Demand"),
    defaultPageSize = 20,
    columns = list(
      `DFU` = colDef(name = "DFU"),
      `Demand` = colDef(
        name = "总需求",
        aggregate = "sum", footer = function(values) formatC(sum(values), format = "f", big.mark = ",", digits = 0),
        format = colFormat(separators = TRUE, digits = 0),
        style = list(background = "yellow", fontWeight = "bold")
      ),
      `DemandPercent` = colDef(
        name = "需求占比",
        format = colFormat(percent = TRUE, digits = 1)
      ), # close %
      `Supply` = colDef(
        name = "总供应",
        aggregate = "sum", footer = function(values) formatC(sum(values), format = "f", big.mark = ",", digits = 0),
        format = colFormat(separators = TRUE, digits = 0)
      ),
      `Opening` = colDef(
        name = "期初库存",
        aggregate = "sum", footer = function(values) formatC(sum(values), format = "f", big.mark = ",", digits = 0),
        format = colFormat(separators = TRUE, digits = 0)
      ),
      DemandList = colDef(
        name = "预估需求",
        cell = function(values) {
          sparkline(values)
        }
      ), SupplyList = colDef(
        name = "预估供应",
        cell = function(values) {
          sparkline(values,
            type = "bar"
          )
        }
      ),
      PIQuantity = colDef(
        name = "预计库存",
        cell = function(values) {
          sparkline(values,
            type = "bar"
          )
        }
      ),
      IsDelay = colDef(
        name = "短缺风险",
        cell = function(value) {
          color <- switch(value,
            OK = "hsl(120,61%,50%)",
            Delay = "hsl(39,100%,50%)"
          )
          badge <- status_badge(color = color)
          tagList(badge, value)
        }
      )
    ),
    defaultColDef = colDef(footerStyle = list(fontWeight = "bold")),
    columnGroups = list(
      colGroup(
        name = "需求",
        columns = c(
          "Demand",
          "DemandPercent",
          "DemandList"
        )
      ),
      colGroup(
        name = "供应",
        columns = c("Supply", "SupplyList")
      ),
      colGroup(
        name = "库存",
        columns = c("Opening", "PIQuantity", "IsDelay")
      )
    )
  )
需求
供应
库存
DFU
预估需求
总需求
需求占比
预估供应
总供应
期初库存
短缺风险
预计库存
Item 000008
49,416
34.0%
27,000
17,500
Delay
Item 000005
29,700
20.5%
30,000
17,500
OK
Item 000002
18,458
12.7%
15,120
5,509
OK
Item 000006
17,846
12.3%
17,556
9,954
OK
Item 000004
12,336
8.5%
10,000
7,172
OK
Item 000001
6,185
4.3%
0
6,570
OK
Item 000010
5,190
3.6%
2,520
3,411
Delay
Item 000007
3,870
2.7%
2,593
2,092
OK
Item 000003
1,314
0.9%
0
2,494
OK
Item 000009
909
0.6%
0
1,222
OK

该表格可以清晰的展示哪些产品可能会出现负库存风险

回到顶部