ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

ABC / Pareto Analysis: Practical Guide for Data-Driven Decisions

By MCP Analytics Team | Published , updated

Operational Analytics

ABC analysis ranks items by how much they contribute, then splits them into three groups: A (the few that matter most), B (the middle) and C (the many that matter least). Pareto analysis is the same idea, usually drawn as a chart and tied to the "80/20" idea that a small share of causes produces most of the effect. The items can be products, customers, defect causes or tasks.

The method is simple. The choices around it are where it goes wrong: what you rank by, where you draw the lines, and how often you redo it. This guide runs all three on a small data set so you can see the effect, with the code and the output.

Two terms first. An SKU is one product you stock. Contribution is revenue minus the costs that rise and fall with each sale (cost of goods, shipping, payment fees). Cumulative share is the running total of value as you walk down the ranked list, as a percent of the grand total.

To run a Pareto analysis on your own file, see the Pareto analysis page or try the free Pareto analysis tool.

Where the 80/20 Idea Comes From

Pareto is named for the economist Vilfredo Pareto, who observed that about 80% of the land in Italy was owned by about 20% of the people. Joseph Juran later applied the idea to quality control and management, and preferred to call it "the vital few and the useful many" (Pareto principle, Wikipedia). That same source describes 80/20 as shorthand and a rule of thumb, and says real cases can sit nearer 90/10 or 70/30.

ABC analysis applies the ranking to inventory. The same reference says it has no fixed thresholds for each class, and that the proportions are set from your objectives (ABC analysis, Wikipedia). So "A is 80% of value" is a convention you may adopt, not a result you can expect from every data set.

A Worked Example You Can Re-Run

The data below is synthetic: 300 made-up SKUs generated with a fixed random seed. Revenue is drawn from a skewed (lognormal) distribution and each SKU gets its own margin between about 2% and 45%. It is not data from a real business. It is built so you can see what changes when you rank by revenue versus by contribution. The script needs only numpy. Run it with python3 abc.py.

import numpy as np

rng = np.random.default_rng(11)
n = 300
revenue = rng.lognormal(mean=8.0, sigma=1.1, size=n).round(0)
margin = (0.02 + 0.43 * rng.beta(1.5, 3.0, size=n)).round(3)
contrib = (revenue * margin).round(0)

def classify(value, a=0.80, b=0.95):
    order = np.argsort(-value)
    share = np.cumsum(value[order]) / value.sum()
    cls = np.empty(len(value), dtype="<U1")
    # an item is A if the share BEFORE adding it is below the cutoff
    before = share - value[order] / value.sum()
    cls[order] = np.where(before < a, "A", np.where(before < b, "B", "C"))
    return cls

def summary(label, value, cls):
    out = [label]
    for k in "ABC":
        m = cls == k
        out.append(f"{k}: {m.sum():3d} items ({m.mean():5.1%}) hold {value[m].sum()/value.sum():5.1%}")
    print("  ".join(out))

rev_cls = classify(revenue)
con_cls = classify(contrib)
print(f"items {n}, total revenue {revenue.sum():,.0f}, total contribution {contrib.sum():,.0f}")
summary("by revenue     ", revenue, rev_cls)
summary("by contribution", contrib, con_cls)

print("\ntransition table (rows revenue class, cols contribution class)")
for r in "ABC":
    print(r, [int(((rev_cls == r) & (con_cls == c)).sum()) for c in "ABC"])
changed = (rev_cls != con_cls).sum()
print("items whose class changes:", changed, f"({changed/n:.1%})")
revA = rev_cls == "A"
print("revenue-A items:", revA.sum(), " of which not A by contribution:", (revA & (con_cls != "A")).sum())
print("contribution-A items not A by revenue:", ((con_cls == "A") & ~revA).sum())
print("avg margin of revenue-A items %.1f%%, of contribution-A items %.1f%%" % (
    100*np.average(margin[revA], weights=revenue[revA]), 100*np.average(margin[con_cls=="A"], weights=revenue[con_cls=="A"])))

