№ 01Hero
Case study, not a deployed production system

A decision intelligence engine for supply chain allocation

Supply Chain
Intelligence.

Reallocating 300 SKUs across 3 capacity-constrained warehouses using Monte Carlo demand simulation and a PuLP linear program at the P95 service level.

02
Intro

Most inventory decisions are still made on averages.

Most inventory decisions in mid-market e-commerce are still made on averages. A planner looks at last quarter's sales, divides by the number of warehouses, adds a buffer, and calls it a day. That works fine until demand does what demand actually does. It spikes in one region, collapses in another, and behaves nothing like the mean.

I wanted to see what happens if you stop pretending demand is a single number and start treating it as a distribution. So I built a decision-intelligence engine around a fairly straightforward premise: simulate what demand could look like next week for every SKU in every region, then let an optimizer figure out where to put the units, subject to the fact that warehouses have finite space and stockouts have real dollar costs.

This is a case study, not a live system. But the entire pipeline is reproducible end-to-end, and the tradeoffs it surfaces (which SKUs are constrained, which regions are structurally volatile, which categories eat penalty costs) are exactly the kind of thing a supply-chain team would want a Monday-morning dashboard to tell them.

03
TL;DR

The whole project in six lines.

Problem
Mid-market e-commerce operators running 2 to 4 regional warehouses can't answer a basic weekly question: given uncertain demand, how many units of each SKU should sit in each warehouse to minimize expected total cost (holding + stockout penalty) without violating capacity?
Data
Synthetic-but-realistic dataset: 300 SKUs × 3 warehouses (East, Central, West) × 3 regions × 2 years weekly, roughly 93,600 rows. Includes unit costs, holding cost per week, stockout penalty per unit, and per-warehouse capacity.
Approach
(1) EDA on volume and mix, (2) coefficient-of-variation analysis to segment SKUs by volatility, (3) regional volatility comparison, (4) financial EDA to quantify stockout exposure, (5) Monte Carlo simulation to build per-SKU demand distributions and extract P50 / P95 / P99, (6) PuLP linear program that allocates units to warehouses at the P95 service target subject to capacity constraints.
Key Findings
  • Weekly cost drops from $142K (naïve baseline) to $65K (optimized), a 54% reduction, ~$76.6K/week, ~$4M/year.
  • East region is ~30% more volatile than Central/West and drives most of the stockout risk.
  • 44 SKUs cannot be fully served at P95 given current warehouse capacity. These are the explicit expansion / renegotiation candidates.
  • Electronics category alone carries ~$83K/week in penalty exposure in the unoptimized scenario.
Tech Stack
Python · Pandas · NumPy · SciPy · PuLP · Matplotlib · Seaborn · Monte Carlo Simulation · Linear Programming · Jupyter
Case-study clarification
No deployment, no API, no dashboard in production. This is a reproducible analytical pipeline that demonstrates how the decision problem should be framed and solved. Everything runs from the notebooks in the repo.
04
What I actually built

A six-notebook pipeline, each stage feeding the next.

Step 1
01_basic_eda.ipynb

Volume & Mix

Loaded the 93,600-row weekly demand dataset. Broke down volume by region, warehouse, and category. Confirmed the dataset was clean, seasonally plausible, and had enough variance to make the problem non-trivial. Nothing fancy, but this is where I noticed the East warehouse was pulling disproportionate volume for its share of SKUs.
Step 2
02_demand_volatility.ipynb

Per-SKU CV Analysis

Computed the coefficient of variation (σ/μ) for every SKU across the 2-year window. The distribution came back bimodal. A cluster of stable, boring products and a long tail of chaotic, spike-prone ones. That immediately killed the idea of using a single global safety-stock rule.
Step 3
03_regional_volatility.ipynb

Regional Stability

Aggregated the same volatility analysis by region. East came in ~30% more volatile than Central and West. This finding didn't exist at the SKU level. It only showed up after regional aggregation. It's the reason East needs a fundamentally different service-level policy than the other two warehouses.
Step 4
04_financial_eda.ipynb

Dollarizing the Problem

Applied the per-unit holding costs and per-unit stockout penalties to actual demand. Result: the naïve mean-based allocation was leaking roughly $142K/week, with Electronics carrying ~$83K of that in penalty exposure alone. This turned "we have some stockouts" into "we have a categorized, quantified P&L problem."
Step 5
05_monte_carlo.ipynb

Probabilistic Demand Profiling

For each SKU × warehouse combination, ran 10,000-iteration Monte Carlo simulations to generate a demand distribution. Extracted P50, P95, and P99 quantiles. This is what replaces "next week we'll probably sell about X" with "there's a 95% chance we'll sell at most Y."
Step 6
06_optimization.ipynb

