Skip to content
Mixed

Does the league table never lie?

"The table never lies," they say at the end of every season. Over 26 Scottish Premiership seasons, luck alone moves a team's points total by about eight either way: enough to reshuffle mid-table, but not enough to fake a title.

Intermediate

Contents

The claim

"The league table never lies."

It comes out every May, usually from a manager whose team has just finished where everyone expected. Over a whole season, the argument goes, the luck evens out and every side ends up where it deserves.

Why people believe it

Over one match, anything can happen: a deflection, a red card, a goalkeeper having the game of his life. Nobody claims a single result proves much. But a season is 38 matches, and it feels as if that should be long enough for the breaks to cancel out. When the champions and the relegated sides look about right, it's easy to believe the rest of the table is right too.

The data

Every Scottish Premiership match from 2000/01 to 2025/26: 5,879 matches and 312 team-seasons, from football-data.co.uk. Final scores only.

The method

Two questions:

  1. How much can luck move a team's points total? Work out how much a season's points would vary for a team whose results were decided purely by chance, then compare that with how much teams' points actually vary.
  2. Does the table agree with itself? Split every season in half. If the table told the truth about how good each team is, the first-half table and the second-half table should match.

The evidence

Luck is worth about eight points

Across these seasons, teams won 38.1% of their matches and drew 23.7%. If every result were a random draw at those rates, a team's points total over 38 games would vary with a standard deviation of

$$\sqrt{38 \times 1.76} \approx 8.2 \text{ points}$$

In plain football

  • 1.76 is how much a single match's points (3, 1 or 0) swing around the average of 1.38.
  • × 38 adds up that swing over a season. Luck grows with the number of games, but more slowly: with its square root.
  • 8.2 points is the typical size of the luck in a season's total. About a third of teams will be more than 8 points above or below what their football deserved.

Real teams' points vary far more than that, with a standard deviation of about 18 points, because some teams genuinely are much better than others. Luck accounts for about a fifth of the spread in the final table. The other four-fifths is real quality.

The top is solid. The middle is noise.

Whether eight points matters depends on how far apart the teams are. Here are the typical (median) gaps between neighbouring places in the final table:

Between Typical points gap
1st and 2nd 11
2nd and 3rd 16.5
3rd and 4th 6.5
4th and 5th 4
5th and 6th 2
6th and 7th 2
7th and 8th 1.5
8th and 9th 3
9th and 10th 2
10th and 11th 2.5
11th and 12th 5.5

At the top, the gaps are bigger than luck can bridge. In the middle they're a point or two, far smaller than the eight points luck can add or take away. From 5th to 10th, the order is largely a draw from a hat.

The table disagrees with itself

Split each season in two and compare the table from the first 19 games with the table from the rest. On average, a team's position changes by 2.2 places between the two halves, and 35% of teams move three places or more. The team top of the first-half table also tops the second half only 16 times in 26.

Replaying each season with the same teams makes the point another way. Estimate every team's true quality from its results, allowing for luck, and play the season again 400 times. The best team wins the league about three times in four. A team finishes exactly where its quality says only about 30% of the time.

Show the mathsWhere the 8.2 comes from, and how much of the table is luck. Optional.

For one match, points X are 3 with probability 0.381, 1 with probability 0.237 and 0 otherwise:

$$E[X] = 3(0.381) + 0.237 = 1.38$$

$$E[X^2] = 9(0.381) + 0.237 = 3.67$$

$$\text{Var}(X) = 3.67 - 1.38^2 \approx 1.76$$

Over 38 independent matches the variance adds up, so the luck in a season's total has standard deviation \(\sqrt{38 \times 1.76} \approx 8.2\).

The observed variance of season points is about \(18.4^2 \approx 338\). Luck's share is \(38 \times 1.76 / 338 \approx 20\%\), leaving a spread in true quality of \(\sqrt{338 - 67} \approx 16.5\) points. The equal-teams assumption slightly overstates luck, because a dominant side's results vary less than an average side's.

Splitting each season into alternate matches gives a correlation of 0.70 between the two halves' points per game. Stretched to a full season (the Spearman–Brown formula, \(2r/(1+r)\)), the table's reliability is about 0.82: mostly signal, but a real share of noise.

Verdict

Mixed. The table doesn't lie about the top or the bottom: the gaps there are bigger than luck. But it tells plenty of white lies in between. A side that finishes 6th and one that finishes 9th are often no different in quality, and the points luck handed out can decide who finishes where. And in a league as top-heavy as Scotland's, the "top" is only ever two clubs deep.

Caveats

  • Scotland is unusual. Two clubs are far stronger than the rest, which makes the top of the table unusually easy to get right. In a more even league, luck decides more.
  • The Premiership split means teams don't all play the same opponents the same number of times, which adds its own noise.
  • 2019/20 was cut short after about 30 games, so that season carries more luck than the others.
  • The simulation is a sketch. It treats every match as independent and gives each team one fixed level of quality for the whole season. Injuries, transfers and managers change that.

Reproduce the analysis

The results files are published by football-data.co.uk. Download the Premiership file (SC0) for each season, and save each under its own name, such as SC0_2425.csv; they aren't rehosted on this site. Then:

import csv, glob, statistics

points, results = [], []
for path in glob.glob("SC0_*.csv"):
    table = {}
    with open(path, encoding="latin-1") as f:
        for r in csv.DictReader(f):
            if not (r.get("FTHG") and r.get("FTAG")):
                continue
            hg, ag = int(r["FTHG"]), int(r["FTAG"])
            for team, gf, ga in ((r["HomeTeam"], hg, ag), (r["AwayTeam"], ag, hg)):
                pts = 3 if gf > ga else 1 if gf == ga else 0
                table[team] = table.get(team, 0) + pts
                results.append(pts)
    points.append(statistics.pvariance(table.values()))

win, draw = results.count(3) / len(results), results.count(1) / len(results)
luck_var = 38 * (9 * win + draw - (3 * win + draw) ** 2)
print(f"luck: ±{luck_var ** 0.5:.1f} points; share of the table's spread: {luck_var / statistics.mean(points):.0%}")

Spotted a flaw in the method, or have a football claim you'd like tested? Suggest it on LinkedIn, where discussion of these articles happens.

Get new pieces by email

An email when something new is published, and the occasional update. Unsubscribe in one click. How your email is used.