print("\ncutoff sensitivity (A group size by contribution)")
for a in (0.70, 0.80, 0.90):
    c = classify(contrib, a=a, b=min(a + 0.15, 0.99))
    print(f"A cutoff {a:.0%}: {(c=='A').sum()} items ({(c=='A').mean():.1%})")

print("\ncapacity cutoff: top 30 by contribution hold %.1f%%, top 60 hold %.1f%%" % (
    100*np.sort(contrib)[::-1][:30].sum()/contrib.sum(), 100*np.sort(contrib)[::-1][:60].sum()/contrib.sum()))

# next period: same margins, revenue moves by random noise
rev2 = (revenue * rng.lognormal(0, 0.3, size=n)).round(0)
con2 = (rev2 * margin).round(0)
cls2 = classify(con2)
print("\nnext period (revenue noise sigma 0.3, margins unchanged)")
print("items that change class:", (cls2 != con_cls).sum(), f"({(cls2 != con_cls).mean():.1%})")
print("A items that drop out of A:", ((con_cls == "A") & (cls2 != "A")).sum(), "of", (con_cls == "A").sum())
# show a few revenue-A that fall
fall = np.where(revA & (con_cls != "A"))[0]
fall = fall[np.argsort(-revenue[fall])][:4]
print("top revenue-A that drop")
for i in fall: print(i+1, int(revenue[i]), margin[i], int(contrib[i]), rev_cls[i], con_cls[i])
rise = np.where(~revA & (con_cls == "A"))[0]
rise = rise[np.argsort(-contrib[rise])][:4]
print("rise")
for i in rise: print(i+1, int(revenue[i]), margin[i], int(contrib[i]), rev_cls[i], con_cls[i])

An item is put in A if the cumulative share before adding it is still below 80%. It goes in B if that share is still below 95%. Everything else is C. These 80/95 lines are the common convention, used here as a starting point.

Result 1: the 80/20 split did not appear

Ranked byA itemsB itemsC items
Revenue134 items (44.7%) hold 80.2%88 items (29.3%) hold 14.9%78 items (26.0%) hold 4.9%
Contribution113 items (37.7%) hold 80.2%91 items (30.3%) hold 14.8%96 items (32.0%) hold 5.0%

Total revenue is 1,490,689 and total contribution is 253,407. To reach 80% of the value, you need 38% to 45% of the items, not 20%. The data here is less skewed than the "vital few" picture suggests. That is a feature of this made-up data set, and your own data may be steeper or flatter. The lesson is to check, not to assume.

Result 2: ranking by revenue and by contribution disagree

Class by revenue (rows)A by contributionB by contributionC by contribution
A (134 items)94364
B (88 items)194227
C (78 items)01365

99 of the 300 items (33.0%) land in a different class depending on which measure you use. Of the 134 revenue-A items, 40 are not A by contribution. In the other direction, 19 items are A by contribution but not by revenue. Here are the four biggest revenue-A items that drop to B, and the four biggest contribution-A items that were B by revenue:

SKURevenueMarginContributionRevenue classContribution class
13712,7663.8%485AB
8512,4823.9%487AB
311,4673.2%367AB
719,8463.3%325AB
2233,28935.8%1,177BA
893,89929.6%1,154BA
2662,92837.0%1,083BA
992,92736.5%1,068BA

The pattern is the one to watch for: large sales at thin margins look important by revenue, and small sales at fat margins get missed. Which measure is right depends on your decision. If the question is "where should our money and attention go", contribution is closer to the point. If the question is "how much shelf space do we need", revenue or units may fit better.

Result 3: the cutoff changes the size of group A a lot

A cutoff (cumulative share of contribution)Items in AShare of all items
70%8227.3%
80%11337.7%
90%16354.3%

Moving the line by ten points moves group A by 31 to 50 items. If a buyer can only watch 30 items closely, none of these cutoffs fits. The other way to set the line is by capacity: pick the number of items your team can actively manage, then check what they hold. In this data the top 30 items by contribution hold 41.4% of contribution, and the top 60 hold 60.2%. That is a different answer than "80%", and it is an honest one: with this spread of values, 30 items cannot cover most of the value.