The LP

Built the PuLP linear program:
  • Decision variable: units of SKU i allocated to warehouse w for the coming week.
  • Objective: minimize holding_cost × allocated_units + expected_stockout_penalty × unmet_demand.
  • Constraints: (a) each warehouse's total allocation ≤ its physical capacity, (b) service-level target. Allocation must cover at least the P95 demand for each SKU wherever feasible.
  • Output: the per-SKU-per-warehouse allocation plan, plus a report of SKUs that couldn't be fully served under capacity.

The optimized plan cut modeled weekly cost from $142K to $65K.

05
Reality check

What actually happened. The honest layer.

This section is intentionally visually distinct. It's not marketing. It's the part I'd want to read if I were hiring me.

The first optimizer was wrong.

I initially wrote the LP without warehouse capacity constraints. It happily produced a "solution" that allocated 110%+ of physical capacity to two of the three warehouses. Beautiful cost number, physically impossible plan. Adding the capacity constraint is what turned it from a math exercise into a real decision tool.

44 SKUs still can't be fully served.

After the capacity constraint went in, the LP told me, correctly, that under current warehouse space, 44 SKUs cannot hit their P95 service target. That's not a bug; that's the actual answer. Those 44 SKUs are the business case for either a 4th warehouse, a 3PL contract, or a hard conversation with procurement.

Mean-based targets almost tricked me.

My first pass at "how much should we stock?" used mean demand plus a flat safety-stock percentage. The Monte Carlo output made it obvious that for volatile SKUs, mean + buffer systematically under-stocks and the penalty cost eats the savings. Switching to P95-based targets was the single biggest unlock in the whole project.

The East spike was invisible at the SKU level.

No single SKU in East looked scary on its own. It only became clear that East was ~30% more volatile than the other regions once I aggregated up. If I'd trusted the per-SKU view, I would have missed the biggest regional signal in the dataset.

The CV distribution was bimodal, not smooth.

I expected a nice long-tailed volatility distribution. What I got was two clumps: a "boring, predictable" cluster and a "chaotic" cluster, with almost nothing in between. That changed the framing from "tune one policy" to "run two policies."

This is a case study, not a system.

No orchestration, no scheduler, no live data feed, no UI. Someone taking this into production would need to wire it to actual ERP data, add rolling re-runs, and probably swap PuLP for a commercial solver at scale.

06
Modeling progression

Each step was a response to a specific failure in the previous step.

Baseline
Equal / Mean-Based Allocation

Divide expected weekly demand across the three warehouses roughly in proportion to historical share. No uncertainty modeling. This is the "planner in a spreadsheet" baseline.

Modeled weekly cost
~$142K
Intermediate
Mean + Flat Safety Stock

Same as baseline but add a fixed % buffer on top of mean demand per SKU. Reduces stockouts on average but over-stocks the stable SKUs and still under-stocks the volatile ones. Improved but structurally flawed for the bimodal volatility profile.

Modeled weekly cost
~$95 to $105K
Final
Monte Carlo P95 + Capacity-Constrained LP

Replace point estimates with simulated distributions. Target the 95th percentile of demand per SKU per warehouse. Let PuLP optimize allocation subject to real warehouse capacity.

Modeled weekly cost
~$65K

The Final plan lands at a 54% reduction vs. baseline. That progression matters more than the final number.

07
Trade-offs & design decisions

Every technical choice was a rejection of a plausible alternative.

Why Monte Carlo instead of a parametric distribution fit?

The bimodal CV structure meant no single family (Normal, Log-Normal, Gamma) fit all 300 SKUs cleanly. Monte Carlo on the empirical distribution is more honest and doesn't force a distributional assumption I couldn't defend.

Why P95 as the service target, not P99?

P99 is achievable for most SKUs but pushes total inventory past warehouse capacity and drives holding cost past the savings threshold. P95 is where the marginal dollar of holding cost stops beating the marginal dollar of expected penalty cost. I confirmed this by running the LP at P90, P95, and P99 and comparing objective values.

Why PuLP and not OR-Tools / Gurobi / CVXPY?

PuLP is free, readable, deterministic, and the problem is linear with a few hundred variables. It doesn't need a commercial solver. If this went to production over thousands of SKUs and rolling weekly runs, I'd re-evaluate Gurobi.

Why linear programming and not reinforcement learning or a neural forecaster?

The problem is fundamentally an allocation problem under known constraints, not a control problem. LP gives an exact, explainable solution. A recruiter or planner can read the constraint report and understand why SKU 217 didn't get its full P95 allocation. An RL policy or an LSTM forecast can't offer that.

Why I rejected simple reorder-point / EOQ models.

