DNAmFitAge#
Index#
Let’s first import some packages:
[1]:
import os
import inspect
import shutil
import json
import torch
import pandas as pd
import numpy as np
import pyaging as pya
Instantiate model class#
[2]:
def print_entire_class(cls):
source = inspect.getsource(cls)
print(source)
print_entire_class(pya.models.DNAmFitAge)
class DNAmFitAge(pyagingModel):
def __init__(self):
super().__init__()
self.GaitF = None
self.GripF = None
self.GaitM = None
self.GripM = None
self.VO2Max = None
self.features_GaitF = None
self.features_GripF = None
self.features_GaitM = None
self.features_GripM = None
self.features_VO2Max = None
def forward(self, x):
Female = x[:, -3] # .unsqueeze(1)
Age = x[:, -2] # .unsqueeze(1)
GrimAge = x[:, -1].unsqueeze(1)
is_female = Female == 1
is_male = Female == 0
x_f = x[is_female]
x_m = x[is_male]
GaitF = self.GaitF(x_f[:, self.features_GaitF])
GripF = self.GripF(x_f[:, self.features_GripF])
VO2MaxF = self.VO2Max(x_f[:, self.features_VO2Max])
GrimAgeF = GrimAge[is_female, :]
GaitM = self.GaitM(x_m[:, self.features_GaitM])
GripM = self.GripM(x_m[:, self.features_GripM])
VO2MaxM = self.VO2Max(x_m[:, self.features_VO2Max])
GrimAgeM = GrimAge[is_male, :]
x_f = torch.concat(
[
(VO2MaxF - 46.825091) / (-0.13620215),
(GripF - 39.857718) / (-0.22074456),
(GaitF - 2.508547) / (-0.01245682),
(GrimAgeF - 7.978487) / (0.80928530),
],
dim=1,
)
x_m = torch.concat(
[
(VO2MaxM - 49.836389) / (-0.141862925),
(GripM - 57.514016) / (-0.253179827),
(GaitM - 2.349080) / (-0.009380061),
(GrimAgeM - 9.549733) / (0.835120557),
],
dim=1,
)
y_f = self.base_model_f(x_f)
y_m = self.base_model_m(x_m)
y = torch.zeros((x.size(0), 1), dtype=x.dtype, device=x.device)
y[is_female] = y_f
y[is_male] = y_m
return y
def preprocess(self, x):
return x
def postprocess(self, x):
return x
[3]:
model = pya.models.DNAmFitAge()
Define clock metadata#
[4]:
model.metadata["clock_name"] = 'dnamfitage'
model.metadata["data_type"] = 'methylation'
model.metadata["species"] = 'Homo sapiens'
model.metadata["year"] = 2023
model.metadata["approved_by_author"] = '⌛'
model.metadata["citation"] = "McGreevy, Kristen M., et al. \"DNAmFitAge: biological age indicator incorporating physical fitness.\" Aging (Albany NY) 15.10 (2023): 3904."
model.metadata["doi"] = 'https://doi.org/10.18632/aging.204538'
model.metadata["research_only"] = None
model.metadata["notes"] = 'Reference values is mean between male and female training medians'
Download clock dependencies#
Download GitHub repository#
[5]:
github_url = "https://github.com/kristenmcgreevy/DNAmFitAge.git"
github_folder_name = github_url.split('/')[-1].split('.')[0]
os.system(f"git clone {github_url}")
[5]:
0
Download from R package#
[6]:
%%writefile download.r
options(repos = c(CRAN = "https://cloud.r-project.org/"))
library(jsonlite)
DNAmFitnessModels <- readRDS("DNAmFitAge/DNAmFitnessModelsandFitAge_Oct2022.rds")
AllCpGs <- DNAmFitnessModels$AllCpGs
write_json(AllCpGs, "AllCpGs.json")
MaleMedians <- DNAmFitnessModels$Male_Medians_All
write.csv(MaleMedians, "MaleMedians.csv")
FemaleMedians <- DNAmFitnessModels$Female_Medians_All
write.csv(FemaleMedians, "FemaleMedians.csv")
Gait_noAge_Females <- DNAmFitnessModels$Gait_noAge_Females
Gait_noAge_Males <- DNAmFitnessModels$Gait_noAge_Males
Grip_noAge_Females <- DNAmFitnessModels$Grip_noAge_Females
Grip_noAge_Males <- DNAmFitnessModels$Grip_noAge_Males
VO2maxModel <- DNAmFitnessModels$VO2maxModel
write.csv(Gait_noAge_Females, "Gait_noAge_Females.csv")
write.csv(Gait_noAge_Males, "Gait_noAge_Males.csv")
write.csv(Grip_noAge_Females, "Grip_noAge_Females.csv")
write.csv(Grip_noAge_Males, "Grip_noAge_Males.csv")
write.csv(VO2maxModel, "VO2maxModel.csv")
Writing download.r
[7]:
os.system("Rscript download.r")
[7]:
0
Load features#
From JSON file#
[8]:
with open('AllCpGs.json', 'r') as f:
features_list = json.load(f)
model.features = features_list + ['female'] + ['age'] + ['grimage']
Load weights into base model#
From CSV file#
[9]:
gaitf_df = pd.read_csv('Gait_noAge_Females.csv', index_col=0)
gaitm_df = pd.read_csv('Gait_noAge_Males.csv', index_col=0)
gripf_df = pd.read_csv('Grip_noAge_Females.csv', index_col=0)
gripm_df = pd.read_csv('Grip_noAge_Males.csv', index_col=0)
vo2max_df = pd.read_csv('VO2maxModel.csv', index_col=0)
Linear model#
[10]:
all_features = features_list + ['Female'] + ['Age'] + ['GrimAge']
model.GaitF = pya.models.LinearModel(input_dim=len(gaitf_df))
model.GaitF.linear.weight.data = torch.tensor(np.array(gaitf_df['estimate'][1:])).unsqueeze(0).float()
model.GaitF.linear.bias.data = torch.tensor(np.array(gaitf_df['estimate'].iloc[0])).float()
model.features_GaitF = torch.tensor([all_features.index(item) for item in np.array(gaitf_df['term'][1:]) if item in all_features]).long()
model.GaitM = pya.models.LinearModel(input_dim=len(gaitm_df))
model.GaitM.linear.weight.data = torch.tensor(np.array(gaitm_df['estimate'][1:])).unsqueeze(0).float()
model.GaitM.linear.bias.data = torch.tensor(np.array(gaitm_df['estimate'].iloc[0])).float()
model.features_GaitM = torch.tensor([all_features.index(item) for item in np.array(gaitm_df['term'][1:]) if item in all_features]).long()
model.GripF = pya.models.LinearModel(input_dim=len(gripf_df))
model.GripF.linear.weight.data = torch.tensor(np.array(gripf_df['estimate'][1:])).unsqueeze(0).float()
model.GripF.linear.bias.data = torch.tensor(np.array(gripf_df['estimate'].iloc[0])).float()
model.features_GripF = torch.tensor([all_features.index(item) for item in np.array(gripf_df['term'][1:]) if item in all_features]).long()
model.GaitM = pya.models.LinearModel(input_dim=len(gaitm_df))
model.GaitM.linear.weight.data = torch.tensor(np.array(gaitm_df['estimate'][1:])).unsqueeze(0).float()
model.GaitM.linear.bias.data = torch.tensor(np.array(gaitm_df['estimate'].iloc[0])).float()
model.features_GaitM = torch.tensor([all_features.index(item) for item in np.array(gaitm_df['term'][1:]) if item in all_features]).long()
model.GripM = pya.models.LinearModel(input_dim=len(gripm_df))
model.GripM.linear.weight.data = torch.tensor(np.array(gripm_df['estimate'][1:])).unsqueeze(0).float()
model.GripM.linear.bias.data = torch.tensor(np.array(gripm_df['estimate'].iloc[0])).float()
model.features_GripM = torch.tensor([all_features.index(item) for item in np.array(gripm_df['term'][1:]) if item in all_features]).long()
model.VO2Max = pya.models.LinearModel(input_dim=len(vo2max_df))
model.VO2Max.linear.weight.data = torch.tensor(np.array(vo2max_df['estimate'][1:])).unsqueeze(0).float()
model.VO2Max.linear.bias.data = torch.tensor(np.array(vo2max_df['estimate'].iloc[0])).float()
model.features_VO2Max = torch.tensor([all_features.index(item) for item in np.array(vo2max_df['term'][1:]) if item in all_features]).long()
Linear model#
[11]:
base_model_m = pya.models.LinearModel(input_dim=4)
base_model_m.linear.weight.data = torch.tensor(np.array([0.1390346, 0.1787371, 0.1593873, 0.5228411])).unsqueeze(0).float()
base_model_m.linear.bias.data = torch.tensor(np.array([0.0])).float()
model.base_model_m = base_model_m
base_model_f = pya.models.LinearModel(input_dim=4)
base_model_f.linear.weight.data = torch.tensor(np.array([0.1044232, 0.1742083, 0.2278776, 0.4934908])).unsqueeze(0).float()
base_model_f.linear.bias.data = torch.tensor(np.array([0.0])).float()
model.base_model_f = base_model_f
Load reference values#
From CSV file#
[12]:
reference_df_f = pd.read_csv('FemaleMedians.csv', index_col=0)
reference_f = reference_df_f.loc[1, model.features[:-3]]
reference_df_m = pd.read_csv('MaleMedians.csv', index_col=0)
reference_m = reference_df_m.loc[1, model.features[:-3]]
reference = (reference_f + reference_m)/2
model.reference_values = list(reference) + [1] + [65] + [65] #65yo F with 65GrimAge
Load preprocess and postprocess objects#
[13]:
model.preprocess_name = None
model.preprocess_dependencies = None
[14]:
model.postprocess_name = None
model.postprocess_dependencies = None
Check all clock parameters#
[15]:
pya.utils.print_model_details(model)
%==================================== Model Details ====================================%
Model Attributes:
training: True
metadata: {'approved_by_author': '⌛',
'citation': 'McGreevy, Kristen M., et al. "DNAmFitAge: biological age '
'indicator incorporating physical fitness." Aging (Albany NY) '
'15.10 (2023): 3904.',
'clock_name': 'dnamfitage',
'data_type': 'methylation',
'doi': 'https://doi.org/10.18632/aging.204538',
'notes': 'Reference values is mean between male and female training medians',
'research_only': None,
'species': 'Homo sapiens',
'version': None,
'year': 2023}
reference_values: [0.521913219528255, 0.28125954210819004, 0.927523008548927, 0.01455467410155745, 0.041014116925727054, 0.12647568639954998, 0.7148617994059816, 0.6786637301838809, 0.909376031310397, 0.1136806555747305, 0.45398237911395245, 0.0544492346267719, 0.7738429377348031, 0.8480746411296824, 0.7667083937960659, 0.0159858833215953, 0.7183128068669931, 0.06813828137044395, 0.939547714031041, 0.8290646522154059, 0.01727972597475225, 0.0697125677059708, 0.366626793673691, 0.588925514102081, 0.027865661596066897, 0.8252930680510391, 0.211681997462417, 0.01269953071843695, 0.7886011964686286, 0.871255311509148]... [Total elements: 630]
preprocess_name: None
preprocess_dependencies: None
postprocess_name: None
postprocess_dependencies: None
features: ['cg25137787', 'cg08911391', 'cg24685778', 'cg25551287', 'cg15322207', 'cg24604749', 'cg03890680', 'cg14601038', 'cg25587481', 'cg23922134', 'cg18561976', 'cg08175029', 'cg23202468', 'cg06181470', 'cg14422932', 'cg15128470', 'cg13587180', 'cg25440680', 'cg16995193', 'cg12864235', 'cg23715435', 'cg02805890', 'cg06381959', 'cg00779476', 'cg25489467', 'cg02376916', 'cg17741339', 'cg20219159', 'cg19629631', 'cg25577212']... [Total elements: 630]
base_model_features: None
base_model: None
features_GaitF: [272, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 281, 514, 515, 516, 517, 518, 301, 519, 305, 520, 521, 522, 523, 524, 525, 526, 314, 318, 527]... [Tensor of shape torch.Size([53])]
features_GripF: [272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301]... [Tensor of shape torch.Size([91])]
features_GaitM: [545, 546, 481, 547, 548, 483, 549, 550, 485, 551, 486, 148, 552, 553, 554, 488, 149, 555, 556, 557, 558, 559, 234, 560, 561, 562, 563, 564, 465, 565]... [Tensor of shape torch.Size([59])]
features_GripM: [361, 362, 363, 209, 364, 365, 366, 367, 211, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 225]... [Tensor of shape torch.Size([93])]
features_VO2Max: [587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616]... [Tensor of shape torch.Size([41])]
%==================================== Model Details ====================================%
Model Structure:
GaitF: LinearModel(
(linear): Linear(in_features=54, out_features=1, bias=True)
)
GaitM: LinearModel(
(linear): Linear(in_features=60, out_features=1, bias=True)
)
GripF: LinearModel(
(linear): Linear(in_features=92, out_features=1, bias=True)
)
GripM: LinearModel(
(linear): Linear(in_features=94, out_features=1, bias=True)
)
VO2Max: LinearModel(
(linear): Linear(in_features=42, out_features=1, bias=True)
)
base_model_m: LinearModel(
(linear): Linear(in_features=4, out_features=1, bias=True)
)
base_model_f: LinearModel(
(linear): Linear(in_features=4, out_features=1, bias=True)
)
%==================================== Model Details ====================================%
Model Parameters and Weights:
GaitF.linear.weight: [-0.05867812782526016, -0.05637867748737335, -0.10371068120002747, 0.01624305173754692, -0.053210534155368805, -0.07633326947689056, -0.01514248363673687, -0.049918416887521744, -0.013779371976852417, 0.14702405035495758, 0.22061608731746674, -0.6326411366462708, -0.40431228280067444, 0.06633924692869186, -0.2228449434041977, -0.03177845478057861, -0.35903501510620117, 0.4153103232383728, -0.837234616279602, 0.056484829634428024, -0.13299566507339478, -0.058516617864370346, 0.04777200520038605, 0.13982263207435608, -0.1280703842639923, -0.03444225341081619, -0.05433110147714615, -0.4258767366409302, 0.0011224570916965604, 0.01846371404826641]... [Tensor of shape torch.Size([1, 53])]
GaitF.linear.bias: tensor(3.9701)
GaitM.linear.weight: [0.10235995799303055, 0.08753516525030136, 0.3124901354312897, -0.28120002150535583, -0.3208324611186981, 0.24479524791240692, 0.05682919919490814, 0.21363066136837006, -0.3853186368942261, -0.038501303642988205, -0.0023554968647658825, -0.17415688931941986, 0.05159717798233032, -0.5185700058937073, -0.04655730724334717, -0.19074112176895142, -0.21096128225326538, 0.011959427036345005, 0.1078566312789917, 0.0770212784409523, 0.18820391595363617, 0.43347951769828796, -0.13240143656730652, 0.021351546049118042, -0.12319610267877579, -0.010150707326829433, -0.007736711762845516, 0.13240836560726166, -1.1829639673233032, -0.10984379798173904]... [Tensor of shape torch.Size([1, 59])]
GaitM.linear.bias: tensor(3.1825)
GripF.linear.weight: [-2.3457672595977783, -2.94146728515625, 2.8132119178771973, -0.9427763223648071, 3.2280826568603516, -0.5796002745628357, -5.075088977813721, -1.3516250848770142, 3.539742946624756, -6.468724727630615, -3.5424692630767822, -6.332897663116455, 4.4002580642700195, 10.170988082885742, -0.5222252011299133, -2.993544101715088, -0.7089398503303528, -3.3968186378479004, 0.9145923852920532, 1.0081183910369873, -2.5558736324310303, -1.6970638036727905, 2.0081098079681396, 0.2233070731163025, -3.5272421836853027, -4.740792274475098, -2.4629898071289062, 0.7111413478851318, -11.599475860595703, 3.976231575012207]... [Tensor of shape torch.Size([1, 91])]
GripF.linear.bias: tensor(53.8206)
GripM.linear.weight: [-0.892844021320343, 1.6379542350769043, 1.5265462398529053, -0.3347032964229584, -1.9029316902160645, -0.2647155225276947, -6.30814266204834, 14.954833984375, 1.178484320640564, 3.5211784839630127, -0.1861504316329956, -1.6255935430526733, 4.550158977508545, -1.587499976158142, -0.449662446975708, -8.599822998046875, 25.895660400390625, 4.368823051452637, 3.992393970489502, 1.3252184391021729, -2.2360410690307617, -0.6896253228187561, 1.5932470560073853, 1.5443568229675293, -0.7052236795425415, -3.0787854194641113, -0.2242996096611023, -0.23673297464847565, 2.1442930698394775, -0.3954241871833801]... [Tensor of shape torch.Size([1, 93])]
GripM.linear.bias: tensor(43.0198)
VO2Max.linear.weight: [5.249129772186279, 3.0901758670806885, -7.551166534423828, -5.796545028686523, -1.094834804534912, -2.3806116580963135, -0.0022889631800353527, 1.0938740968704224, -1.4775551557540894, 1.4427802562713623, 1.268430471420288, 5.4764933586120605, -8.934550285339355, -1.9918478727340698, -5.6620774269104, -6.2174201011657715, -0.6082701086997986, -7.513339996337891, -1.4299590587615967, -3.6723220348358154, 14.669830322265625, 0.5884844660758972, -0.9597266912460327, -1.0253041982650757, -1.802089810371399, -4.9922356605529785, -0.6746888160705566, -10.973499298095703, -0.6614307761192322, 2.365175247192383]... [Tensor of shape torch.Size([1, 41])]
VO2Max.linear.bias: tensor(69.6523)
base_model_m.linear.weight: tensor([[0.1390, 0.1787, 0.1594, 0.5228]])
base_model_m.linear.bias: tensor([0.])
base_model_f.linear.weight: tensor([[0.1044, 0.1742, 0.2279, 0.4935]])
base_model_f.linear.bias: tensor([0.])
%==================================== Model Details ====================================%
Basic test#
[16]:
torch.manual_seed(42)
input = torch.randn(10, len(model.features), dtype=float)
model.eval()
model.to(float)
pred = model(input)
pred
[16]:
tensor([[0.],
[0.],
[0.],
[0.],
[0.],
[0.],
[0.],
[0.],
[0.],
[0.]], dtype=torch.float64, grad_fn=<IndexPutBackward0>)
Save torch model#
[17]:
torch.save(model, f"../weights/{model.metadata['clock_name']}.pt")
Clear directory#
[18]:
# 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: Grip_noAge_Females.csv
Deleted file: Grip_noAge_Males.csv
Deleted file: Gait_noAge_Females.csv
Deleted file: VO2maxModel.csv
Deleted file: AllCpGs.json
Deleted file: Gait_noAge_Males.csv
Deleted folder: DNAmFitAge
Deleted file: download.r
Deleted file: FemaleMedians.csv
Deleted file: MaleMedians.csv