Skip to main content
Certains contenus sont encore en cours de traduction — le support complet en français arrive bientôt. Some content is still being translated — full French support coming soon.

Model Accuracy

How has the forecast performed against real election results?

2025 Federal Election Calibration

Ridings Called Correctly

97.7%

334 of 342 ridings 343 ridings total. Terrebonne (QC) is excluded; its result was nullified by the courts after the election.

Vote Share MAE

0.9pp

Mean absolute error across 6 parties

80% Bands Hit

5/5

Parties whose actual seats fell in projected range

CPC / LPC Seat Swing

CPC +15 · LPC -14

Seats vs. median projection

Why 80% intervals? We report 80% bands (not 95%) because they're easier to validate against real results. A 95% interval almost never misses, making it hard to test whether the model is actually calibrated. With a single election, a model can pass a 95% CI test by accident; an 80% CI is genuinely informative. See methodology →

Analysis & Commentary

A written breakdown of where the model was right, where it was wrong, and why.

Going into election night, the model gave the Liberals a 68.4% chance of a majority. They fell 4 seats short, landing at 168, just below the 172-seat majority threshold and near the lower edge of the model's 80% range (156–212). That was the headline miss: the model leaned majority, but a narrow minority was the outcome.

The CPC miss is the key residual error. Using the final day's polls, the model showed them at 39.1%; they ended up at 41.5%, a 2.4pp gap that is entirely attributable to polling error. The polls hadn't fully closed on the late CPC surge, even by April 27. Critically, the model itself didn't amplify this: the simulation reproduced the poll average faithfully and added no further CPC underestimation. CPC's actual 144 seats landed comfortably inside the 80% band (101–155).

Everywhere else, the model was sharp. LPC vote share landed within 0.6pp of the forecast. BQ, NDP, GPC, and PPC were all inside their calibrated error bands. The model called 334 of 342 ridings correctly (97.7%), with just 8 misses, concentrated in tight LPC/CPC marginals in Ontario and BC. All six parties fell within their 80% seat intervals, and four of six were within 2 seats of the median.

This calibration uses the final-day poll average from April 27, 2025, one day before voting. The 0.87pp MAE reflects the residual polling error that persisted even with fully up-to-date inputs; the model's simulation layer did not add noise beyond what the polls contained.

National Vote Share

Predicted = model simulation output using the poll average as of 2025-04-27 (not the raw poll average). Actual = certified 2025 election result.

PartyPredictedActualError
Liberal43.4%44.0%+0.6pp
Conservative39.1%41.5%+2.4pp
NDP7.7%6.3%-1.3pp
Bloc Québécois6.2%6.3%+0.1pp
Green1.4%1.2%-0.2pp
People's1.3%0.7%-0.6pp

Error = actual − predicted. Positive = party outperformed the forecast; negative = underperformed.

Model Forecast

LPC Majority
68.4%
LPC Minority
22.3%
CPC Minority
7.5%
CPC Majority
1.9%

Actual Result

LPC Minority

LPC: 168 seats · CPC: 144 seats

Majority threshold: 172 seats · LPC fell 4 short

Seat Projection

Monte Carlo distribution from 10,000 simulated elections using the pre-election poll average (validation runs use 10,000; live scenario runs on the map use 2,000). Brackets show the 80% range (p10–p90).

PartyMedian80% rangeActualError
Liberal182156–212168-14
Conservative129101–155144+15
NDP85–127-1
Bloc Québécois2217–27220
Green10–210
People's00–00

Actual seat counts in green fell within the 80% projected range; red fell outside. Error = actual − median. Positive = party won more seats than projected.

Why vote share accuracy and seat accuracy can differ

A small miss on vote share can produce a large miss on seats, or the reverse. Both are normal.

Comparing the vote share table above to the seat projection table can be confusing. The model might predict a party's national vote share within half a point but still miss several seats, or hit the seat count almost exactly while overestimating the vote by a full percentage point. Both outcomes are common under first-past-the-post.

Three structural reasons account for the gap. First, vote share is a national number but seats are decided riding by riding: a party can be off by a point nationally with most of that error landing in regions where the seat count doesn't change. Second, three-way races are sensitive to where second- and third-place support sits, so a small shift in NDP support can flip several Liberal versus Conservative marginals without moving the headline LPC and CPC numbers. Third, the model applies regional adjustments (Alberta CPC floor, BC NDP baseline, Atlantic variance multiplier) that reflect historical patterns and partially decouple national swing from local outcomes.

