Skip to content

Repository files navigation

Closing the Gap: Epigenetic Age Prediction with ElasticNet and Public Data

Read the Paper (PDF)

Predicted vs Actual Age on held-out EPIC v2 test set (GSE246337, n=500)

Predicted vs. actual age on the held-out EPIC v2 test set (GSE246337, n=500). Left to right: HistGBR (MAE 3.79), ElasticNet (MAE 3.37), DeepStrataAge (MAE 2.45).


Overview

This repository contains the code and results for building an epigenetic age clock from publicly available DNA methylation data. We train an ElasticNet model on 11,328 samples from 17 GEO cohorts and evaluate on an independent Illumina EPIC v2 test set, achieving MAE 3.37 years — closing 53% of the performance gap to DeepStrataAge (De Lima Camillo et al., npj Aging, 2026), a 40.7M-parameter DNN trained on 29,167 proprietary samples.

We show that the remaining gap is attributable to data volume, not model architecture: DeepStrataAge's own ElasticNet baseline achieves MAE 2.02 on their data — only 0.13 years behind the full DNN.

Results

Model Training Data Test MAE MedAE Pearson r
DeepStrataAge (DNN, 40.7M params) 29,167 (proprietary) 2.45 1.79 0.959 0.980
ElasticNet (this work) 11,328 (public) 3.37 2.23 0.937 0.977
HistGBR (this work) 11,328 (public) 3.79 2.77 0.926 0.965

Test set: GSE246337 (500 samples, EPIC v2, age 18–89). Held out during training and hyperparameter tuning. 95% CI for ElasticNet: [3.03, 3.77].

Scaling

Train N Cohorts Test MAE Gap to DSA
3,140 7 4.38 1.93
5,329 9 3.57 1.12
8,722 11 3.52 1.06
11,328 17 3.37 0.91

Method

  • Cross-validation: Leave-One-Cohort-Out (LOCO) across 17 cohorts. Random CV inflated results by ~50%.
  • Tuning: Optuna TPE with fold-level pruning (60 trials, 40% subsampling). Test set excluded by assertion.
  • Features: 12,234 CpGs + sex + platform flag + 5 batch features. Population-mean imputation for cross-platform CpGs.
  • Regularization: Optimal l1_ratio shifted from 0.06 (near-Ridge) at 5K samples to 0.45 (true ElasticNet) at 11K — sparsity helps with heterogeneous cohorts.

Data Quality

Three bugs in public GEO datasets caused initial MAE > 24. Fixing them was the largest single improvement:

Issue Dataset Effect
Detection p-values interleaved with betas GSE196696 Mean beta collapsed to 0.13
G-CSF mobilized transplant donors GSE196696 +22 years epigenetic age shift
Sentrix / GSM ID order mismatch GSE246337 All age labels shuffled

Training Data

All data is publicly available from GEO.

17 training cohorts (click to expand)
GEO ID N Platform Age Description
GSE40279 656 450K 19–101 Hannum et al. (2013)
GSE41169 95 450K 18–65 Dutch population
GSE42861 335 450K 20–70 EIRA RA study (controls)
GSE50660 464 450K 38–67 UK Airwave
GSE51032 845 450K 34–72 EPIC-Italy
GSE51057 329 450K 35–70 Menarcheal timing
GSE55763 2,664 450K 24–75 LOLIPOP UK
GSE56105 614 450K 10–75 BSGS (Australia)
GSE72773 310 450K 35–92 Horvath multi-ethnic
GSE72775 335 450K 36–90 Horvath Hispanic
GSE73103 355 450K 14–34 Swedish young adults
GSE87571 729 450K 14–94 Swedish lifespan
GSE106648 139 450K 20–65 MS study (controls)
GSE125105 699 450K 17–87 MPI Psychiatry
GSE132203 795 EPIC v1 18–76 GTP cohort
GSE196696 570 EPIC v1 19–40 CIBMTR
GSE210255 1,394 EPIC v1 21–87 Multi-ethnic

Test: GSE246337 (500 samples, EPIC v2, age 18–89)

Reproduce

Requirements

python >= 3.11
numpy  pandas  scikit-learn  scipy  optuna  torch  matplotlib

Steps

# 1. Download DeepStrataAge weights
#    https://zenodo.org/records/14768481 → data/zenodo/DeepStratv3/

# 2. Download and parse GEO datasets into data/processed/*.parquet
#    (see training data table for accessions)

# 3. Hyperparameter tuning (optional — tuned params included in tuning/)
python tune_optuna.py --model elasticnet --n-trials 60 --subsample 0.4

# 4. Evaluate
python run_definitive_tuned.py

Repository Structure

├── paper/
│   ├── paper.tex                   # Manuscript source (LaTeX)
│   └── paper.pdf                   # Compiled PDF
├── run_definitive_tuned.py         # Main pipeline (tuned params)
├── run_definitive.py               # Pipeline (default params)
├── tune_optuna.py                  # Hyperparameter search
├── src/                            # Utilities (imputation, evaluation, plots)
├── tuning/                         # Best hyperparameters (JSON)
└── results/                        # Final CSVs and figures

Citation

@misc{elouahabi2026epigenetic,
  author       = {El Ouahabi, Maher},
  title        = {Closing the Gap: Epigenetic Age Prediction with ElasticNet and Public Data},
  year         = {2026},
  howpublished = {\url{https://github.com/maher-coder/epigenetic-clock}},
}

References

  • De Lima Camillo et al. (2026). DeepStrataAge. npj Aging. DOI: 10.1038/s41514-026-00358-w
  • Horvath (2013). DNA methylation age of human tissues and cell types. Genome Biology, 14(10), R115.
  • Hannum et al. (2013). Genome-wide methylation profiles reveal quantitative views of human aging rates. Molecular Cell, 49(2), 359–367.

License

MIT

About

Epigenetic age prediction with ElasticNet on public GEO data. MAE 3.37 years — closing 53% of the gap to DeepStrataAge (DNN, 29K proprietary samples).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages