Fallstudie 4: Kapazitäts- und Lagerbestandspooling

SushiFresh-Übungen und Zentral- oder Regionallager für einen brasilianischen Online-Marktplatz (Olist-Daten)

Autor:in

Supply Chain Management – Gruppenarbeit

HinweisSteckbrief
Thema Kapazitätspooling, Sicherheitsbestand, Lagerbestandspooling (Zentralisierung), Einfluss der Korrelation
Vorlesungsbezug Block 3 „Unsicherheits- und Risikomanagement in Supply Chains“: Kapazitäts- & Lagerbestandspooling
Teil 1 Klausurvorbereitung: Aufgaben mit Stift und Papier zu einer neuen SushiFresh-Entscheidungssituation (25–30 Min.)
Teil 2 Datenbasierte Fallstudie mit realen Bestelldaten (Brazilian E-Commerce Public Dataset by Olist, Kaggle)
Gruppengröße 3–6 Personen (Teil 2)
Ergebnis Präsentation (20 Min.) + Diskussion (10 Min.), Foliensatz (PDF) und reproduzierbarer R-/Quarto-Code

1 Lernziele

Nach Bearbeitung der Übungen und der Fallstudie können Sie

  • den Nutzen flexibler Kapazitäten (Kapazitätspooling) an Auslastung und Lieferservice messen,
  • Sicherheitsbestände für einen α-Servicegrad bei dezentraler und zentraler Lagerung berechnen,
  • das Quadratwurzelgesetz anwenden und erklären, wie Korrelation und ungleich große Standorte den Pooling-Effekt verändern, und
  • den Pooling-Vorteil gegen Transportkosten und Lieferzeiten abwägen.

2 Teil 1 – Klausurvorbereitung: Lachsbestände und Küchenkapazität im Rhein-Neckar-Gebiet

HinweisHinweise

Bearbeitungszeit ca. 25 Minuten · Hilfsmittel: nicht programmierbarer Taschenrechner · 25 Punkte · \(z_{0{,}95} = 1{,}645\)

Situation A – Kapazitätspooling. SushiFresh betreibt in Mannheim und Heidelberg je eine kleine Küche mit einer Kapazität von 100 Boxen pro Tag. Bisher beliefert jede Küche nur „ihre“ Filiale. Nicht lieferbare Nachfrage geht verloren. Die Nachfrage einer typischen Woche:

Tag Mo Di Mi Do Fr Sa
Filiale Mannheim 80 120 95 110 70 105
Filiale Heidelberg 115 85 100 90 120 95

Aufgabe 1 (8 Punkte).

  1. Berechnen Sie für beide Küchen die Auslastung und die verlorene Nachfrage (Lost Sales) der Woche sowie den Lieferservicegrad (gelieferte / nachgefragte Menge) jeder Filiale.

  2. Beide Küchen dürfen künftig beide Filialen beliefern (vollständige Flexibilität). Wie viel Nachfrage geht jetzt noch verloren? Wie hoch ist die Auslastung?

  1. Getrennte Küchen (Kapazität je 100):
Tag Mo Di Mi Do Fr Sa Summe
Lieferung Mannheim 80 100 95 100 70 100 545
Lieferung Heidelberg 100 85 100 90 100 95 570
Küche Mannheim Küche Heidelberg
Auslastung 545/600 = 90,8 % 570/600 = 95,0 %
Lost Sales 580 − 545 = 35 605 − 570 = 35
Lieferservicegrad 545/580 = 94,0 % 570/605 = 94,2 %
  1. Mit vollständiger Flexibilität steht eine Kapazität von 200 je Tag für die Gesamtnachfrage zur Verfügung:
Tag Mo Di Mi Do Fr Sa
Gesamtnachfrage 195 205 195 200 190 200

Nur am Dienstag gehen 5 Boxen verloren (statt 70). Die Auslastung steigt auf 1.180/1.200 = 98,3 %. Ausgeglichen wird, dass die Spitzen der beiden Filialen an unterschiedlichen Tagen auftreten.

Bewertung: a) 5 Punkte, b) 3 Punkte.