Result 4: classes move from one period to the next

To test stability, the script makes a "next period" by multiplying each SKU's revenue by random noise (lognormal, spread 0.3) and keeping each margin the same. With that moderate change, 37 of 300 items (12.3%) land in a different contribution class, and 15 of the 113 A items drop out of A. Real demand shifts are not random noise, so treat this as an illustration that classes are not fixed, not as a forecast for your business. A reasonable habit is to recalculate on a schedule and look at the items sitting just either side of a line.

What the Example Suggests, and What It Does Not

What it does not show: whether treating A, B and C items differently improves results. That needs a before-and-after or a comparison group on your own operation, and this page does not claim an effect size.

Choosing Cutoffs

Common conventions are 80/15/5 and 70/20/10 (share of value for A, B and C). They are starting points. Some ways to decide:

Prepare the Data First

Dirty inputs can change the ranking, so check these before you run it:

What to Do With the Classes

The labels only matter if they change what people do. Write the treatment down before you run the analysis. Here is one way to set it up. The review rhythm is a suggestion, so change it to fit your business.

ClassPossible treatment
ANamed owner, custom reorder point, frequent review, a backup supplier where one exists
BStandard reorder formula, periodic review
CSimple min/max rules, fewer touches, a periodic check on whether to keep the item

One limit to know: ABC ranking looks at each item alone. An item that is C on its own may be bought together with an A item, so a basket check (which items sell together) is a useful second look before you cut anything.

Beyond Inventory

The same ranking works on customers (rank by contribution after cost to serve, and add a trend view so a shrinking customer is not hidden), on marketing categories, on support tickets by cause, and on how you spend your own time. Where one number is not enough, researchers have extended ABC analysis to rank on several criteria at once, such as cost and how critical an item is (Flores and Whybark, 1986, listed in the sources below).

Run It on Your Own Data

With MCP Analytics you upload a CSV with one row per item and a value column. A tested statistical method ranks the items and computes the cumulative shares, and you get a written report. It is repeatable: the same file gives the same numbers. You decide the cutoffs and what the A group should get. Start from the Pareto analysis page.

Your turn

Bring your own data and the question you actually need answered.

MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai

Frequently Asked Questions

What's the difference between ABC analysis and Pareto analysis?

They are close relatives and are often used as one method. Both rank items by how much they contribute, then group them by cumulative share. ABC analysis comes from inventory control and sorts items into A, B and C. Pareto analysis is named after Vilfredo Pareto and is used more widely, for example on defect causes or customers. The 80/20 split is a rule of thumb, not a law, and real data can land far from it.

How do I choose the cutoffs for A, B and C?

There is no fixed rule. Splits such as 80/15/5 or 70/20/10 are conventions. Two sound ways to choose: set the cutoff by cumulative share (for example, A is the items that make up the first 80% of value), or set it by how many items your team can actively manage and see what share of value that group holds. Whichever you pick, write down the reason and test a neighbouring cutoff to see how much the group sizes change.

Should I run ABC analysis on revenue or on profit?

Use the measure that matches the decision. For where to spend inventory money or attention, contribution (revenue minus the costs that vary with each sale) is usually closer to what you care about than revenue. In the worked example on this page, 40 of the 134 items in the revenue A group dropped out of A when ranked by contribution. Ranking by units is reasonable when the question is shelf or warehouse space.

How often should I recalculate the classes?

It depends on how fast your sales change. In the worked example, adding moderate random change to revenue moved 37 of 300 items (12.3%) into a different class the next period. That is a sign to recalculate on a schedule and to watch items near a cutoff, but the right schedule for your business (monthly, quarterly) is a judgment call.

Can I use ABC analysis for customers?

Yes. Rank customers by contribution or profit instead of items. Add a time view as well, since a customer who is shrinking can still sit in group A on last year's numbers. A one-number ranking says nothing about direction.

Sources