Supply chain analytics
Two Weights, One Number
A supplier scorecard, tested for hidden overlap.
- Role
- Author
- Classification
- Engineering prototype
Problem
Five scores look like five opinions.
How it was solved
I traced each score to its data and found two read one signal.
- Data
- KPIs
- Weights
- Score
Result
55%
of the score is one signal twice
- One shared signal55%
- Everything else45%
Built with
- Python
- pandas
- Plotly Dash
- statsmodels
Supply chain analytics / Scoring
A supplier scorecard with five weighted components looks like five opinions about a supplier. Read the weights against the functions they weight - how many opinions are actually in there?
Share of the score that is one signal55%
One table, three analyses, and two components that are one
This diagram in words
- Order table source — Schema validated and every column profiled before use.pandas
- KPI engine process — Overview, shipping and financial views over the same rows.
- Supplier scorecard process — Five components, min-max normalised, combined by weight.
- Demand forecast process — Chronological holdout, measured against naive baselines.statsmodels
- Inventory policy process — EOQ, safety stock and reorder point at a service level.SciPy
- Weighting audit artifact — Reads the weights against the functions they weight.
- Dashboard sink — Publishes no business metric; the repository versions code only.Plotly Dash
Read the full background
Problem
Why this work exists
A composite score is persuasive in a way its parts are not: five weighted components read as five independent opinions, and nobody checks whether they are. In a supply chain scorecard the temptation is worse, because the fields that sound most different - reliability and quality - are often the only fields the source data can actually support.
Contribution
What I can claim
Built the pipeline and the dashboard, then audited the scorecard against itself. Two of the five components turn out to be the same computed series under different names, which is a defect in my own design rather than a caveat about the data, and the page leads with it because that is what the finding is worth.
Method
How a composite score hides its own structure
Five weighted components, adding to one, presented as a single number per supplier.
Inverting a min-max normalisation of one minus a series returns the series, so those two components are equal for every supplier. The repository publishes no data and no metric; the inventory formulas are classical and their assumptions are the user’s to justify.
Aggregate
Orders are grouped into per-supplier metrics.
Weight
Five components are given weights that sum to one: reliability, quality, cost, lead time, flexibility.
Trace
Each component is a normalisation of one column.
Collapse
Inverting a min-max normalisation of one minus a series returns the series.
Concede
Which leaves four signals, not five, and more than half the score resting on delivery timeliness alone.
What this does not show
Nothing here is measured. The repository versions source and notebooks only - no dataset, no processed data, no forecast artefacts, no verified metrics - and makes no claim about any fill rate, delivery rate, region or forecast accuracy. The supplier grouping is a proxy and must not be read as a supplier-quality assessment, and the inventory outputs are classical formulas whose assumptions belong to whoever applies them.
How it was built
System
Workflow and decisions
Five modules behind one Plotly Dash application: ingestion and data quality, KPI calculation, demand forecasting against naive baselines, inventory optimisation, supplier scoring. The dataset is deliberately ignored by Git, which is why the repository can be read in full without any of it being mistaken for a result.
- 1ingestion and data quality
- 2KPI calculation
- 3demand forecasting against naive baselines
- 4inventory optimisation
- 5supplier scoring
- Python
- pandas
- Plotly Dash
- NumPy
- SciPy
- statsmodels
Evidence
What is actually versioned
delivery reliability normalises on_time_rate, ascending; quality normalises late_delivery_rate, descending. The aggregation defines late_delivery_rate as one minus on_time_rate, and inverting a min-max normalisation of one minus a series returns the series exactly - so the two components are equal for every supplier. They carry 55% of the composite between them, which leaves 4 distinct signals rather than 5.
The repository versions source and notebooks only: no the source dataset, no a processed dataset, no trained forecast artefacts, no verified business metrics. It therefore makes no claim about any fill rate, on-time-delivery rate, region or forecast accuracy, and this page makes none either.
EOQ = sqrt(2 D S / H); SS = z sqrt(LT sigma_d^2 + d^2 sigma_LT^2); ROP = d LT + SS, at a default service level of 95%. These are textbook identities rather than results: the repository calls their outputs illustrative and says the assumptions must be validated for a real operation.
How the work is checked
Quality controls
How the work is checked
- The supplier proxy is named as a proxy in the README rather than presented as supplier data: the source has no supplier identifiers, so departments and categories stand in for them
- The quality-like component is already flagged in the README as derived from late delivery and not usable as a quality assessment - this page carries that through to what it does to the weighting
- Forecasts are compared against naive baselines on a chronological holdout, so a seasonal series cannot look skilful by accident
- Prophet is optional: the comparison records a warning and continues rather than failing, so the pipeline runs with whatever is installed
Limitations
Where the evidence stops
- The scorecard's weighting is wrong as it stands, and the fix is a design decision about what the remaining signals should be worth rather than a one-line change
- No dataset, no processed data, no forecast artefacts and no verified metrics are versioned, so nothing here is measured
- Suppliers are departments and categories standing in for suppliers. Any conclusion about a supplier is a conclusion about a grouping that is not one
- The inventory outputs assume stable demand, a known lead-time distribution and a normal service-level factor. Those assumptions belong to whoever uses them, and the repository says so
What this changed in my practice
What this changed in my practice
I built the scorecard and I did not notice. It took reading the weights beside the functions they weight, rather than reading either on its own, and the arithmetic was two lines long once I looked. A composite score hides its own structure by design - that is what composites are for - which is exactly why the weighting deserves the same scrutiny as the model.