CMPT 353 final project. The question: to what extent can economic, climate, and geopolitical variables predict monthly Ontario grocery-price inflation? The target is the year-over-year change of Ontario's "food purchased from stores" CPI; ten data sources across three themes are cleaned, merged, and used for statistical inference and walk-forward forecasting.
| theme | data | source |
|---|---|---|
| target | CPI (food from stores, all-items, core, energy, gasoline; Canada/Ontario/Toronto) | StatCan 18-10-0004 via Web Data Service API |
| target (item level) | retail food prices, Canada 1995-2022 | StatCan 18-10-0002 (discontinued) |
| target (item level) | retail food prices, Canada + Ontario 2017- | StatCan 18-10-0245 |
| economic | Ontario fuel price survey (weekly) | data.ontario.ca fuels-price-survey-information |
| economic | CAD/USD exchange rate (daily) | FRED DEXCAUS |
| climate | Toronto daily weather 1990-2026 | NASA POWER API (43.6532 N, -79.3832 W) |
| climate | US statewide Palmer Drought Severity Index | NOAA climdiv climdiv-pdsist |
| climate | ENSO index (MEI v2) | NOAA PSL |
| geopolitical | Geopolitical Risk index (GPR, GPRC_CAN) | matteoiacoviello.com |
| geopolitical | Canada Economic Policy Uncertainty | FRED CANEPUINDXM (mirror of policyuncertainty.com) |
US drought data is used deliberately: Ontario imports most of its winter produce from the US (California in particular), so US growing conditions are a supply-side signal for Ontario retail prices.
pip install -r requirements.txt
Python 3.11 was used. Library versions in requirements.txt are the tested
ones; recent versions should also work.
| command | what it does | needs network? |
|---|---|---|
python 01_download_data.py |
downloads all raw sources into data_raw/ (~26 MB). Optional args: source names (e.g. fuel mei) and --force to re-download |
yes |
python 02_clean_data.py |
tidies every source to monthly tables in data/ and joins them into data/monthly_master.csv (438 months x 30 columns, 1990-2026, no missing values) |
no |
python 03_splice_basket.py |
matches products across the two retail tables, validates the match during the 2017-2022 overlap, growth-splices an Ontario basket back to 1995, and checks it against official CPI | no |
python 04_analysis_inference.py |
spurious-correlation demo, lag cross-correlations, OLS with Newey-West errors, ENSO ANOVA + Tukey | no |
python 05_analysis_ml.py |
walk-forward forecasting (2010-2026) at 1- and 6-month horizons: linear/ridge/lasso/random-forest/gradient-boosting vs a persistence baseline, feature-theme ablation, permutation importance. Takes a few minutes | no |
The cleaned data/ tables are committed, so steps 03-05 run without
downloading anything. data_raw/ is not committed (except truncated format
samples in data_raw/samples/); step 01 recreates it. All randomized models
use random_state=353.
figures/- all report figures (03_.png ... 05_.png)results/splice_validation.csv- per-item cross-table match statistics and which of the 40 candidate matches survived the pre-committed thresholdsresults/splice_summary.txt- the three splice validation checksresults/lag_correlations.csv,results/ols_hac.txt,results/ols_coefficients.csv,results/enso_anova.txt- inference outputsresults/ml_metrics.csv- MAE/RMSE/R^2/skill for every model x feature set x horizon;results/ml_predictions.csv- all out-of-sample predictions;results/ml_importance.csv- permutation importances;results/ml_error_test.txt- paired Wilcoxon test of the climate improvement
features.py- shared feature engineering (YoY transforms, weather anomalies vs 1990-2020 climatology, log transforms for skewed indices)plotstyle.py- shared matplotlib stylingreport/- project report