Situation B – Lagerbestandspooling. Der frische Lachs wird bisher in den vier Rhein-Neckar-Filialen gelagert. Die Tagesnachfrage (kg) ist normalverteilt und unabhängig:

Filiale Mannheim Ludwigshafen Heidelberg Weinheim
\(\mu\) [kg/Tag] 200 100 150 50
\(\sigma\) [kg/Tag] 40 30 30 20

Aufgabe 2 (9 Punkte).

  1. Berechnen Sie den Sicherheitsbestand für einen α-Servicegrad von 95 % bei dezentraler Lagerung (je Filiale und gesamt) und bei Lagerung in einem Zentrallager.

  2. Um wie viel Prozent sinkt der Sicherheitsbestand? Vergleichen Sie mit dem Quadratwurzelgesetz für vier gleich große Filialen (\(1 - 1/\sqrt{4}\)) und erklären Sie den Unterschied.

  1. Dezentral: \(SB_i = 1{,}645 \cdot \sigma_i\)
MA LU HD WH Summe
\(SB_i\) [kg] 65,8 49,4 49,4 32,9 197,4

Zentral: \(\sigma_Z = \sqrt{40^2 + 30^2 + 30^2 + 20^2} = \sqrt{3.800} = 61{,}6\) kg, also $SB_Z = 1{,}645 6 = $ 101,4 kg.

  1. Einsparung: \(1 - 101{,}4/197{,}4 = 48{,}6\,\%\). Das Quadratwurzelgesetz verspricht bei vier gleich großen Filialen \(1 - 1/\sqrt 4 = 50\,\%\). Die Einsparung ist kleiner, weil die Filialen ungleich groß sind: Die große Filiale Mannheim dominiert die Gesamtstreuung und profitiert kaum vom Ausgleich.

Bewertung: a) 6 Punkte, b) 3 Punkte.

Aufgabe 3 (5 Punkte). Die Nachfragen in Mannheim und Ludwigshafen sind korreliert (Fußballspiele, Wetter). Berechnen Sie den gemeinsamen Sicherheitsbestand dieser beiden Filialen für \(\rho = -0{,}5\), \(\rho = 0\) und \(\rho = 0{,}5\). Was bedeutet das für die Entscheidung über ein gemeinsames Lager?

\(SB = 1{,}645 \cdot \sqrt{40^2 + 30^2 + 2 \rho \cdot 40 \cdot 30}\):

\(\rho\) −0,5 0 0,5 dezentral
\(\sigma\) [kg] 36,1 50,0 60,8 70
\(SB\) [kg] 59,3 82,3 100,1 115,2

Je höher die Korrelation, desto kleiner die Einsparung. Bei \(\rho = 1\) gäbe es keinen Pooling-Vorteil mehr. Gemeinsame Einflüsse wie Fußballspiele oder Wetter verringern also den Nutzen eines gemeinsamen Lagers.

Bewertung: 3 Punkte Rechnung, 2 Punkte Interpretation.

Aufgabe 4 (3 Punkte). Nennen Sie zwei Nachteile der Zentralisierung, die in der Rechnung fehlen.

Zum Beispiel: längere Transportwege und höhere Transportkosten zu den Filialen, längere Lieferzeit bzw. geringere Frische (kritisch bei Lachs), zusätzliche Umschlagvorgänge mit Risiko für die Kühlkette, Abhängigkeit von einem einzigen Standort (Ausfallrisiko).

Bewertung: 1,5 Punkte je Nachteil.

3 Teil 2 – Fallstudie: Risk Pooling im E-Commerce

3.1 Ausgangslage

Olist ist ein brasilianischer Online-Marktplatz, über den kleine und mittlere Händler ihre Produkte auf großen Verkaufsplattformen anbieten. Bisher versenden die Händler selbst, die meisten aus dem Bundesstaat São Paulo. Kundinnen und Kunden im Norden und Nordosten warten deshalb oft zwei bis drei Wochen und zahlen deutlich höhere Frachtkosten.