Classical EOQ assumes stable demand and doesn't handle multi-warehouse allocation jointly. It's a per-SKU-per-location heuristic. It cannot answer "given a shared capacity constraint across three warehouses, how do I split units globally?" which is the actual business question.

Constraints I didn't model (and would in a v2).

Lead time variability, in-transit inventory, cross-warehouse transfer costs, and supplier-side MOQs. Each is a legitimate extension; leaving them out kept the case study focused on the allocation-under-uncertainty core.

08
Business impact & decision use

What each function actually does with the output.

For the planning team, this pipeline replaces the Monday-morning "gut call" with a defensible, quantified allocation plan. Instead of "put more in East because it felt tight last week," the output is: East gets X units of SKU 217 because at P95 demand is Y, capacity headroom is Z, and the marginal penalty cost dominates the marginal holding cost.

For finance, the modeled savings, ~$76.6K/week ≈ ~$4M/year on a 300-SKU, 3-warehouse footprint, are directly attributable to reallocating existing inventory, not to buying more. That's a working-capital story, not a capex story.

For operations, the 44 constrained SKUs are the single most useful output in the whole project. They convert "we should think about more warehouse space" into a specific, ranked list of SKUs with dollar-value justification per line.

For the executive layer, the regional volatility finding (East ~30% more volatile) reframes East from "our best-performing warehouse" to "our highest-variance warehouse," which changes how you staff it, how much buffer capacity it needs, and whether you want a 3PL fallback there.

Core benefits, one line each
  • Fewer stockouts in the regions and categories where they hurt most (Electronics, East).
  • Less dead inventory in Central and West where the naïve allocation was systematically over-stocking.
  • Better cash flow because the same service level is achieved with less total inventory on hand.
  • Explicit capacity signals. The 44 unmet-demand SKUs are a procurement/warehousing roadmap, not a mystery.
09
Visualizations & key charts

Every chart earns its place in the story.

All charts are generated in-notebook and reproducible from the repo.

FIG. 01
Weekly demand volume by region and category

Establishes the mix and shows East pulling disproportionate share. The "know your data" chart.

FIG. 02
Coefficient-of-variation distribution across 300 SKUs

The bimodal shape that killed the single-policy idea. Two clusters, not a smooth tail.

FIG. 03
Regional volatility. East vs. Central vs. West

Makes the ~30% East-volatility premium visible in a single bar. The finding that only exists at the aggregated level.

FIG. 04
Weekly stockout penalty exposure by category

Electronics towering over the rest at ~$83K/week. This is the chart you show finance.

FIG. 05
Monte Carlo demand distributions. Stable vs. volatile SKUs

Side-by-side histograms of the 10,000-iteration simulations with P50 / P95 / P99 marked. Shows why point estimates are a lie for the volatile cluster.

FIG. 06
Baseline vs. optimized weekly cost

$142K to $65K, the headline result. One chart, one number, one story.

FIG. 07
Warehouse utilization. Before vs. after the capacity constraint

The "110% utilization" failure and the fixed version side by side. The Reality Check, visualized.

FIG. 08
The 44 constrained SKUs, ranked by unmet-demand dollar impact

Turns "we need more space" into a procurement to-do list. The most operationally useful chart in the deck.

10
Links & resources

Everything you need to verify the work.

Repo Structure
Supply-Chain-DI/
├── notebooks/
│   ├── 01_basic_eda.ipynb
│   ├── 02_demand_volatility.ipynb
│   ├── 03_regional_volatility.ipynb
│   ├── 04_financial_eda.ipynb
│   ├── 05_monte_carlo.ipynb
│   └── 06_optimization.ipynb
├── data/                # 300 SKUs × 3 warehouses × 2 years weekly (~93,600 rows)
├── outputs/             # charts, allocation plans, constrained-SKU report
├── Supply_Chain_DI_Documentation.pdf
└── README.md
Tech Stack (Full)
Python 3PandasNumPySciPyPuLPMatplotlibSeabornJupyterMonte Carlo SimulationLinear Programming
Data Sources

Synthetic-but-realistic weekly demand dataset generated to reflect mid-market e-commerce operating conditions: 300 SKUs across Electronics, Apparel, Home, and adjacent categories; 3 warehouses (East / Central / West) serving 3 regions; 2 years of weekly observations; per-unit holding cost, stockout penalty, and per-warehouse capacity attached to each record.

№ 11
Close

Better planning logic recovered the margin.

On the same network, with the same warehouse limits and the same demand patterns, the difference was not more inventory. It was better allocation logic. Weekly cost dropped from $142K to $65K in the modeled scenario, a 54% reduction worth roughly $4M annualized. The 44 SKUs the LP can't fully serve aren't a failure. They're the procurement roadmap that was hiding in the data.