Skip to content

perf: Replace statsmodels OLS+f_test with numpy/scipy in Granger F-test - #46

Merged
cbueth merged 6 commits into
mainfrom
perf/fast-granger-f-test
Jul 30, 2026
Merged

perf: Replace statsmodels OLS+f_test with numpy/scipy in Granger F-test#46
cbueth merged 6 commits into
mainfrom
perf/fast-granger-f-test

Conversation

@cbueth

@cbueth cbueth commented Jul 29, 2026

Copy link
Copy Markdown
Owner

This replaces the statsmodels OLS + F-test path in Granger causality with a numpy/scipy linear algebra implementation that produces identical p-values.

The old code called statsmodels.OLS.fit() + f_test() for every lag of every pair. As example, that would be 51,450 OLS regressions for a 50-node network with 21 lags. Each statsmodels call has heavy overhead: class instantiation, data validation, result object tree construction. The new implementation computes the same F-statistic and p-value using np.linalg.solve / scipy.linalg.lstsq directly.

71ed1a4 contains 6 variants of the F-test (normal equations, QR, Cholesky, scipy.lstsq, two-regression QR/Cholesky), all were benchmarked against statsmodels. The fastest variant (normal equations) gives about 8x speedup with p-values matching to machine epsilon 🥳 carrying over to the network reconstruction funcationality.

Statsmodels is still used for design matrix construction (lagmat2ds) but the OLS fitting is gone from the central network reconstruction path. The old granger.py is kept as-is, the new code lives in _granger_fast.py and is wired in as the "gc" connectivity metric.
Also includes a comprehensive test suite: p-value parity against statsmodels across grid of T/L values, causal lag detection, collinear data edge cases, constant time series, dispatch parity, and multi-lag optimal lag matching.

cbueth added 4 commits July 29, 2026 13:20
- NODE_SIZES [5,15] (was [10,20,40,50])
- Remove SMALL_NODES and continuous_data_small (unified)
- Unified _RECON_METRICS = lc/rc/gc/gv
- ts_len 500 → 200 in isolated metric benchmarks
- N_TESTS 5 → 2 (mi/te benchmarks)
- Drop cop/random_patterns from isolated metrics
- Drop continuous_data_20 fixture
- Workers test simplified to [1, 2]
Signed-off-by: Carlson Büth <commit@cbueth.de>
Signed-off-by: Carlson Büth <commit@cbueth.de>
@cbueth cbueth self-assigned this Jul 29, 2026
@cbueth cbueth added the enhancement New feature or request label Jul 29, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 29, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
❌ 1 regressed benchmark
✅ 13 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
test_ordinal_patterns 9.4 ms 23.1 ms -59.4%
test_reconstruct[nodes10-gc] 300.4 ms 143.4 ms ×2.1
test_reconstruct[nodes5-gc] 67.5 ms 32.4 ms ×2.1
test_granger_f_test 3.3 ms 1.7 ms +95.73%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing perf/fast-granger-f-test (a9c0fa6) with main (d9c47e1)

Open in CodSpeed

@cbueth
cbueth force-pushed the perf/fast-granger-f-test branch from 19fa9b4 to c2848ba Compare July 29, 2026 15:51
cbueth added 2 commits July 30, 2026 09:44
- Replace statsmodels OLS+f_test with numpy/scipy normal-equations F-test in granger.py
- Remove _granger_fast.py (5 unused F-test variants + benchmark helpers + dead code)
- Keep only the single optimal implementation (same API: gt_single_lag, gt_multi_lag)
- Remove statsmodels as dependency from the Granger hot path (still used for design matrix)
- Merge tests from test_fast_granger.py into test_granger.py, remove test_fast_granger.py
- Keep public API fully stable, no user-facing changes required
@cbueth
cbueth force-pushed the perf/fast-granger-f-test branch from c2848ba to a9c0fa6 Compare July 30, 2026 07:44
@cbueth

cbueth commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

The only regression comes from runner changes, and the 2.1 speedup is underestimated, as the system calls on this other runner shadow the speedup.

@cbueth
cbueth merged commit c7d03fe into main Jul 30, 2026
9 of 10 checks passed
@cbueth
cbueth deleted the perf/fast-granger-f-test branch July 30, 2026 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant