YOCO + Sparse Matrix for Blazing Fast Cluster-Robust Inference
Overview
leanfe now supports clustered standard errors with YOCO compression, implementing Section 5.3.1 of Wong et al. (2021). This enables cluster-robust inference at the same blazing speed as IID/HC1 standard errors.
The Challenge
Traditional clustered SE computation requires:
Computing residuals for all n observations
Summing scores within each cluster (loop over C clusters)
Building the meat matrix from cluster scores
This is slow for large datasets with many clusters.
The YOCO Solution (Section 5.3.1)
The key insight is within-cluster compression: include the cluster identifier in the GROUP BY, so each compressed record belongs to exactly one cluster.
\(\tilde{e}^0 = \tilde{y}^0 - \tilde{n} \odot \hat{y}\) = sum of residuals per group
\(\tilde{W}_C\) = sparse cluster indicator matrix (G × C)
Implementation
leanfe uses sparse matrices for efficient cluster score aggregation:
# Build sparse cluster indicator matrix W_CW_C = sparse.csr_matrix((ones, (group_idx, cluster_idx)), shape=(G, C))# Compute scores per group: diag(e0) @ M = X * e0[:, None]scores_g = X.multiply(e0_g[:, np.newaxis]) # G x p sparse# Aggregate within clusters using sparse matrix multiplicationcluster_scores = W_C.T @ scores_g # C x p# Meat matrix: sum of outer productsmeat = cluster_scores.T @ cluster_scores
This avoids explicit loops and enables vectorized computation.
Benchmark: Clustered SEs
All benchmarks use standardized data generation (see Methodology):
10,000,000 5,000 60.01s 73.49s 2341 MB 3101 MB 99.6%
✓ All backends use YOCO compression strategy
✓ Clustered SEs computed from compressed data
✓ Results match between Polars and DuckDB
The compression ratio shows how much data reduction YOCO achieves:
print("YOCO Compression for Clustered SEs")print("="*60)print(f"{'Observations':>15}{'Clusters':>10}{'Compressed':>15}{'Ratio':>10}")print("-"*60)for r in py_cluster_results: n_compressed =int(r["n_obs"] * r["compression"])print(f"{r['n_obs']:>15,}{r['n_clusters']:>10,}{n_compressed:>15,}{r['compression']:>9.1%}")
YOCO Compression for Clustered SEs
============================================================
Observations Clusters Compressed Ratio
------------------------------------------------------------
100,000 100 99,789 99.8%
1,000,000 1,000 998,092 99.8%
10,000,000 5,000 9,961,559 99.6%
R Implementation
The R package also supports YOCO + sparse matrix for clustered SEs:
# R Implementation Example (requires Matrix package)library(Matrix)# Source the package (in production, use library(leanfe))source("../../r/R/common.R")source("../../r/R/compress.R")# Test sparse cluster matrix buildercluster_ids <-c("A", "A", "B", "B", "C", "A", "C", "B", "C", "A")result <-.build_sparse_cluster_matrix(cluster_ids)cat("R Sparse Cluster Matrix Test\n")cat("============================\n")cat("Cluster IDs:", paste(cluster_ids, collapse=", "), "\n")cat("N groups:", length(cluster_ids), "\n")cat("N clusters:", result$n_clusters, "\n")cat("Matrix class:", class(result$W_C)[1], "\n")cat("Matrix dimensions:", paste(dim(result$W_C), collapse=" x "), "\n")
Output:
R Sparse Cluster Matrix Test
============================
Cluster IDs: A, A, B, B, C, A, C, B, C, A
N groups: 10
N clusters: 3
Matrix class: dgCMatrix
Matrix dimensions: 10 x 3
R Cluster SE Computation Test
==============================
N groups: 50
N clusters: 10
Cluster SEs: 0.2847, 0.2156, 0.2534
✓ R implementation uses YOCO + sparse matrix for cluster SEs
Key Benefits
Feature
Benefit
Within-cluster compression
Reduces data from n to G groups
Sparse cluster matrix
O(G) storage instead of O(G×C)
Vectorized aggregation
No loops over clusters
Lossless
Identical results to full computation
When to Use
YOCO + sparse matrix for clustered SEs is most beneficial when:
Discrete regressors: Binary treatments, categorical controls → high compression
Many clusters: C > 100 clusters benefit most from sparse matrix
Large datasets: n > 100K observations see significant speedups
Technical Details
Algorithm (Section 5.3.1)
Compress with cluster: GROUP BY (regressors + FE + cluster_id)
Compute sufficient statistics: n, sum(y), sum(y²) per group
Solve WLS: On compressed data
Compute ẽ⁰: Sum of residuals per group = sum_y - n × ŷ
**Build sparse W̃_C**: Indicator matrix mapping groups to clusters