Methodology
How The Northern Vibe Project works: plain English first, technical depth below.
What Northern Vibe does
Northern Vibe projects the seat outcome of a Canadian federal election as of today. It combines national and regional polling averages with riding-level demographic baselines and economic indicator trends, then runs 10,000 simulated elections to produce a probability distribution over seat counts rather than a single point estimate. (The daily pre-computed run uses 10,000 simulations; live scenario runs on the map use 2,000.) The result is a range of plausible outcomes and a probability for each scenario (majority, minority, or opposition win), not a prediction that any one outcome will definitely happen.
Inputs
Polling aggregate. National and regional vote-intention polls going back to 2004, with a 21-day rolling window and exponential recency decay (14-day half-life). Each poll is house-effect-corrected before entering the average (see below).
Economic indicators. Real GDP growth, unemployment rate, and CPI from Statistics Canada. A Bayesian trajectory model (PyMC) translates these, alongside a media sentiment covariate (see Accountability below), into a medium-term support prior that grounds the short-term poll average.
2025 riding baselines. Certified GE45 results at the riding level provide the starting point for the simulation. Demographic covariates from the 2021 Statistics Canada Census (income, age, housing tenure, immigration share) shift the swing away from the national average in each riding.
Historical baseline
Every riding starts with its historical voting pattern (how people voted in 2021 and 2025), adjusted for who actually lives there. A riding full of renters in their twenties and thirties behaves differently than a rural riding with a large retiree population.
Polling & vote transfer
Polling data provides the national and regional mood. If the Liberals drop three points nationally, the model distributes that drop across ridings using empirically calibrated vote-transfer matrices: votes leaving one party flow to other parties in the proportions observed between the 2021 and 2025 election transitions, rather than being distributed uniformly. The simulation also applies structural regional corrections that national swing alone can't capture.
Why vote share doesn't predict seats
National vote share can move in the opposite direction from seat count. A party can lose two points of national support and still gain seats, or gain a point and lose seats. This isn't a quirk of the model. It reflects a structural feature of Canadian federal elections under first-past-the-post, and it is one of the most common sources of confusion when comparing two forecast scenarios.
Vote share is national; seats are local. A party can lose support concentrated in regions where it already wins every seat (or already loses every seat), with no effect on the seat count. Recent forecasts have shown the Liberals losing close to two points of national support while still gaining a small number of seats, because most of the drop occurred in Alberta and rural Saskatchewan, where the LPC seat count is near zero anyway.
Three-way races are sensitive to second-place support. When the NDP gains a point of support, those voters don't come uniformly from the Liberals. The vote-transfer matrix estimates that NDP gains pull disproportionately from CPC-leaning urban and suburban voters in Ontario. That cross-pressure can tighten LPC versus CPC marginals even when LPC's own vote share is falling.
Regional adjustments matter. The simulation applies calibrated regional intercepts on top of national swing: an Alberta CPC floor of 45%, a BC NDP baseline intercept, and an Atlantic uncertainty multiplier. These encode patterns visible in past elections that pure uniform swing misses.
The practical implication is that you cannot infer seat changes from vote share changes alone, and a forecast that does so will mislead. The seat projection on this site is computed riding by riding using local fundamentals, demographic transitions, and the vote-transfer matrix, then aggregated to the national total.
Monte Carlo simulation
To turn all of that into seat counts, the model runs 2,000 simulated elections per live scenario (the daily pre-computed run uses 10,000). Each simulation adds correlated randomness (ridings in the same province move together to reflect the province-level swings that happen on election night), then counts who wins each riding. The result is a probability distribution: not just "LPC wins 170 seats" but "LPC wins between 155 and 185 seats 80% of the time."
Scenario Builder
The Scenario Builder lets you apply your own assumptions on top of all of this. Shift the NDP up five points or collapse Liberal support nationwide. The simulation reruns immediately and the map updates. Click any riding to see its full probability breakdown, previous election results, and riding profile.
The results table reports five statistics for each party. Mean is the average seat count across all 2,000 simulated elections. p10 and p90 are the 10th and 90th percentiles: 80% of simulations produced a result within that range. Majority % is the share of simulations in which that party won 172 or more seats. Minority % is the share in which they won the most seats but fell short of a majority.
Volatility tiers
Volatility tiers appear in two places and mean slightly different things. On individual riding pages, the tier is based on the certified April 2025 election margin between first- and second-place finishers: TOSSUP (<5 pp), SWING (5–10 pp), LEAN (10–20 pp), SAFE (≥20 pp). On the map riding drawer, the tier reflects the current simulation: it is derived from the leading party's win probability across 2,000 simulated elections under the active scenario. This means the drawer tier updates as you move scenario sliders, giving a live read on how competitive each riding is under your assumptions rather than how it finished on election night.
Polling aggregator
The aggregate is a rolling 21-day weighted average: polls conducted closer to today receive more weight than older ones, following an exponential decay curve with a 14-day half-life that prioritises recency while still incorporating the signal in earlier surveys. The aggregator also applies a house effect correction: each polling firm's historical tendency to over- or under-estimate each party's support is estimated from past elections and subtracted before combining results. The 95% confidence interval shown in the polls table is derived from the spread of polls within the window. The aggregate refreshes automatically as new polls are published.
Accountability
The Accountability page tracks how Canadian media assigns political blame and credit in real time. Every day the platform fetches political news headlines, classifies each article for relevance and framing, and scores whether coverage attributes economic conditions to government decisions or to forces beyond its control. Those scores are aggregated into a 28-day exponentially weighted signal (the attribution modifier) that feeds the forecast model as an additional directional input.
Economic forecast
The Forecast page projects where the parties are likely to stand 1, 3, and 6 months from now, with calibrated uncertainty bands that widen with each horizon. A Bayesian trajectory model (PyMC) is trained on economic time series (inflation, unemployment, housing starts, governing-party tenure) with a media sentiment covariate (valence signal, γ ≈ 0.05) that nudges the fundamental level up or down based on the tone of political news coverage. The model output is blended with current polling to produce forward-looking support estimates.
The sentiment covariate enters the Bayesian model directly as a fitted parameter (γ_valence); it is not a post-hoc adjustment. Its posterior mean is positive and its 94% credible interval is mostly above zero, meaning favourable media coverage is associated with modestly higher governing-party support in the model. Economic fundamentals dominate over the medium term; the sentiment effect is intentionally modest.
By-election open-seat adjustments
When a sitting MP does not contest a by-election, the model applies two literature-calibrated corrections. First, the personal-vote incumbency bonus (3.2 pp, derived from Blais et al. 2003) is removed, since that bonus is tied to the individual MP, not the party. Second, a retirement adjustment is applied: long-serving MPs accumulate an additional personal vote of roughly 0.5–1 pp per electoral cycle (Cain, Ferejohn & Fiorina 1987; Kendall & Rekkas 2012), which also disappears on retirement. For ridings where the departing MP's personal positioning attracted voters who would not otherwise support the party, a BQ recovery adjustment is also applied where appropriate. All parameters carry citation comments in the source code.
How uncertainty is modelled
Every simulated election draws a national vote share from a multivariate normal distribution centred on the current poll average. The variance has two components added in quadrature: the estimation variance from the polling window itself, and a systematic polling error calibrated from past elections.
Systematic polling error (RMSE) is estimated from the gap between the final 7-day poll average and the certified result across all six federal elections from 2008 to 2025:
| Party | Polling RMSE (pp) |
|---|---|
| LPC | 1.8pp |
| CPC | 2.9pp |
| NDP | 2.0pp |
| BQ | 0.5pp |
| GPC | 1.0pp |
| PPC | 1.2pp |
Calibrated across 6 federal elections (2008–2025). Regenerated against certified results after each election.
A province-level correlation structure is also applied so that ridings within the same province move together, reflecting shared regional events rather than independent noise.
Pollster house effects
Every polling firm has a characteristic "house effect": a tendency to over- or under-estimate each party's support relative to the final certified result. This can arise from differences in methodology (phone vs. online), sample weighting, and how undecided voters are handled. If uncorrected, combining polls from multiple firms can amplify a systematic bias in one direction.
We estimate house effects from each firm's final-week polls before GE44 (2021) and GE45 (2025) and apply James-Stein shrinkage: when the sample of past elections is small, the correction is pulled toward zero, so that sparse data produces a modest adjustment rather than an overfit one. The table below shows the current computed adjustments:
| Pollster | LPC | CPC | NDP | BQ | GPC | PPC |
|---|---|---|---|---|---|---|
| Abacus Data | -0.5 | -0.9 | +1.0 | -0.2 | +0.1 | +0.3 |
| Angus Reid | -0.4 | -0.6 | +0.3 | — | +0.1 | — |
| Ekos Research | -0.2 | -1.2 | +0.5 | -0.4 | +0.4 | +0.7 |
| Forum Research | -0.6 | -0.5 | -0.0 | -0.2 | +0.2 | +0.8 |
| Ipsos | -0.6 | -0.8 | +0.8 | -0.1 | +0.2 | -0.1 |
| Léger | -0.3 | -0.5 | +0.4 | -0.1 | +0.1 | +0.3 |
| Mainstreet Research | -0.4 | -0.5 | +0.2 | -0.3 | +0.1 | +0.7 |
| Nanos Research | -0.4 | -0.9 | +0.6 | -0.2 | +0.5 | +0.3 |
pp = percentage points. Positive = firm historically over-predicts this party; the aggregator subtracts this before computing the rolling average. "—" = insufficient data to estimate a correction for this firm/party combination.
What the model does not do
Northern Vibe does not incorporate real-time news sentiment during live campaigns. The accountability tracker reads daily Canadian political headlines to produce a directional modifier, but this is an attribution index based on media framing, not a real-time waveform of campaign events. During an active campaign, the poll aggregate is the dominant input.
The model does not use internal party data, private polling, constituency canvass returns, or any non-public information. All inputs are from publicly available sources listed in the data sources section below.
Track record
The model was validated on GE45 (April 28, 2025) using only the pre-election poll average as input. Full results (riding call accuracy, vote share MAE, seat band coverage, and missed ridings) are on the Model Accuracy page.
Honest limitations
Riding-level accuracy is validated on one general election (GE45). One election is not enough to make strong statistical claims about interval calibration. Whether the 80% bands really contain the true outcome 80% of the time requires many more observations. The current results are encouraging but not conclusive evidence of correct calibration.
National polls carry a ±2–3% margin of error that compounds at the riding level. The model faithfully reproduces the uncertainty in the polls; it does not add or reduce it. If the polls are wrong, the model will be wrong in the same direction.
Demographic data is from the 2021 Census. Fast-growing ridings and those that have seen significant demographic change since 2021 may carry larger errors than the aggregate suggests.
By-election open-seat effects use literature-calibrated retirement adjustments. Candidate quality, local profile, and campaign spending beyond incumbency are not modelled.
Model decision log
Changes to model parameters are documented publicly in docs/model_decisions.md. We do not adjust parameters retroactively to improve past accuracy figures.
How to verify the numbers
The scoring/ directory in the GitHub repository contains a self-contained Python script that reproduces every metric on the accuracy page (MAE, riding call accuracy, 80% band coverage, and the missed-riding list) from a frozen fixture file and the Elections Canada certified results CSV. No simulation imports required:
python scoring/evaluate.py
Data sources
| Source | What it feeds |
|---|---|
| Elections Canada | Riding boundaries, 2021 & 2025 candidate results, EDA campaign finance (2025) |
| Statistics Canada (2021 Census) | Demographics per riding: income, age, housing tenure, immigration, education, commuting, industry; rent baseline scaled to CMHC 2025 CMA prices |
| Statistics Canada (Web Data Service) | Economic indicators: real GDP growth, unemployment rate, CPI |
| Statistics Canada (Crime Severity Index) | CMA-level crime severity, rescaled to national average = 100 |
| CRA (Individual Tax Statistics by FSA) | Tax filer median income, government transfer dependency, EI & benefits recipients, RRSP contributors |
| CMHC | New housing construction starts by metro area (CMA-level) |
| IRCC | Annual permanent residents admitted per CMA, distributed to ridings by population |
| CRTC (National Broadband Data) | % of households without 50/10 Mbps broadband service, by riding |
| NRCan (National Fire Database) | Wildfire exposure index per riding (2015–2024), indexed to national average = 100 |
| NRCan (Flood Susceptibility Mapping) | Mean flood susceptibility index per riding (2000–2023 raster) |
| Pollster Audit API + Polling Canada | National & regional vote-intention polls (2004–present) |
| Nanos Research, Angus Reid, Environics | Issue salience polling: cost of living, housing, healthcare, Canada–US relations |
| OurCommons.ca | MP Hill office contact information (phone & email) |
| Government of Canada (Proactive Disclosure) | Federal grants & contributions by riding, all fiscal years available |
| MediaCloud | Canadian political news headlines: vibe score & party attribution classifier |