# Mauna Loa CO₂: rise, seasonality, and short-term forecasting

The record shows a large, accelerating long-term rise and a persistent annual cycle. Short-term statistical forecasts are useful, but a simple seasonal forecast adjusted for recent growth is a demanding benchmark: it slightly beat the fixed SARIMA model at 12 months.

## Data and provenance

Source: [NOAA Global Monitoring Laboratory monthly Mauna Loa record](https://gml.noaa.gov/webdata/ccgg/trends/co2/co2_mm_mlo.txt), retrieved 24 September 2026; file created 5 September 2026. [NOAA source explanation](https://gml.noaa.gov/ccgg/trends/) was also inspected. NOAA credits C. David Keeling/Scripps for March 1958–April 1974. Units are ppm dry-air mole fraction.

The analysis uses 814 monthly values, March 1958–December 2025. The frozen raw file includes later months, which the code excludes. MD5: `35591deeaf110bca96cc64a7ec337994`; a SHA-256 manifest is supplied in the archive. Dates are unique and form a regular monthly grid. We use the monthly-average column, not NOAA's deseasonalized column.

The prespecified exclusion rule marks negative averages or, from May 1974 onward, jointly negative standard deviation and uncertainty as missing. No rows satisfy that rule. Two rows have ambiguous quality metadata: December 1975 (days −1) and April 1984 (days 2) have negative standard deviation but zero uncertainty. They remain included under the fixed rule; their status cannot be confidently inferred. Early Scripps values have unavailable quality metadata, so unidentified interpolation may remain. This is a limitation, not proof that all historical values were directly observed. All test targets have usable values.

NOAA documents substitution of Maunakea observations from December 2022 through July 4, 2023 following the Mauna Loa shutdown. Those observations are retained. NOAA says the last year of published data remains preliminary; the later part of 2025 may therefore still be subject to recalibration in this snapshot.

## Main patterns

Annual means require all 12 months; incomplete 1958 is excluded from annual comparisons.

| Quantity | Result |
|---|---:|
| 1959 annual mean | 315.98 ppm |
| 2025 annual mean | 427.35 ppm |
| Increase, 1959–2025 | 111.37 ppm (35.24%) |
| Linear slope of annual means, 1960–1969 | 0.81 ppm/year |
| Linear slope of annual means, 2010–2019 | 2.43 ppm/year |
| Linear slope of annual means, 2020–2025 | 2.65 ppm/year |

The rise has accelerated over the long run, although decade-to-decade growth is not monotonic. These are descriptive slopes over stated windows, not causal estimates or forecasts.

For seasonality, fit a linear trend separately within each decade (2020–2025 is a shorter period), then average residuals by calendar month. Peak-to-trough departures are about 5.9–6.9 ppm across the periods examined. The peak is May; the trough is September or October. For 2020–2025 the estimated swing is 6.37 ppm. Differences between period profiles should not be interpreted as a tested secular change in seasonal amplitude: detrending choices, interannual variability, and unequal period lengths matter.

The cycle is consistent with seasonal terrestrial carbon uptake and release, strongly influenced by the Northern Hemisphere. The concentration series alone cannot apportion sources and sinks or establish the mechanisms causing changes in growth.

![Monthly concentrations, annual means, and detrended seasonal profiles](co2_patterns.png)

## Genuinely chronological forecast evaluation

The model, refitting scheme, baselines, and missing-data rules were recorded before examining forecast errors. No model selection or tuning used test performance.

At each monthly origin from December 2020 to November 2025, refit SARIMA (0,1,1)(0,1,1)[12] by maximum likelihood to an expanding window beginning March 1958, with no deterministic trend. Only earlier observations enter that fit. Earlier test-period observations become training inputs after their dates pass; this is rolling-origin evaluation, not one forecast made in 2020 for five years.

For horizons h = 1, 6, 12 months:

- Seasonal naive predicts the value for the same calendar month one year earlier.
- Seasonal drift adds the mean year-over-year increase across the last 60 calendar months available at the origin. At least 12 valid pairs are required.
- Only targets in 2021–2025 are scored. This gives 60, 55, and 49 targets respectively: January 2021, June 2021, and December 2021 are the first targets.

All models have the same eligible targets within each horizon. MAE is mean absolute error; RMSE gives greater weight to large misses; bias is prediction minus observation.

| Horizon | Model | n | MAE (ppm) | RMSE (ppm) | Bias (ppm) |
|---|---|---:|---:|---:|---:|
| 1 month | SARIMA | 60 | 0.299 | 0.378 | −0.036 |
| 1 month | Seasonal naive | 60 | 2.627 | 2.722 | −2.627 |
| 1 month | Seasonal drift | 60 | 0.552 | 0.702 | −0.140 |
| 6 months | SARIMA | 55 | 0.446 | 0.547 | −0.158 |
| 6 months | Seasonal naive | 55 | 2.655 | 2.753 | −2.655 |
| 6 months | Seasonal drift | 55 | 0.600 | 0.750 | −0.181 |
| 12 months | SARIMA | 49 | 0.670 | 0.828 | −0.377 |
| 12 months | Seasonal naive | 49 | 2.728 | 2.824 | −2.728 |
| 12 months | Seasonal drift | 49 | 0.641 | 0.813 | −0.273 |

Seasonal naive systematically misses the ongoing rise. Correcting it for recent growth removes much of that error. SARIMA's benefit is clearest at one month; it is not uniformly superior. The 12-month difference is small and has not been established as statistically significant. Different horizons cover slightly different target periods, so their scores are not a pure isolated test of horizon length.

## Uncertainty and limitations

SARIMA intervals are Gaussian forecast intervals conditional on fitted parameters; they do not incorporate parameter-estimation uncertainty, data revisions, or future structural changes.

| Horizon | 80% coverage | Mean 80% width | 95% coverage | Mean 95% width |
|---|---:|---:|---:|---:|
| 1 month | 47/60 (78.3%) | 0.80 ppm | 54/60 (90.0%) | 1.23 ppm |
| 6 months | 43/55 (78.2%) | 1.36 ppm | 53/55 (96.4%) | 2.08 ppm |
| 12 months | 33/49 (67.3%) | 1.82 ppm | 46/49 (93.9%) | 2.78 ppm |

Coverage is uneven, particularly for 12-month 80% intervals. All 60 fits converged without warnings. Training-residual lag-1 autocorrelation was 0.015–0.024; 24-lag Ljung–Box p-values were 0.381–0.801. These diagnostics did not reveal strong remaining training-residual dependence, but they do not guarantee calibrated future uncertainty.

Held-out forecast errors themselves are dependent: lag-1 correlations are approximately 0.02, 0.62, and 0.75 at 1, 6, and 12 months. Overlapping forecasts are not independent replicates. With only five test years, interval coverage and differences between models remain uncertain; no independent-error significance tests or binomial confidence bounds are asserted.

This is a current-vintage historical evaluation, not an archived real-time backtest: later recalibration and publication delays are not reconstructed. It is genuinely held out in chronological fitting and model choice, but not in data vintage. Mauna Loa is a valuable background station, not a direct global-average measurement or emissions inventory. Statistical extrapolation cannot predict policy-driven emissions pathways, abrupt carbon-cycle shifts, or long-term climate outcomes.

![Held-out mean absolute errors and 12-month SARIMA errors with conditional intervals](forecast_evaluation.png)

## Reproduce and inspect

Extract the archive into a new directory and run `Rscript analysis.R` there, or open R in that directory and run `source("analysis.R")`. Only base/recommended R packages are used; R 4.4.3 was tested. The script is offline and verifies the frozen input's checksum before analysis. It recreates cleaned data, descriptive tables, every held-out prediction and interval, diagnostics, metrics, validation checks, and both figures.

The final script was rerun against the frozen input and reproduced all forecast metrics within 1e−12. Boundary checks, baseline arithmetic, and metric arithmetic passed; figures were visually inspected. Python statsmodels was unusable because of an installed dependency incompatibility; the approved base-R implementation required no installations or application changes. Exact environment information and a file-level SHA-256 manifest are included.