Das Management prüft den Aufbau eines eigenen Fulfillment-Netzes. Für die umsatzstärksten Produktkategorien stehen drei Strukturen zur Diskussion:

  • Struktur Z (zentral): ein Fulfillment-Center in Cajamar (Großraum São Paulo) beliefert ganz Brasilien.
  • Struktur R (regional): fünf Regionallager, je eines pro Großregion: Cajamar (Sudeste), Curitiba (Sul), Goiânia (Centro-Oeste), Recife (Nordeste) und Belém (Norte).
  • Struktur H (hybrid): Cajamar für Sudeste, Sul und Centro-Oeste sowie Recife für Nordeste und Norte.

3.2 Daten

Brazilian E-Commerce Public Dataset by Olist (Kaggle, Lizenz CC BY-NC-SA 4.0): https://www.kaggle.com/datasets/olistbr/brazilian-ecommerce

Rund 100.000 echte, anonymisierte Bestellungen aus den Jahren 2016 bis 2018. Sie benötigen fünf der neun Tabellen:

Datei Relevante Spalten
olist_orders_dataset.csv order_id, customer_id, order_status, order_purchase_timestamp
olist_order_items_dataset.csv order_id, product_id, price, freight_value (eine Zeile je Artikel)
olist_customers_dataset.csv customer_id, customer_state (Bundesstaat)
olist_products_dataset.csv product_id, product_category_name
product_category_name_translation.csv Übersetzung der Kategorienamen ins Englische
WichtigHinweise zur Datenaufbereitung
  • Nachfrage = Anzahl bestellter Artikel je Woche, Region und Kategorie; stornierte und nicht verfügbare Bestellungen ausschließen.
  • Zeitraum 02.01.2017 bis 20.08.2018 (86 Wochen); Konzentration auf die 5 größten Produktkategorien.
  • Das Geschäft wächst stark, im November gibt es einen Ausschlag (Black Friday). Verwenden Sie deshalb den Prognosefehler eines gleitenden Durchschnitts (8 Wochen) als Maß der Unsicherheit, nicht die Rohstreuung.

3.3 Planungsparameter

Parameter Wert
Hochrechnung Mengen und Standardabweichungen mit dem Faktor 50 auf das geplante Volumen hochrechnen
Zielservicegrad (α) 95 %
Wiederbeschaffungszeit Händler → Lager 2 Wochen
Warenwert 60 % des Verkaufspreises (price)
Lagerhaltungskostensatz 25 % p. a. vom Warenwert
Fixkosten je Lager (anteilig) Cajamar: 2,0 Mio. BRL/Jahr, jedes weitere Lager: 0,9 Mio. BRL/Jahr

3.4 Aufgaben

3.4.1 Teil A – Datenaufbereitung

A1. Verknüpfen Sie die Tabellen und erzeugen Sie für die 5 größten Kategorien die wöchentliche Artikelnachfrage je Region. Beschreiben Sie die Verteilung der Nachfrage auf die Regionen und stellen Sie die durchschnittlichen Frachtkosten (freight_value) je Region dar.

3.4.2 Teil B – Lagerbestandspooling

B1. Berechnen Sie je Kategorie den Sicherheitsbestand \(SB = z_\alpha\,\sigma\sqrt{L}\) in den Strukturen Z, R und H, und zwar (a) unter der Annahme unabhängiger Regionen und (b) mit der empirischen Kovarianzmatrix der Prognosefehler, \(\sigma_{\text{pool}} = \sqrt{\mathbf 1^\top \Sigma\,\mathbf 1}\) (siehe Startercode). Warum fällt der Pooling-Effekt kleiner aus, als das Quadratwurzelgesetz mit \(\sqrt{5}\) verspricht?

B2. Bewerten Sie die Sicherheitsbestände mit Warenwert und Lagerhaltungskostensatz und stellen Sie sie den Fixkosten der Lager gegenüber. Ab welchem Bestandskostenvorteil würde sich ein zusätzliches Lager allein aus Bestandssicht lohnen?

3.4.3 Teil C – Empfehlung und Reflexion

C1. Formulieren Sie eine Empfehlung an das Olist-Management. Berücksichtigen Sie neben den Kosten die Lieferzeit und die Frachtkosten als Wettbewerbsfaktor.

