# How many points is a goal worth?

Source: https://www.footballdatascience.co.uk/research/points-per-goal
Published: 2026-09-29

> Goal difference explains 93% of the points a Scottish side takes, at about 0.63 points per goal. Some teams beat their goals by four wins' worth in a season, but it barely carries into the next one. 572 team-seasons show why.

## The research question

Every manager knows goals win matches. But **how many points is one more goal actually worth over a season?** And some teams finish with far more points than their goals suggest, winning the close ones, or far fewer. **Is that a skill, or is it luck?**

## The dataset

Every Scottish Premiership and Championship season from 2000/01 to 2025/26: **572 team-seasons**, each a team's wins, draws, goals for, goals against and points. A handful of stray rows in the files, teams with only a match or two in a division, are left out by keeping team-seasons with at least 20 matches.

## The method

**Points per goal.** Fit a straight line through points per game against goal difference per game, across all 572 team-seasons. The slope is how many points each goal of goal difference is worth.

**Pythagorean expectation.** A straight line can't respect the fact that no team takes fewer than 0 or more than 3 points a game. Analysts in baseball, basketball and football use a curve instead, named for its resemblance to Pythagoras' theorem:

$$\text{expected share of results} = \frac{\text{GF}^{k}}{\text{GF}^{k} + \text{GA}^{k}}$$

<div class="plain" markdown="1">
In plain football

- **GF and GA** are goals for and goals against over the season.
- **Share of results** counts a win as 1 and a draw as a half, divided by games played. An average side sits at 50%.
- **k** controls how steeply goals turn into results. It's fitted to the data: the value that makes the formula match real seasons best.
</div>

**Beating your goals.** A team's actual share of results minus its expected share, times games played, is how many **wins' worth** it finished above or below its goals: a win instead of a defeat counts as one, a draw instead of a defeat as a half.

**Luck or skill?** Take every team that played consecutive seasons in the same division, 449 pairs, and check whether beating its goals in one season goes with beating them in the next. A skill should carry over; luck shouldn't.

## Results

### A goal is worth about 0.63 points

<figure class="rank-chart">
<div role="img" aria-label="Average points a game for team-seasons grouped by goal difference a game, from minus 1.4 to plus 1.9. The points rise steadily from 0.55 to 2.54, close to a straight line with slope 0.63.">

</div>
<figcaption>Team-seasons grouped by goal difference per game; each dot is a group's average points per game, larger for bigger groups. They sit close to the dashed line: every goal of goal difference is worth about 0.63 points.</figcaption>
</figure>

$$\begin{aligned} &\text{points a game} \\ &= 1.37 + 0.63 \times \text{goal difference a game} \end{aligned}$$

<div class="plain" markdown="1">
In plain football

- **1.37** is what a team with a goal difference of zero takes per game: an average side.
- **0.63** is the value of each goal of goal difference, and because both sides of the equation are per game, it's per goal over a season too.
- So **ten more goals of goal difference is worth about six points**, the difference between a mid-table finish and a European place in many seasons.
</div>

Goal difference alone explains **93%** of the variation in points per game. Split into its two halves, each goal scored is worth about **0.65** points and each goal conceded costs about **0.60**: a goal saved is worth nearly as much as a goal scored.

