{ "cells": [ { "cell_type": "markdown", "id": "2f04eee0-5928-4e74-a754-6dc2e528810c", "metadata": {}, "source": [ "# CamilloH3K9me3" ] }, { "cell_type": "markdown", "id": "a3f514a3-772c-4a14-afdf-5a8376851ff4", "metadata": {}, "source": [ "## Index\n", "1. [Instantiate model class](#Instantiate-model-class)\n", "2. [Define clock metadata](#Define-clock-metadata)\n", "3. [Download clock dependencies](#Download-clock-dependencies)\n", "5. [Load features](#Load-features)\n", "6. [Load weights into base model](#Load-weights-into-base-model)\n", "7. [Load reference values](#Load-reference-values)\n", "8. [Load preprocess and postprocess objects](#Load-preprocess-and-postprocess-objects)\n", "10. [Check all clock parameters](#Check-all-clock-parameters)\n", "10. [Basic test](#Basic-test)\n", "11. [Save torch model](#Save-torch-model)\n", "12. [Clear directory](#Clear-directory)" ] }, { "cell_type": "markdown", "id": "d95fafdc-643a-40ea-a689-200bd132e90c", "metadata": {}, "source": [ "Let's first import some packages:" ] }, { "cell_type": "code", "execution_count": 1, "id": "4adfb4de-cd79-4913-a1af-9e23e9e236c9", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:49:44.264415Z", "iopub.status.busy": "2025-04-07T17:49:44.264050Z", "iopub.status.idle": "2025-04-07T17:49:45.745157Z", "shell.execute_reply": "2025-04-07T17:49:45.744845Z" } }, "outputs": [], "source": [ "import os\n", "import inspect\n", "import shutil\n", "import json\n", "import torch\n", "import pandas as pd\n", "import pyaging as pya\n", "import joblib\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "145082e5-ced4-47ae-88c0-cb69773e3c5a", "metadata": {}, "source": [ "## Instantiate model class" ] }, { "cell_type": "code", "execution_count": 2, "id": "8aa77372-7ed3-4da7-abc9-d30372106139", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:49:45.746859Z", "iopub.status.busy": "2025-04-07T17:49:45.746625Z", "iopub.status.idle": "2025-04-07T17:49:45.753421Z", "shell.execute_reply": "2025-04-07T17:49:45.753157Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "class CamilloH3K9me3(pyagingModel):\n", " def __init__(self):\n", " super().__init__()\n", "\n", " def preprocess(self, x):\n", " return x\n", "\n", " def postprocess(self, x):\n", " return x\n", "\n" ] } ], "source": [ "def print_entire_class(cls):\n", " source = inspect.getsource(cls)\n", " print(source)\n", "\n", "print_entire_class(pya.models.CamilloH3K9me3)" ] }, { "cell_type": "code", "execution_count": 3, "id": "78536494-f1d9-44de-8583-c89a310d2307", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:49:45.754670Z", "iopub.status.busy": "2025-04-07T17:49:45.754583Z", "iopub.status.idle": "2025-04-07T17:49:45.756154Z", "shell.execute_reply": "2025-04-07T17:49:45.755889Z" } }, "outputs": [], "source": [ "model = pya.models.CamilloH3K9me3()" ] }, { "cell_type": "markdown", "id": "51f8615e-01fa-4aa5-b196-3ee2b35d261c", "metadata": {}, "source": [ "## Define clock metadata" ] }, { "cell_type": "code", "execution_count": 4, "id": "6601da9e-8adc-44ee-9308-75e3cd31b816", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:49:45.757459Z", "iopub.status.busy": "2025-04-07T17:49:45.757375Z", "iopub.status.idle": "2025-04-07T17:49:45.759362Z", "shell.execute_reply": "2025-04-07T17:49:45.759132Z" } }, "outputs": [], "source": [ "model.metadata[\"clock_name\"] = \"camilloh3k9me3\"\n", "model.metadata[\"data_type\"] = \"histone modification\" # Paper: The study builds age predictors from seven histone modifications measured by ChIP-seq.\n", "model.metadata[\"species\"] = \"Homo sapiens\" # Paper: The analyzed ENCODE ChIP-seq data are from human tissues and cells.\n", "model.metadata[\"year\"] = 2025\n", "model.metadata[\"approved_by_author\"] = \"✅\"\n", "model.metadata[\"citation\"] = \"de Lima Camillo, L. P., Asif, M. H., Horvath, S., Larschan, E., & Singh, R. Histone mark age of human tissues and cell types. Science Advances 11, eadk9373 (2025).\"\n", "model.metadata[\"doi\"] = \"https://doi.org/10.1126/sciadv.adk9373\"\n", "model.metadata[\"notes\"] = \"Pan-tissue chronological-age predictor trained on gene-level H3K9me3 ChIP-seq enrichment; ElasticNet feature selection is followed by truncated-SVD PCA and automatic relevance determination regression.\"\n", "model.metadata[\"research_only\"] = None\n", "model.metadata[\"tissue\"] = [\"multi-tissue\"] # Paper: The ENCODE collection contains 248 H3K9me3 ChIP-seq samples among 82 tissues and cell types.\n", "model.metadata[\"predicts\"] = [\"chronological age\"] # Paper: The H3K9me3 model is described as an age predictor.\n", "model.metadata[\"training_target\"] = [\"chronological age\"] # Paper: The training response is the ENCODE biosample age.\n", "model.metadata[\"unit\"] = [\"years\"] # Paper: The author tutorial reports predicted histone-mark age in years.\n", "model.metadata[\"model_type\"] = \"PCA + elastic net + ARD regression\" # Paper: ElasticNet selects nonzero features, PCA uses truncated SVD, and ARD regression makes the final prediction.\n", "model.metadata[\"platform\"] = [\"ChIP-seq\"] # Paper: The input consists of ENCODE histone-modification ChIP-seq enrichment tracks.\n", "model.metadata[\"population\"] = \"all ages\" # Paper: Samples span embryonic through 90-plus years and are roughly sex-balanced; cancer samples were removed for predictor evaluation.\n", "model.metadata[\"journal\"] = \"Science Advances\"\n", "model.metadata[\"last_author\"] = \"Ritambhara Singh\"\n", "model.metadata[\"n_features\"] = 341\n", "model.metadata[\"citations\"] = 4\n", "model.metadata[\"citations_date\"] = \"2026-07-05\"\n" ] }, { "cell_type": "markdown", "id": "74492239-5aae-4026-9d90-6bc9c574c110", "metadata": {}, "source": [ "## Download clock dependencies" ] }, { "cell_type": "markdown", "id": "7bec474f-80ce-4884-9472-30c193327117", "metadata": {}, "source": [ "#### Download GitHub repository" ] }, { "cell_type": "code", "execution_count": 5, "id": "df09b874-28a1-4140-9b1b-9e16ef23668c", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:49:45.760638Z", "iopub.status.busy": "2025-04-07T17:49:45.760558Z", "iopub.status.idle": "2025-04-07T17:50:01.508198Z", "shell.execute_reply": "2025-04-07T17:50:01.507774Z" } }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "github_url = \"https://github.com/rsinghlab/HistoneClocks.git\"\n", "github_folder_name = github_url.split('/')[-1].split('.')[0]\n", "os.system(f\"git clone {github_url}\")" ] }, { "cell_type": "markdown", "id": "5035b180-3d1b-4432-8ebe-b9c92bd93a7f", "metadata": {}, "source": [ "## Load features" ] }, { "cell_type": "markdown", "id": "15f4af76-b93c-438c-b57f-f129d6e9ec99", "metadata": {}, "source": [ "#### From CSV file" ] }, { "cell_type": "code", "execution_count": 6, "id": "8a3d5de6-6303-487a-8b4d-e6345792f7be", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.510590Z", "iopub.status.busy": "2025-04-07T17:50:01.510469Z", "iopub.status.idle": "2025-04-07T17:50:01.687171Z", "shell.execute_reply": "2025-04-07T17:50:01.686889Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/lucascamillo/mambaforge/envs/research/lib/python3.9/site-packages/sklearn/base.py:380: InconsistentVersionWarning: Trying to unpickle estimator ElasticNet from version 1.0.1 when using version 1.6.0. This might lead to breaking code or invalid results. Use at your own risk. For more info please refer to:\n", "https://scikit-learn.org/stable/model_persistence.html#security-maintainability-limitations\n", " warnings.warn(\n", "/Users/lucascamillo/mambaforge/envs/research/lib/python3.9/site-packages/sklearn/base.py:380: InconsistentVersionWarning: Trying to unpickle estimator TruncatedSVD from version 1.0.1 when using version 1.6.0. This might lead to breaking code or invalid results. Use at your own risk. For more info please refer to:\n", "https://scikit-learn.org/stable/model_persistence.html#security-maintainability-limitations\n", " warnings.warn(\n", "/Users/lucascamillo/mambaforge/envs/research/lib/python3.9/site-packages/sklearn/base.py:380: InconsistentVersionWarning: Trying to unpickle estimator ARDRegression from version 1.0.1 when using version 1.6.0. This might lead to breaking code or invalid results. Use at your own risk. For more info please refer to:\n", "https://scikit-learn.org/stable/model_persistence.html#security-maintainability-limitations\n", " warnings.warn(\n" ] } ], "source": [ "histone = 'H3K' + model.metadata[\"clock_name\"].split('k')[1]\n", "\n", "feature_selector_path = 'HistoneClocks/results/models/' + histone + '_feature_selector.pkl'\n", "feature_selector = joblib.load(feature_selector_path)\n", "\n", "dim_reduction_path = 'HistoneClocks/results/models/' + histone + '_dim_reduction.pkl'\n", "dim_reduction = joblib.load(dim_reduction_path)\n", "\n", "ard_model_path = 'HistoneClocks/results/models/' + histone + '_model.pkl'\n", "ard_model = joblib.load(ard_model_path)\n", "\n", "genes = pd.read_csv('HistoneClocks/metadata/Ensembl-105-EnsDb-for-Homo-sapiens-genes.csv')\n", "chromosomes = ['1', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '21', '22', '3', '4', '5', '6', '7', '8', '9', 'X']\n", "genes = genes[genes['chr'].apply(lambda x: x in chromosomes)]\n", "genes.index = genes.gene_id\n", "model.features = genes.gene_id[np.abs(feature_selector.coef_) > 0].tolist()" ] }, { "cell_type": "markdown", "id": "ee6d8fa0-4767-4c45-9717-eb1c95e2ddc0", "metadata": {}, "source": [ "## Load weights into base model" ] }, { "cell_type": "code", "execution_count": 7, "id": "e09b3463-4fd4-41b1-ac21-e63ddd223fe0", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.688738Z", "iopub.status.busy": "2025-04-07T17:50:01.688635Z", "iopub.status.idle": "2025-04-07T17:50:01.691670Z", "shell.execute_reply": "2025-04-07T17:50:01.691359Z" } }, "outputs": [], "source": [ "weights = torch.tensor(ard_model.coef_).unsqueeze(0).float()\n", "intercept = torch.tensor([ard_model.intercept_]).float()\n", "rotation = torch.tensor(dim_reduction.components_.T).float()\n", "center = torch.tensor(0)" ] }, { "cell_type": "markdown", "id": "a5fb949f-500a-49d0-a792-2a774b0de18f", "metadata": {}, "source": [ "#### PC linear model" ] }, { "cell_type": "code", "execution_count": 8, "id": "b6e1baed-fb83-4b97-a2e7-c2f17254ca47", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.693021Z", "iopub.status.busy": "2025-04-07T17:50:01.692933Z", "iopub.status.idle": "2025-04-07T17:50:01.695463Z", "shell.execute_reply": "2025-04-07T17:50:01.695186Z" } }, "outputs": [], "source": [ "base_model = pya.models.PCLinearModel(input_dim=len(model.features), pc_dim=rotation.shape[1])\n", "\n", "base_model.center.data = center.float()\n", "base_model.rotation.data = rotation.float()\n", "base_model.linear.weight.data = weights.float()\n", "base_model.linear.bias.data = intercept.float()\n", "\n", "model.base_model = base_model" ] }, { "cell_type": "markdown", "id": "ad8b4c1d-9d57-48b7-9a30-bcfea7b747b1", "metadata": {}, "source": [ "## Load reference values" ] }, { "cell_type": "code", "execution_count": 9, "id": "ade0f4c9-2298-4fc3-bb72-d200907dd731", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.696802Z", "iopub.status.busy": "2025-04-07T17:50:01.696714Z", "iopub.status.idle": "2025-04-07T17:50:01.698359Z", "shell.execute_reply": "2025-04-07T17:50:01.698104Z" } }, "outputs": [], "source": [ "model.reference_values = None" ] }, { "cell_type": "markdown", "id": "af3bcf7b-74a8-4d21-9ccb-4de0c2b0516b", "metadata": {}, "source": [ "## Load preprocess and postprocess objects" ] }, { "cell_type": "code", "execution_count": 10, "id": "7a22fb20-c605-424d-8efb-7620c2c0755c", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.699697Z", "iopub.status.busy": "2025-04-07T17:50:01.699614Z", "iopub.status.idle": "2025-04-07T17:50:01.701029Z", "shell.execute_reply": "2025-04-07T17:50:01.700748Z" } }, "outputs": [], "source": [ "model.preprocess_name = None\n", "model.preprocess_dependencies = None" ] }, { "cell_type": "code", "execution_count": 11, "id": "ff4a21cb-cf41-44dc-9ed1-95cf8aa15772", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.702279Z", "iopub.status.busy": "2025-04-07T17:50:01.702189Z", "iopub.status.idle": "2025-04-07T17:50:01.703741Z", "shell.execute_reply": "2025-04-07T17:50:01.703477Z" } }, "outputs": [], "source": [ "model.postprocess_name = None\n", "model.postprocess_dependencies = None" ] }, { "cell_type": "markdown", "id": "86e3d6b1-e67e-4f3d-bd39-0ebec5726c3c", "metadata": {}, "source": [ "## Check all clock parameters" ] }, { "cell_type": "code", "execution_count": 12, "id": "2168355c-47d9-475d-b816-49f65e74887c", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.705097Z", "iopub.status.busy": "2025-04-07T17:50:01.705001Z", "iopub.status.idle": "2025-04-07T17:50:01.710408Z", "shell.execute_reply": "2025-04-07T17:50:01.710131Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "%==================================== Model Details ====================================%\n", "Model Attributes:\n", "\n", "training: True\n", "metadata: {'approved_by_author': '✅',\n", " 'citation': 'de Lima Camillo, Lucas Paulo, et al. \"Histone mark age of human '\n", " 'tissues and cells.\" Science Advances 11.1 (2025): eadk9373.',\n", " 'clock_name': 'camilloh3k9me3',\n", " 'data_type': 'histone mark',\n", " 'doi': 'https://doi.org/10.1126/sciadv.adk9373',\n", " 'notes': None,\n", " 'research_only': None,\n", " 'species': 'Homo sapiens',\n", " 'version': None,\n", " 'year': 2023}\n", "reference_values: None\n", "preprocess_name: None\n", "preprocess_dependencies: None\n", "postprocess_name: None\n", "postprocess_dependencies: None\n", "features: ['ENSG00000285833', 'ENSG00000200796', 'ENSG00000229687', 'ENSG00000238653', 'ENSG00000173810', 'ENSG00000270976', 'ENSG00000273727', 'ENSG00000206980', 'ENSG00000212292', 'ENSG00000222457', 'ENSG00000249197', 'ENSG00000200327', 'ENSG00000252552', 'ENSG00000226565', 'ENSG00000221673', 'ENSG00000283881', 'ENSG00000283699', 'ENSG00000199222', 'ENSG00000272319', 'ENSG00000272387', 'ENSG00000224162', 'ENSG00000221594', 'ENSG00000232142', 'ENSG00000272627', 'ENSG00000201954', 'ENSG00000200728', 'ENSG00000266676', 'ENSG00000241008', 'ENSG00000240298', 'ENSG00000201591']... [Total elements: 341]\n", "base_model_features: None\n", "\n", "%==================================== Model Details ====================================%\n", "Model Structure:\n", "\n", "base_model: PCLinearModel(\n", " (linear): Linear(in_features=247, out_features=1, bias=True)\n", ")\n", "\n", "%==================================== Model Details ====================================%\n", "Model Parameters and Weights:\n", "\n", "base_model.center: tensor(0.)\n", "base_model.rotation: [0.05324198305606842, 0.0940878763794899, 0.06535070389509201, -0.09214675426483154, -0.08845143765211105, 0.14370842278003693, 0.05924377962946892, 0.04560413956642151, -0.01798827014863491, 0.019018931314349174, 0.06142134964466095, 0.07810656726360321, -0.04977318271994591, -0.033549174666404724, -0.00220973277464509, -0.0019830341916531324, -0.03713170811533928, 0.08470380306243896, 0.013711818493902683, -0.03922244533896446, 0.01654326543211937, -0.03835022822022438, -0.02710358425974846, 0.06989412754774094, 0.018537024036049843, 0.047473885118961334, -0.017129063606262207, 0.020791441202163696, -0.012957916595041752, 0.0911138579249382]... [Tensor of shape torch.Size([341, 247])]\n", "base_model.linear.weight: [-0.5548347234725952, -3.9517745971679688, 0.5627398490905762, -5.180229663848877, 1.0164791345596313, -5.611454486846924, -6.15842866897583, -0.1160941943526268, -4.563173294067383, 2.9563746452331543, 4.438188552856445, -4.377952575683594, 2.5765492916107178, -2.7293200492858887, 2.149219512939453, -0.5059330463409424, 1.8233673572540283, 1.0248630046844482, -4.9408392906188965, -0.7393870949745178, -1.5198975801467896, -2.560576915740967, 0.9188230633735657, -0.838702380657196, 1.3052270412445068, -2.490286111831665, 0.16001547873020172, -0.7358596920967102, -0.39013969898223877, 0.28255495429039]... [Tensor of shape torch.Size([1, 247])]\n", "base_model.linear.bias: tensor([52.7988])\n", "\n", "%==================================== Model Details ====================================%\n", "\n" ] } ], "source": [ "pya.utils.print_model_details(model)" ] }, { "cell_type": "markdown", "id": "986d0262-e0c7-4036-b687-dee53ba392fb", "metadata": {}, "source": [ "## Basic test" ] }, { "cell_type": "code", "execution_count": 13, "id": "936b9877-d076-4ced-99aa-e8d4c58c5caf", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.711817Z", "iopub.status.busy": "2025-04-07T17:50:01.711713Z", "iopub.status.idle": "2025-04-07T17:50:01.716725Z", "shell.execute_reply": "2025-04-07T17:50:01.716468Z" } }, "outputs": [ { "data": { "text/plain": [ "tensor([[ 99.1685],\n", " [ 41.4859],\n", " [ 7.6682],\n", " [ 71.2971],\n", " [ 75.7144],\n", " [ 57.6654],\n", " [102.5710],\n", " [ 65.1856],\n", " [ 40.4876],\n", " [ 37.4566]], dtype=torch.float64, grad_fn=)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "torch.manual_seed(42)\n", "input = torch.randn(10, len(model.features), dtype=float)\n", "model.eval()\n", "model.to(float)\n", "pred = model(input)\n", "pred" ] }, { "cell_type": "markdown", "id": "fe8299d7-9285-4e22-82fd-b664434b4369", "metadata": {}, "source": [ "## Save torch model" ] }, { "cell_type": "code", "execution_count": 14, "id": "5ef2fa8d-c80b-4fdd-8555-79c0d541788e", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.718160Z", "iopub.status.busy": "2025-04-07T17:50:01.718067Z", "iopub.status.idle": "2025-04-07T17:50:01.721108Z", "shell.execute_reply": "2025-04-07T17:50:01.720824Z" } }, "outputs": [], "source": [ "torch.save(model, f\"../weights/{model.metadata['clock_name']}.pt\")" ] }, { "cell_type": "markdown", "id": "bac6257b-8d08-4a90-8d0b-7f745dc11ac1", "metadata": {}, "source": [ "## Clear directory\n", "" ] }, { "cell_type": "code", "execution_count": 15, "id": "11aeaa70-44c0-42f9-86d7-740e3849a7a6", "metadata": { "execution": { "iopub.execute_input": "2025-04-07T17:50:01.722544Z", "iopub.status.busy": "2025-04-07T17:50:01.722457Z", "iopub.status.idle": "2025-04-07T17:50:01.739782Z", "shell.execute_reply": "2025-04-07T17:50:01.739458Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Deleted folder: HistoneClocks\n" ] } ], "source": [ "# Function to remove a folder and all its contents\n", "def remove_folder(path):\n", " try:\n", " shutil.rmtree(path)\n", " print(f\"Deleted folder: {path}\")\n", " except Exception as e:\n", " print(f\"Error deleting folder {path}: {e}\")\n", "\n", "# Get a list of all files and folders in the current directory\n", "all_items = os.listdir('.')\n", "\n", "# Loop through the items\n", "for item in all_items:\n", " # Check if it's a file and does not end with .ipynb\n", " if os.path.isfile(item) and not item.endswith('.ipynb'):\n", " os.remove(item)\n", " print(f\"Deleted file: {item}\")\n", " # Check if it's a folder\n", " elif os.path.isdir(item):\n", " remove_folder(item)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" } }, "nbformat": 4, "nbformat_minor": 5 }