C2. Reflexion. Beantworten Sie in der Präsentation:

  1. Wie gut beschreibt das Quadratwurzelgesetz die realen Daten? Was lernen Sie über die Anwendung von Lehrbuchformeln auf reale Daten?
  2. Der Pooling-Vorteil ist vermutlich klein im Vergleich zu Fracht und Lieferzeit. Was bedeutet das für Bestandsargumente bei Netzwerkentscheidungen?
  3. Die Daten zeigen Bestellungen, nicht die Nachfrage, die bei kürzeren Lieferzeiten entstanden wäre. Wie könnte ein Regionallager im Nordosten die Nachfrage selbst verändern?

4 Literatur

  • Olist (2018): Brazilian E-Commerce Public Dataset by Olist. Kaggle, https://www.kaggle.com/datasets/olistbr/brazilian-ecommerce.
  • Eppen, G. D. (1979): Effects of Centralization on Expected Costs in a Multi-Location Newsboy Problem. Management Science 25(5), 498–501.
  • Folien und Reader zur Vorlesung, Block 3.

5 Anhang: R-Startercode

Code
library(tidyverse)
source("../R/scm_functions.R")   # pooling_safety_stock()

pfad   <- "olist/"   # Ordner mit den entpackten CSV-Dateien
orders <- read_csv(paste0(pfad, "olist_orders_dataset.csv"))
items  <- read_csv(paste0(pfad, "olist_order_items_dataset.csv"))
cust   <- read_csv(paste0(pfad, "olist_customers_dataset.csv"))
prod   <- read_csv(paste0(pfad, "olist_products_dataset.csv"))
transl <- read_csv(paste0(pfad, "product_category_name_translation.csv"))
names(transl)[1] <- "product_category_name"   # entfernt ggf. ein BOM-Zeichen

regionen <- tibble(
  customer_state = c("AC","AP","AM","PA","RO","RR","TO",
                     "AL","BA","CE","MA","PB","PE","PI","RN","SE",
                     "DF","GO","MT","MS",
                     "ES","MG","RJ","SP",
                     "PR","RS","SC"),
  region = c(rep("Norte", 7), rep("Nordeste", 9), rep("Centro-Oeste", 4),
             rep("Sudeste", 4), rep("Sul", 3))
)

daten <- items |>
  inner_join(orders, by = "order_id") |>
  filter(!order_status %in% c("canceled", "unavailable")) |>
  inner_join(cust, by = "customer_id") |>
  left_join(prod, by = "product_id") |>
  left_join(transl, by = "product_category_name") |>
  left_join(regionen, by = "customer_state") |>
  mutate(kategorie = product_category_name_english,
         woche = floor_date(as_date(order_purchase_timestamp), "week", week_start = 1)) |>
  filter(woche >= as.Date("2017-01-02"), woche <= as.Date("2018-08-20"))

top5 <- daten |> count(kategorie, sort = TRUE) |> slice_head(n = 5) |> pull(kategorie)

wochen <- daten |>
  filter(kategorie %in% top5) |>
  count(kategorie, region, woche, name = "menge") |>
  complete(kategorie, region, woche, fill = list(menge = 0))

# Beispiel: Prognosefehler (gleitender Durchschnitt über 8 Wochen) für eine Kategorie
fehler <- wochen |>
  filter(kategorie == top5[1]) |>
  group_by(region) |> arrange(woche) |>
  mutate(prognose = lag(zoo::rollmeanr(menge, 8, fill = NA)),
         fehler   = 50 * (menge - prognose)) |>          # Hochrechnung Faktor 50
  ungroup() |> drop_na(fehler) |>
  select(woche, region, fehler) |>
  pivot_wider(names_from = region, values_from = fehler)

Sigma <- cov(as.matrix(fehler[, -1]))
z <- qnorm(0.95); L <- 2
c(SB_regional = sum(z * sqrt(diag(Sigma)) * sqrt(L)),
  SB_zentral  = z * sqrt(sum(Sigma)) * sqrt(L))