Those two numbers make goals comparable at both ends of the pitch, which is how [who's the best signing?](/learn/what-are-we-optimising) weighs a striker against a centre-back.

### The Pythagorean curve

The best-fitting exponent is **k = 1.2**, and with it the formula predicts a team's share of results to within about **3.8 percentage points** typically: over a 38-game season, roughly a win and a half. The teams that beat it by most:

| Team and season | Points | GD | Wins above |
|---|---|---|---|
| Motherwell, 2013/14 | 70 | +4 | +4.3 |
| St Mirren, 2007/08 | 41 | −28 | +4.3 |
| St Johnstone, 2010/11 | 44 | −20 | +4.3 |
| Celtic, 2016/17 | 106 | +81 | +3.7 |
| Ross County, 2002/03* | 35 | −4 | −4.0 |
| Airdrie Utd, 2005/06* | 45 | +14 | −4.0 |

\* Championship. The rest: Premiership.

Motherwell's 2013/14 is the standout: **70 points from a goal difference of just +4**, second in the Premiership, about four wins more than their goals deserved. They won lots of close games. At the other end, Airdrie United in 2005/06 had a goal difference of +14 and took just 45 points.

### Beating your goals is mostly luck

<figure class="rank-chart">
<div role="img" aria-label="Correlation with the same team next season. Goal difference: 0.75. Beating your goals: 0.10, with a range of plus or minus 0.09.">

</div>
<figcaption>How much of each carries into the next season. A team's goal difference is strongly repeated. How far it beat its goals barely is.</figcaption>
</figure>

A team's goal difference is strongly repeated from one season to the next: a correlation of **0.75**. How far it beat its goal difference is not: **0.10**, only just clear of zero, with a range of ±0.09. Winning the close games in one season tells you very little about the next. If there's any skill in it, it's small; most of it is the luck of which way the tight matches went.

That's the same conclusion, reached a different way, as [does the league table never lie?](/myth-or-maths/league-table-never-lies): the table carries a layer of luck on top of quality. Goal difference is closer to the quality underneath.

## A warning about small samples

A single season's over- or under-performance is built on a handful of close matches: a +4 means about four results going the other way. The luck test rests on 449 pairs of seasons, which is enough to say the carry-over is small but not to pin down exactly how small; it could be anywhere from nothing to about 0.2.

## Limitations

- **Two divisions.** The Premiership and Championship play different numbers of games and have different spreads of quality; the per-game measures put them on the same footing, but the fit is shared.
- **Draws counted as half.** The Pythagorean share treats a draw as half a win; in points, a draw is worth a third of a win.
- **Points deductions** aren't in the data, so a few team-seasons' points differ from the official tables.
- **Goals aren't the whole story.** Expected goals would separate lucky finishing from genuinely good chances; these files don't include it.

## Conclusion

A goal of goal difference is worth about 0.63 points in Scottish football, and goal difference explains 93% of the variation in points. The gaps between points and goals are real enough to matter, four wins' worth at the extremes, but they don't last: a team that beat its goals this season is barely more likely than anyone else to do it again. When judging a team, trust its goal difference over its points.

## Reproduce the analysis

The results files are published by [football-data.co.uk](https://www.football-data.co.uk/scotlandm.php). Download the Premiership (SC0) and Championship (SC1) files for each season from 2000/01 to 2025/26 and save each under its own name, such as `SC0_2425.csv` and `SC1_2425.csv`; they aren't rehosted on this site. Then:

```python
import csv
from collections import Counter
from math import sqrt

names = [f"{y % 100:02d}{(y + 1) % 100:02d}" for y in range(2000, 2026)]
seasons = {}  # (season, division, team) -> wins, draws, goals for, goals against, games, points
for s in names:
    for div in ("SC0", "SC1"):  # Premiership and Championship
        tally = {}
        with open(f"{div}_{s}.csv", encoding="latin-1") as f:
            for r in csv.DictReader(f):
                if r.get("FTR") not in ("H", "D", "A"):
                    continue
                h, a, x, y = r["HomeTeam"], r["AwayTeam"], int(r["FTHG"]), int(r["FTAG"])
                for team, scored, conceded in ((h, x, y), (a, y, x)):
                    t = tally.setdefault(team, Counter())
                    t["w"] += scored > conceded; t["d"] += scored == conceded
                    t["gf"] += scored; t["ga"] += conceded; t["n"] += 1
                    t["pts"] += 3 * (scored > conceded) + (scored == conceded)
        seasons.update({(s, div, team): t for team, t in tally.items() if t["n"] >= 20})  # drops a few stray rows

def fit(xs, ys):  # straight line through the points: slope, intercept, correlation
    mx, my = sum(xs) / len(xs), sum(ys) / len(ys)
    sxy = sum((x - mx) * (y - my) for x, y in zip(xs, ys))
    sxx, syy = sum((x - mx) ** 2 for x in xs), sum((y - my) ** 2 for y in ys)
    return sxy / sxx, my - sxy / sxx * mx, sxy / sqrt(sxx * syy)

t = list(seasons.values())
slope, start, r = fit([(v["gf"] - v["ga"]) / v["n"] for v in t], [v["pts"] / v["n"] for v in t])
print(f"{len(t)} team-seasons: points a game = {start:.2f} + {slope:.3f} x goal difference a game; explains {r * r:.0%}")

edges = [-9, -1.2, -0.8, -0.4, 0, 0.4, 0.8, 1.2, 1.6, 9]  # average points a game in bands of goal difference a game
for lo, hi in zip(edges, edges[1:]):
    band = [v for v in t if lo < (v["gf"] - v["ga"]) / v["n"] <= hi]
    gd_avg = sum((v["gf"] - v["ga"]) / v["n"] for v in band) / len(band)
    print(f"  goal difference {gd_avg:+.2f} a game ({len(band)} team-seasons): {sum(v['pts'] / v['n'] for v in band) / len(band):.2f} points a game")

# goals scored and goals conceded separately (two-variable least squares)
x1, x2, y = [v["gf"] / v["n"] for v in t], [v["ga"] / v["n"] for v in t], [v["pts"] / v["n"] for v in t]
m1, m2, my = sum(x1) / len(t), sum(x2) / len(t), sum(y) / len(t)
s11, s22 = sum((a - m1) ** 2 for a in x1), sum((b - m2) ** 2 for b in x2)
s12 = sum((a - m1) * (b - m2) for a, b in zip(x1, x2))
s1y, s2y = sum((a - m1) * (c - my) for a, c in zip(x1, y)), sum((b - m2) * (c - my) for b, c in zip(x2, y))
det = s11 * s22 - s12 ** 2
print(f"each goal scored {(s22 * s1y - s12 * s2y) / det:+.2f} points, each goal conceded {(s11 * s2y - s12 * s1y) / det:+.2f}")

# Pythagorean: share of results (a draw counts half) against goals for^k / (goals for^k + goals against^k)
share = lambda v: (v["w"] + v["d"] / 2) / v["n"]
pyth = lambda v, k: v["gf"] ** k / (v["gf"] ** k + v["ga"] ** k)
error, k = min((sum((share(v) - pyth(v, k / 100)) ** 2 for v in t), k / 100) for k in range(80, 250))
print(f"best exponent k = {k}, typical miss {sqrt(error / len(t)):.1%} of results")
beat = {key: (share(v) - pyth(v, k)) * v["n"] for key, v in seasons.items()}  # wins' worth above expectation
ranked = sorted(beat, key=beat.get)
for key in ranked[-5:][::-1] + ranked[:5]:
    v = seasons[key]
    print(f"  20{key[0][:2]}/{key[0][2:]} {key[2]} ({'Premiership' if key[1] == 'SC0' else 'Championship'}): "
          f"{v['pts']} points, goal difference {v['gf'] - v['ga']:+}, {beat[key]:+.1f} wins' worth")

# does beating your goals carry over to next season? same team, same division, consecutive seasons
pairs = [(key, (names[names.index(key[0]) + 1], key[1], key[2])) for key in seasons
         if key[0] != names[-1] and (names[names.index(key[0]) + 1], key[1], key[2]) in seasons]
luck = fit([beat[a] / seasons[a]["n"] for a, _ in pairs], [beat[b] / seasons[b]["n"] for _, b in pairs])[2]
gd = fit([(seasons[a]["gf"] - seasons[a]["ga"]) / seasons[a]["n"] for a, _ in pairs],
         [(seasons[b]["gf"] - seasons[b]["ga"]) / seasons[b]["n"] for _, b in pairs])[2]
print(f"{len(pairs)} pairs of seasons: beating your goals correlates {luck:.2f} with next season (±{1.96 / sqrt(len(pairs)):.2f}); goal difference {gd:.2f}")
```

## Further reading

- [Pythagorean expectation](https://en.wikipedia.org/wiki/Pythagorean_expectation), Wikipedia. The formula's origins in baseball and how it's been adapted for basketball, hockey and American football.
- [Regression toward the mean](https://en.wikipedia.org/wiki/Regression_toward_the_mean), Wikipedia. Why teams that overachieve one season tend to come back to earth.
- [Goal difference](https://en.wikipedia.org/wiki/Goal_difference), Wikipedia. How it's used to separate teams, and its alternatives.
