Article · April 18, 2023

The average is a lie — a field guide to skew

Almost every number a business cares about is right-skewed, and almost every business reports it as a mean. Here is what that does, why nobody notices, and what to publish instead.

3 min read ·Statistics ·statistics practice

Here is a number: the average order value at a company I once worked with was $84. Here is another: the median was $41.

Both were computed correctly from the same table on the same day. The executive team had been planning around the first one for two years, and the shipping-threshold experiment they built on it failed for reasons nobody could explain until someone looked at the histogram.

Why the mean drifts#

The arithmetic mean is the balance point of a distribution. For a symmetric distribution, that is also the typical value, and everything is fine. For a right-skewed one — a long tail of large values — the balance point is dragged toward the tail, away from where most of the observations actually are.

Right skew is not an edge case in business data. It is the default:

  • Money. Order values, salaries, customer lifetime value, insurance claims.
  • Durations. Session length, time to resolution, delivery time, page load.
  • Counts. Sessions per user, items per order, messages per conversation.
  • Anything with a floor and no ceiling. Which is most things — you cannot spend negative money, but there is no upper limit.

The mechanism is simple. Multiplicative processes produce lognormal-ish distributions, and most business quantities are multiplicative: a customer's spend is roughly (number of visits) × (items per visit) × (price per item), each of which varies. Multiply three moderately variable things and you get a long tail.

The specific damage#

Planning. If typical is $41 and you plan capacity, pricing, or a free-shipping threshold around $84, you have designed for a customer who does not exist.

Thresholds. "Free shipping over $75" sounds like a small nudge if the average is $84. It is an enormous ask when the median is $41 — you are asking most of your customers to nearly double their basket.

Comparisons over time. A mean is unstable in the presence of a heavy tail. One enterprise deal moves the monthly average and nothing has changed about typical behaviour. Teams then explain the noise: "the mean is up 12%, our new onboarding is working". It was one customer.

Experiments. A t-test on revenue per user assumes the sampling distribution of the mean is roughly normal. On a heavy tail at realistic sample sizes it is not, so the p-value means much less than it appears to.

What to publish instead#

Median first. For any money, duration, or count metric, lead with the median. It answers "what is typical", which is what people think the mean means.

A high percentile beside it. The p90 or p95 tells you about the tail, which is often where the money is. "Median order $41, p90 $156" is two numbers and a complete picture.

The mean, when the total matters. The mean is not wrong — it is the total divided by the count, so if you care about total revenue, the mean is exactly the right per-unit number. Say so: "mean $84, which is the number that multiplies out to total revenue".

A histogram, once. Not in every report. But once, at the start of the relationship, showing the stakeholder the shape. After that the median makes sense to them without an argument every quarter.

The conversation that follows#

Someone will say the median is harder to explain, or that finance uses the mean, or that the dashboard has always shown the average.

Two things that help. First, "half of orders are below this" is genuinely easier to explain than "the balance point of the distribution", so the difficulty objection has it backwards. Second, do not remove the mean — add the median next to it. A tile showing both, with the gap visible, teaches the concept without a meeting. When people see median $41 and mean $84 sitting side by side for a month, the question asks itself.

A worked check#

Take ride-hail-trips and compute both:

sql
select borough,
       round(avg(fare_usd), 2) as mean_fare,
       count(*)                as trips
from ride_hail_trips
group by borough
order by mean_fare desc;

Then open the same column in the Data Explorer, which draws the median and the mean on the histogram together. The gap is visible immediately, and the Airport rows explain it — long trips at a high base fare, few in number, heavy in influence.

That gap is not a data quality problem to be cleaned. It is the shape of the business, and reporting one number that hides it is the only actual error available here.