This is why we publish vote share error and riding call accuracy separately. They measure different things, and a forecast is only credible if it gets both roughly right. See methodology for the full mechanism →

Regional Accuracy

Riding call accuracy broken down by region.

Atlantic
31/3296.9%
Quebec
77/77100.0%
Ontario
120/12298.4%
Prairies
64/6598.5%
BC
40/4393.0%
Northsmall sample
2/366.7%

Missed Ridings (8)

Ridings where the model called the wrong winner, sorted by actual certified margin — closest calls first.

RidingModel called (win prob.)Actual winnerMargin
Windsor—Tecumseh—LakeshoreONLPC51.9%CPC0.1pp
NunavutNULPC60.4%NDP0.6pp
Acadie—AnnapolisNSLPC71.8%CPC1.1pp
Markham—UnionvilleONLPC62.8%CPC3.6pp
New Westminster—Burnaby—MaillardvilleBCNDP50.8%LPC3.6pp
Cowichan—Malahat—LangfordBCNDP55%CPC4.6pp
Edmonton RiverbendABLPC55%CPC5.4pp
North Island—Powell RiverBCNDP49.7%CPC6.1pp

% = model's win probability for the party it (wrongly) called. Margin = certified vote share gap between 1st and 2nd place; red = under 1pp, amber = under 3pp.

By-Election Track Record

Top-two margin predicted within 7.7pp on average

Winner calls: 4/4 correct

University—Rosedale

ON · 2026-04-13

LPC wonCalled correctly
PartyPredictedActualError
Liberal64.0%64.4%+0.5pp
Conservative16.4%12.4%-4.0pp
NDP12.8%18.9%+6.1pp
Green3.6%2.9%-0.7pp
LiberalConservative marginPredicted: 47.6ppActual: 52.0ppError: +4.4pp

Predicted = 2025 election result for this riding + national polling swing as of 2026-04-12.

Scarborough Southwest

ON · 2026-04-13

LPC wonCalled correctly
PartyPredictedActualError
Liberal61.5%69.6%+8.1pp
Conservative23.5%18.8%-4.7pp
NDP7.9%5.9%-2.0pp
Green3.3%2.5%-0.8pp
LiberalConservative marginPredicted: 38.0ppActual: 50.8ppError: +12.8pp

Predicted = 2025 election result for this riding + national polling swing as of 2026-04-12.

Terrebonne

QC · 2026-04-13

LPC wonCalled correctly
Non-trivial call: Terrebonne was a statistical coin-flip going in (BQ–LPC polling within the margin of error). The model called the BQ–LPC margin within 1.3pp.
PartyPredictedActualError
Liberal38.6%48.3%+9.6pp
Conservative11.1%3.3%-7.8pp
NDP5.5%0.5%-5.0pp
Bloc Québécois38.5%46.9%+8.4pp
Green2.9%0.4%-2.5pp
LiberalBloc Québécois marginPredicted: 0.1ppActual: 1.4ppError: +1.3pp

Predicted = 2025 election result for this riding + national polling swing as of 2026-04-12.

Battle River—Crowfoot

AB · 2025-08-18

CPC wonCalled correctly
PartyPredictedActualError
Liberal11.8%4.3%-7.5pp
Conservative76.2%80.9%+4.8pp
NDP6.8%2.1%-4.7pp
Green2.0%0.2%-1.8pp
ConservativeLiberal marginPredicted: 64.3ppActual: 76.6ppError: +12.3pp

Predicted = 2025 election result for this riding + national polling swing as of 2025-08-17.

Why margins, not vote shares? By-election turnout and local candidate effects shift absolute vote-share levels in ways that national polling can't anticipate. But the relative positioning of parties, which is what determines seat outcomes, is captured by the national swing prior. Margin accuracy is therefore the better signal: it tests exactly what the model is optimised for. Four margin errors averaging single-digit accuracy is a more informative validation sample than four binary winner calls.

Reproduce these numbers yourself

The scoring harness is public; you don't have to take our word for it. Clone the repo and run:

python scoring/evaluate.py

github.com/Northern-Vibe/scoring → · Neither 338 nor Poliwave publishes an equivalent harness.