DunedinPoAm38#

Index#

  1. Instantiate model class

  2. Define clock metadata

  3. Download clock dependencies

  4. Load features

  5. Load weights into base model

  6. Load reference values

  7. Load preprocess and postprocess objects

  8. Check all clock parameters

  9. Basic test

  10. Save torch model

  11. Clear directory

Let’s first import some packages:

[1]:
import os
import inspect
import shutil
import json
import torch
import pandas as pd
import pyaging as pya

Instantiate model class#

[2]:
def print_entire_class(cls):
    source = inspect.getsource(cls)
    print(source)

print_entire_class(pya.models.DunedinPoAm38)
class DunedinPoAm38(LinearReferenceClock):
    pass

[3]:
model = pya.models.DunedinPoAm38()

Define clock metadata#

[4]:
model.metadata["clock_name"] = 'dunedinpoam38'
model.metadata["data_type"] = 'methylation'
model.metadata["species"] = 'Homo sapiens'
model.metadata["year"] = 2020
model.metadata["approved_by_author"] = '⌛'
model.metadata["citation"] = "Belsky, Daniel W., et al. \"Quantification of the pace of biological aging in humans through a blood test, the DunedinPoAm DNA methylation algorithm.\" eLife 9 (2020): e54870."
model.metadata["doi"] = "https://doi.org/10.7554/eLife.54870"
model.metadata["research_only"] = None
model.metadata["notes"] = "Whole-blood elastic-net estimator (46 CpGs) of the pace of biological aging, trained on a longitudinal Pace-of-Aging score computed from 18 organ-system biomarkers tracked to age 38 in the Dunedin cohort, quantifying how fast aging is proceeding rather than age attained."
model.metadata["tissue"] = 'whole blood'
model.metadata["predicts"] = 'pace of aging (rate of biological aging)'
model.metadata["unit"] = 'years'
model.metadata["model_type"] = 'Elastic net'
model.metadata["platform"] = 'Illumina 450K/EPIC'
model.metadata["population"] = 'adults (developed at age 38; validated ages 18-95)'
model.metadata["journal"] = 'eLife'
model.metadata["last_author"] = 'Terrie E. Moffitt'
model.metadata["n_features"] = 46
model.metadata["citations"] = 666
model.metadata["citations_date"] = '2026-07-05'

Download clock dependencies#

[5]:
os.system(f"curl -sL -o coefficients.csv https://raw.githubusercontent.com/bio-learn/biolearn/180852e2bab473303cb85da627178b1695ee9d86/biolearn/data/DunedinPoAm38.csv")
[5]:
0

Load features#

[6]:
df = pd.read_csv('coefficients.csv')
mask = df['CpGmarker'].astype(str).str.lower().isin(['intercept', '(intercept)'])
intercept_value = float(df.loc[mask, 'CoefficientTraining'].iloc[0]) if mask.any() else 0.0
coef_df = df.loc[~mask].reset_index(drop=True)
model.features = coef_df['CpGmarker'].tolist()

Load weights into base model#

[7]:
weights = torch.tensor(coef_df['CoefficientTraining'].tolist()).unsqueeze(0).float()
intercept = torch.tensor([intercept_value]).float()
[8]:
base_model = pya.models.LinearModel(input_dim=len(model.features))

base_model.linear.weight.data = weights.float()
base_model.linear.bias.data = intercept.float()

model.base_model = base_model

Load reference values#

[9]:
model.reference_values = None

Load preprocess and postprocess objects#

[10]:
model.preprocess_name = None
model.preprocess_dependencies = None
[11]:
model.postprocess_name = None
model.postprocess_dependencies = None

Check all clock parameters#

[12]:
pya.utils.print_model_details(model)

%==================================== Model Details ====================================%
Model Attributes:

training: True
metadata: {'approved_by_author': '⌛',
 'citation': 'Belsky, Daniel W., et al. "Quantification of the pace of '
             'biological aging in humans through a blood test, the DunedinPoAm '
             'DNA methylation algorithm." eLife 9 (2020): e54870.',
 'clock_name': 'dunedinpoam38',
 'data_type': 'methylation',
 'doi': 'https://doi.org/10.7554/eLife.54870',
 'notes': None,
 'research_only': None,
 'species': 'Homo sapiens',
 'version': None,
 'year': 2020}
reference_values: None
preprocess_name: None
preprocess_dependencies: None
postprocess_name: None
postprocess_dependencies: None
features: ['cg02582848', 'cg03730474', 'cg03922834', 'cg04480708', 'cg05227215', 'cg05513157', 'cg05575921', 'cg06133392', 'cg07045089', 'cg07185119', 'cg07986378', 'cg08376310', 'cg09349128', 'cg09404119', 'cg10727171', 'cg10919522', 'cg11574055', 'cg11674508', 'cg11897887', 'cg13074055', 'cg13121699', 'cg14485633', 'cg14775114', 'cg15018359', 'cg19422687', 'cg19510038', 'cg19743820', 'cg20451986', 'cg21079030', 'cg21370522']... [Total elements: 46]
base_model_features: None

%==================================== Model Details ====================================%
Model Structure:

base_model: LinearModel(
  (linear): Linear(in_features=46, out_features=1, bias=True)
)

%==================================== Model Details ====================================%
Model Parameters and Weights:

base_model.linear.weight: [0.16865555942058563, -0.030930202454328537, 0.10762208700180054, 0.32811808586120605, 0.20570090413093567, -0.19139723479747772, -0.2568254768848419, -0.013769027777016163, 0.002585785463452339, 0.007155308965593576, -0.3933064937591553, 0.0372597873210907, -0.6891953945159912, 0.010446280241012573, -0.014004146680235863, -0.32410237193107605, 0.06089318171143532, 0.07774978131055832, 0.0017560641281306744, -0.0569249764084816, -0.05277020111680031, 0.030463986098766327, -0.1716403365135193, -0.19539450109004974, 0.2227468192577362, -0.16681736707687378, -0.10328859090805054, 0.01552193146198988, 0.008607408963143826, 0.1834435760974884]... [Tensor of shape torch.Size([1, 46])]
base_model.linear.bias: tensor([-0.0693])

%==================================== Model Details ====================================%

Basic test#

[13]:
torch.manual_seed(42)
input = torch.randn(10, len(model.features), dtype=float)
model.eval()
model.to(float)
pred = model(input)
pred
[13]:
tensor([[ 2.5557],
        [ 1.7208],
        [ 1.9728],
        [ 0.4137],
        [-1.7117],
        [-1.8462],
        [-2.8839],
        [-2.1433],
        [-0.0711],
        [-1.1731]], dtype=torch.float64, grad_fn=<AddmmBackward0>)

Save torch model#

[14]:
torch.save(model, f"../weights/{model.metadata['clock_name']}.pt")

Clear directory#

[15]:
# Function to remove a folder and all its contents
def remove_folder(path):
    try:
        shutil.rmtree(path)
        print(f"Deleted folder: {path}")
    except Exception as e:
        print(f"Error deleting folder {path}: {e}")

# Get a list of all files and folders in the current directory
all_items = os.listdir('.')

# Loop through the items
for item in all_items:
    # Check if it's a file and does not end with .ipynb
    if os.path.isfile(item) and not item.endswith('.ipynb'):
        os.remove(item)
        print(f"Deleted file: {item}")
    # Check if it's a folder
    elif os.path.isdir(item):
        remove_folder(item)
Deleted file: coefficients.csv