Overview
This page provides comprehensive benchmarks across all 4 backend/language combinations and all dataset sizes, clearly showing which computational strategy (YOCO+sparse vs FWL demeaning) was used in each case.
Strategy Selection
leanfe automatically selects the optimal strategy based on FE cardinality:
| Max FE ≤ 10K, Total FE ≤ 20K, No IV |
YOCO + Sparse |
Compression + sparse matrices are efficient |
| Max FE > 10K or Total FE > 20K |
FWL Demeaning |
Avoids huge sparse matrices |
| IV/2SLS |
FWL Demeaning |
YOCO doesn’t support instruments |
In these benchmarks, we use FE1=500 and FE2=100 levels (total=600), so YOCO + Sparse is always selected.
Benchmark Configuration
- Dataset sizes: 100K, 1M, 10M, 100M observations
- Fixed effects: FE1 (500 levels) + FE2 (100 levels)
- Regressors: Binary treatment + discrete x1 (0, 1, 2)
- Standard errors: IID (all use YOCO path)
- Metrics: Runtime (seconds), Peak memory (MB), Strategy used
Python Benchmarks
Python Comprehensive Benchmark (IID Standard Errors)
==============================================================================================================
Obs Backend Time Memory Strategy Compressed Ratio
--------------------------------------------------------------------------------------------------------------
100,000 polars 0.48s 20.0MB compress 83,280 83.28%
100,000 duckdb 1.60s 51.1MB compress 82,981 82.98%
1,000,000 polars 1.47s 67.6MB compress 278,175 27.82%
1,000,000 duckdb 1.95s 86.7MB compress 278,210 27.82%
10,000,000 polars 2.34s 73.9MB compress 300,000 3.00%
10,000,000 duckdb 3.32s 94.5MB compress 300,000 3.00%
100,000,000 polars 9.81s 73.9MB compress 300,000 0.30%
100,000,000 duckdb 16.45s 94.5MB compress 300,000 0.30%
Note: Strategy 'compress' = YOCO + Sparse Matrix path
R Benchmarks
R Comprehensive Benchmark (IID Standard Errors)
====================================================================================================
Obs Backend Time Strategy Compressed Ratio
----------------------------------------------------------------------------------------------------
100,000 polars 0.44s compress 83,016 83.02%
100,000 duckdb 0.56s compress 83,136 83.14%
1,000,000 polars 0.45s compress 278,491 27.85%
1,000,000 duckdb 0.81s compress 278,213 27.82%
10,000,000 polars 1.02s compress 300,000 3.00%
10,000,000 duckdb 2.65s compress 300,000 3.00%
100,000,000 polars 9.44s compress 300,000 0.30%
100,000,000 duckdb 25.14s compress 300,000 0.30%
Note: Strategy 'compress' = YOCO + Sparse Matrix path
Summary Table
The table below summarizes all 4 combinations across all dataset sizes:
| 100K - 100M |
Python |
Polars |
YOCO + Sparse |
FE1=500, FE2=100 → total 600 < 20K threshold |
| 100K - 100M |
Python |
DuckDB |
YOCO + Sparse |
Same FE cardinality, same strategy |
| 100K - 100M |
R |
Polars |
YOCO + Sparse |
Same FE cardinality, same strategy |
| 100K - 100M |
R |
DuckDB |
YOCO + Sparse |
Same FE cardinality, same strategy |
Why YOCO + Sparse is Always Selected Here
With FE1=500 and FE2=100 levels:
- Max single FE: 500 ≤ 10,000 threshold ✓
- Total FE levels: 600 ≤ 20,000 threshold ✓
- No IV/2SLS: ✓
All conditions for YOCO are met, so the sparse matrix path is used for all benchmarks.
FWL Demeaning Benchmark (High-Cardinality FEs)
To demonstrate the FWL path, we use high-cardinality FEs (50K levels) which exceed the YOCO threshold:
High-Cardinality FE Benchmark (FE1=50K, FE2=1K → triggers FWL)
==========================================================================================
Obs Backend Time Strategy Iterations
------------------------------------------------------------------------------------------
768
0
100,000 polars 0.45s fwl 13
0
0
100,000 duckdb 1.35s fwl 13
0
0
1,000,000 polars 0.48s fwl 4
0
0
1,000,000 duckdb 1.55s fwl 4
Note: With FE1=50K > 10K threshold, FWL demeaning is selected instead of YOCO