Data AnalyticsIndustry analytics playbooks

Supplier PPM and defect Pareto: rank problems by what they cost

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 27 September 2026 · 5 min read
In this article (6 sections)

Related programme: the Data Analytics with Generative AI course (3–4 months; ₹90,000 (inclusive of GST) · EMI from ₹4,000/month).

The short answer

Supplier PPM is rejected quantity divided by received quantity, multiplied by 1,000,000, and a defect Pareto ranks defect causes so the few that account for most of the loss are fixed first. The analytical choice that changes decisions is what you rank by: counted by pieces, a cheap moulded clip with flash tops the chart; weighted by cost, a porosity problem on a ₹410 casting accounts for 70% of the loss in the synthetic example below. Build both and lead with the cost view.

The memo the supplier quality head should receive

Start from the output and work backwards. Here is the one-paragraph version of what the analysis below produces:

**Incoming quality, Q2 (synthetic data).** Crest Plastics has the highest PPM (10,000) but the lowest-cost failures. Alpha Castings, at 6,000 PPM, accounts for 86% of rejection cost, most of it porosity on housing HSG-10 and bracket BRK-22. Recommendation: a joint porosity review at Alpha with a process audit of degassing, before any action on Crest. Bharat Springs' wire-diameter rejects are second by count but under 7% of cost.

Everything that follows exists to make each number in that memo defensible.

Source data from the plant

Goods receipt (GRN) lines — grn_no, grn_date, supplier, part_no, received_qty, unit_cost (from the purchase order).

Incoming inspection / non-conformance reports (NCR) — ncr_no, grn_no, supplier, part_no, defect (from a controlled defect-code list), rejected_qty, disposition (return, rework, use-as-is under deviation, scrap).

Plants that run sampling inspection record a lot decision as well as the defectives found in the sample. Know which you have before computing anything; see the traps below.

PPM, defect rate and cost-weighted Pareto

  • Supplier PPM = Σ rejected_qty ÷ Σ received_qty × 1,000,000, over the same period and the same parts.
  • Rejection cost = rejected_qty × unit_cost, as a first approximation.
  • Pareto cumulative % = running total of cost (sorted descending) ÷ total cost × 100.

The calculation (synthetic quarter)

python
import pandas as pd

# Synthetic receipts and incoming-inspection rejections for one quarter
receipts = pd.DataFrame({
    "supplier": ["Alpha Castings"]*3 + ["Bharat Springs"]*3 + ["Crest Plastics"]*2,
    "part_no":  ["HSG-10","HSG-10","BRK-22","SPR-05","SPR-05","SPR-09","CLP-31","CLP-31"],
    "received_qty": [4000, 4000, 1500, 60000, 60000, 20000, 90000, 90000],
    "unit_cost": [410.0, 410.0, 780.0, 3.5, 3.5, 6.0, 1.2, 1.2],
})
rejections = pd.DataFrame({
    "supplier": ["Alpha Castings","Alpha Castings","Alpha Castings","Bharat Springs",
                 "Bharat Springs","Crest Plastics","Crest Plastics","Crest Plastics"],
    "part_no":  ["HSG-10","HSG-10","BRK-22","SPR-05","SPR-09","CLP-31","CLP-31","CLP-31"],
    "defect":   ["porosity","dimension","porosity","wire dia","free length","flash","short shot","flash"],
    "rejected_qty": [36, 12, 9, 540, 60, 900, 300, 600],
    "disposition": ["return","return","rework","return","use-as-is","return","return","return"],
})

supplier_ppm = (receipts.groupby("supplier")["received_qty"].sum().to_frame()
                .join(rejections.groupby("supplier")["rejected_qty"].sum()))
supplier_ppm["ppm"] = (supplier_ppm["rejected_qty"] / supplier_ppm["received_qty"] * 1e6).round(0)
print(supplier_ppm.sort_values("ppm", ascending=False), "\n")

cost = receipts.groupby(["supplier","part_no"])["unit_cost"].first()
rej = rejections.join(cost, on=["supplier","part_no"])
rej["cost_rs"] = rej["rejected_qty"] * rej["unit_cost"]
pareto = (rej.groupby(["supplier","defect"])
             .agg(qty=("rejected_qty","sum"), cost_rs=("cost_rs","sum"))
             .sort_values("cost_rs", ascending=False))
pareto["cum_cost_pct"] = (pareto["cost_rs"].cumsum() / pareto["cost_rs"].sum() * 100).round(1)
pareto["qty_rank"] = pareto["qty"].rank(ascending=False, method="min").astype(int)
print(pareto)
text
                received_qty  rejected_qty      ppm
supplier
Crest Plastics        180000          1800  10000.0
Alpha Castings          9500            57   6000.0
Bharat Springs        140000           600   4286.0

                             qty  cost_rs  cum_cost_pct  qty_rank
supplier       defect
Alpha Castings porosity       45  21780.0          70.0         5
               dimension      12   4920.0          85.8         6
Bharat Springs wire dia      540   1890.0          91.9         2
Crest Plastics flash        1500   1800.0          97.7         1
Bharat Springs free length    60    360.0          98.8         4
Crest Plastics short shot    300    360.0         100.0         3

The qty_rank column is the point. Flash on Crest's clip is rank 1 by pieces and rank 4 by cost. Porosity at Alpha is rank 5 by pieces and 70% of cost. A count-based Pareto would send the supplier development engineer to the wrong factory.

Where PPM and Pareto numbers get distorted

Lot rejection recorded as the full lot. If a sample of 80 fails and the whole lot of 4,000 goes back, some plants enter 4,000 as rejected quantity. That is a lot-acceptance fact, not 4,000 defective parts. Keep two measures: defective PPM (defectives found ÷ inspected) and lot rejection rate (rejected lots ÷ received lots).

Use-as-is deviations. Bharat's 60 free-length rejects were accepted under deviation. They are non-conforming, so they belong in PPM, but they carry no return cost. Decide the rule, then apply it to every supplier; the code above counts them in PPM and prices them at full unit cost, which you may want to change.

Rework priced at full cost. Alpha's BRK-22 porosity was reworked, not scrapped. Pricing it at the full ₹780 overstates cost; rework hours × rate is closer. The first-pass version is fine for ranking only if the ranking survives the correction — here it does, because HSG-10 alone is ₹19,680.

The "others" bucket. If "others" or "visual" is one of your top three defect codes, the Pareto is measuring the defect-code list, not the process. Fix the codes with the quality inspectors before presenting.

Unit cost is not the full cost. A ₹1.20 clip that stops a final assembly line costs far more than ₹1.20. If you have line-stoppage or sorting records, add them as a separate cost column rather than blending them into unit cost silently.

Small denominators. Alpha received only 9,500 pieces; one bad heat of castings moves its PPM by thousands. Report received quantity beside every PPM.

Presenting it at the monthly supplier review

Show two small charts side by side — Pareto by pieces and Pareto by cost — so the room sees the disagreement for itself. Then the table with PPM, received quantity and cost per supplier. Close with one named action per top-cost defect and an owner. Suppliers take PPM seriously when the numerator comes with NCR numbers they can trace, so attach the NCR list as an appendix.

Grouped aggregation, joins and cumulative percentages are the core of this exercise and of the pandas work in our Data Analyst programme. If your background is in supply chain or production, supply chain executive to supply chain analyst covers how to present plant-floor analysis to a hiring panel.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.