{ "cells": [ { "cell_type": "markdown", "id": "2089cc5b-a025-4928-a331-ad33fd1b6a85", "metadata": {}, "source": [ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucascamillomd/pyaging/blob/main/tutorials/tutorial_rnaseq.ipynb) [![Open In nbviewer](https://img.shields.io/badge/View%20in-nbviewer-orange)](https://nbviewer.jupyter.org/github/lucascamillomd/pyaging/blob/main/tutorials/tutorial_rnaseq.ipynb)" ] }, { "cell_type": "markdown", "id": "31cf37ce-09ee-49d7-a411-719bf65e186e", "metadata": {}, "source": [ "# Blood chemistry" ] }, { "cell_type": "markdown", "id": "3ea2b570-56af-4e4f-9606-d4c6d071554c", "metadata": {}, "source": [ "This tutorial is a brief guide for the implementation of PhenoAge. Link to [paper](https://www.aging-us.com/article/101414/text)." ] }, { "cell_type": "markdown", "id": "0a093c7d-dea7-4b34-91bf-08cde6c98011", "metadata": {}, "source": [ "We just need two packages for this tutorial." ] }, { "cell_type": "code", "execution_count": 1, "id": "ad192191-e44f-4994-80ad-ab16cdb7c7e8", "metadata": {}, "outputs": [], "source": [ "import pandas as pd \n", "import pyaging as pya" ] }, { "cell_type": "markdown", "id": "d87488d5-731c-469e-ad6f-79c4c9662371", "metadata": {}, "source": [ "## Download and load example data" ] }, { "cell_type": "markdown", "id": "4c30471f-89e7-4e92-a176-aa3af14a5274", "metadata": {}, "source": [ "Let's download some example human blood data." ] }, { "cell_type": "code", "execution_count": 2, "id": "a0692cf7-e979-4f27-bc14-e1013057c16d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "|-----> 🏗️ Starting download_example_data function\n", "|-----------> Data found in pyaging_data/blood_chemistry_example.pkl\n", "|-----> 🎉 Done! [0.0014s]\n" ] } ], "source": [ "pya.data.download_example_data('blood_chemistry_example')" ] }, { "cell_type": "code", "execution_count": 3, "id": "13aeb69a-4b0e-40f2-8094-194c9a6b42a1", "metadata": {}, "outputs": [], "source": [ "df = pd.read_pickle('pyaging_data/blood_chemistry_example.pkl')" ] }, { "cell_type": "code", "execution_count": 4, "id": "0106112d-21ad-4991-af9f-74b92f46c55b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
albumincreatinineglucoselog_crplymphocyte_percentmean_cell_volumered_cell_distribution_widthalkaline_phosphatasewhite_blood_cell_countage
patient151.887.24.5-0.227.992.413.9123.50.00603770.2
patient253.157.36.1-0.227.880.912.081.50.00413576.5
patient337.4114.75.6-0.223.683.212.4124.40.00738266.4
patient445.988.15.4-0.238.692.511.4113.40.00653746.5
patient540.745.44.7-0.238.388.813.5107.80.00469542.3
\n", "
" ], "text/plain": [ " albumin creatinine glucose log_crp lymphocyte_percent \\\n", "patient1 51.8 87.2 4.5 -0.2 27.9 \n", "patient2 53.1 57.3 6.1 -0.2 27.8 \n", "patient3 37.4 114.7 5.6 -0.2 23.6 \n", "patient4 45.9 88.1 5.4 -0.2 38.6 \n", "patient5 40.7 45.4 4.7 -0.2 38.3 \n", "\n", " mean_cell_volume red_cell_distribution_width alkaline_phosphatase \\\n", "patient1 92.4 13.9 123.5 \n", "patient2 80.9 12.0 81.5 \n", "patient3 83.2 12.4 124.4 \n", "patient4 92.5 11.4 113.4 \n", "patient5 88.8 13.5 107.8 \n", "\n", " white_blood_cell_count age \n", "patient1 0.006037 70.2 \n", "patient2 0.004135 76.5 \n", "patient3 0.007382 66.4 \n", "patient4 0.006537 46.5 \n", "patient5 0.004695 42.3 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "id": "45cbc6e1-9cf7-46a8-ac92-18924a7a5cf8", "metadata": {}, "source": [ "## Convert data to AnnData object" ] }, { "cell_type": "markdown", "id": "ae486006-b533-411b-b449-ff6d2261345a", "metadata": {}, "source": [ "AnnData objects are highly flexible and are thus our preferred method of organizing data for age prediction." ] }, { "cell_type": "code", "execution_count": 5, "id": "acf93ebe-0440-4b1f-9040-05260df459f9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "|-----> 🏗️ Starting df_to_adata function\n", "|-----> ⚙️ Create anndata object started\n", "|-----> ✅ Create anndata object finished [0.0036s]\n", "|-----> ⚙️ Add metadata to anndata started\n", "|-----------? No metadata provided. Leaving adata.obs empty\n", "|-----> ⚠️ Add metadata to anndata finished [0.0005s]\n", "|-----> ⚙️ Log data statistics started\n", "|-----------> There are 30 observations\n", "|-----------> There are 10 features\n", "|-----------> Total missing values: 0\n", "|-----------> Percentage of missing values: 0.00%\n", "|-----> ✅ Log data statistics finished [0.0010s]\n", "|-----> ⚙️ Impute missing values started\n", "|-----------> No missing values found. No imputation necessary\n", "|-----> ✅ Impute missing values finished [0.0008s]\n", "|-----> 🎉 Done! [0.0089s]\n" ] } ], "source": [ "adata = pya.preprocess.df_to_adata(df)" ] }, { "cell_type": "markdown", "id": "54dcb802-6dd7-40cc-ab61-073f70778754", "metadata": {}, "source": [ "Note that the original DataFrame is stored in `X_original` under layers. is This is what the `adata` object looks like:" ] }, { "cell_type": "code", "execution_count": 6, "id": "3cfcf1f4-01d8-4da2-81e9-fee50e051ffe", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AnnData object with n_obs × n_vars = 30 × 10\n", " var: 'percent_na'\n", " layers: 'X_original'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata" ] }, { "cell_type": "markdown", "id": "2277ede6-ab9e-487b-a58d-c01cb21b6b68", "metadata": {}, "source": [ "## Predict age" ] }, { "cell_type": "markdown", "id": "889d2d5f-a596-41d0-b849-560b6bc856a1", "metadata": {}, "source": [ "We can either predict one clock at once or all at the same time. Given we only have one clock of interest for this tutorial, let's go with one. The function is invariant to the capitalization of the clock name. " ] }, { "cell_type": "code", "execution_count": 7, "id": "2dbc7beb-79b8-4e99-b36f-36bcd693c864", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "|-----> 🏗️ Starting predict_age function\n", "|-----> ⚙️ Set PyTorch device started\n", "|-----------> Using device: cpu\n", "|-----> ✅ Set PyTorch device finished [0.0008s]\n", "|-----> 🕒 Processing clock: phenoage\n", "|-----------> ⚙️ Load clock started\n", "|-----------------> Data found in pyaging_data/phenoage.pt\n", "|-----------> ✅ Load clock finished [0.0148s]\n", "|-----------> ⚙️ Check features in adata started\n", "|-----------------> All features are present in adata.var_names.\n", "|-----------> ✅ Check features in adata finished [0.0006s]\n", "|-----------> ⚙️ Predict ages with model started\n", "|-----------------> There is no preprocessing necessary\n", "|-----------------> The postprocessing method is mortality_to_phenoage\n", "|-----------------> in progress: 100.0000%\n", "|-----------> ✅ Predict ages with model finished [0.0345s]\n", "|-----------> ⚙️ Add predicted ages and clock metadata to adata started\n", "|-----------> ✅ Add predicted ages and clock metadata to adata finished [0.0006s]\n", "|-----> 🎉 Done! [0.1068s]\n" ] } ], "source": [ "pya.pred.predict_age(adata, 'PhenoAge')" ] }, { "cell_type": "code", "execution_count": 8, "id": "032382f5-7d98-465e-a3cb-51165eeb7025", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
phenoage
patient170.643137
patient264.834061
patient370.258559
patient442.979385
patient541.677749
\n", "
" ], "text/plain": [ " phenoage\n", "patient1 70.643137\n", "patient2 64.834061\n", "patient3 70.258559\n", "patient4 42.979385\n", "patient5 41.677749" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata.obs.head()" ] }, { "cell_type": "markdown", "id": "2acc80b1-f936-40e4-900a-ef4deb304558", "metadata": {}, "source": [ "Having so much information printed can be overwhelming, particularly when running several clocks at once. In such cases, just set verbose to False." ] }, { "cell_type": "code", "execution_count": 9, "id": "a587f129-a88b-46ec-a249-ac62737a0cb7", "metadata": {}, "outputs": [], "source": [ "pya.data.download_example_data('blood_chemistry_example', verbose=False)\n", "df = pd.read_pickle('pyaging_data/blood_chemistry_example.pkl')\n", "adata = pya.preprocess.df_to_adata(df, verbose=False)\n", "pya.pred.predict_age(adata, ['PhenoAge'], verbose=False)" ] }, { "cell_type": "code", "execution_count": 10, "id": "99fbe406-d076-4979-a2f4-70469755937f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
phenoage
patient170.643137
patient264.834061
patient370.258559
patient442.979385
patient541.677749
\n", "
" ], "text/plain": [ " phenoage\n", "patient1 70.643137\n", "patient2 64.834061\n", "patient3 70.258559\n", "patient4 42.979385\n", "patient5 41.677749" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata.obs.head()" ] }, { "cell_type": "markdown", "id": "72f0eb22-76f2-41b5-b20f-824548215122", "metadata": {}, "source": [ "After age prediction, the clocks are added to `adata.obs`. Moreover, the percent of missing values for each clock and other metadata are included in `adata.uns`." ] }, { "cell_type": "code", "execution_count": 11, "id": "a778028a-7ee6-419c-9be6-e7046a9d8f9a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AnnData object with n_obs × n_vars = 30 × 10\n", " obs: 'phenoage'\n", " var: 'percent_na'\n", " uns: 'phenoage_percent_na', 'phenoage_missing_features', 'phenoage_metadata'\n", " layers: 'X_original'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata" ] }, { "cell_type": "markdown", "id": "1a73e164-a610-4cb6-93f5-6f8ac7d8d56f", "metadata": {}, "source": [ "## Get citation" ] }, { "cell_type": "markdown", "id": "6c7a070c-c448-4ad7-ae0b-21857dafd00e", "metadata": {}, "source": [ "The doi, citation, and some metadata are automatically added to the AnnData object under `adata.uns[CLOCKNAME_metadata]`." ] }, { "cell_type": "code", "execution_count": 12, "id": "9908d25a-9639-4684-9da6-353c7eb4a555", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'clock_name': 'phenoage',\n", " 'data_type': 'blood chemistry',\n", " 'species': 'Homo sapiens',\n", " 'year': 2018,\n", " 'approved_by_author': '⌛',\n", " 'citation': 'Levine, Morgan E., et al. \"An epigenetic biomarker of aging for lifespan and healthspan.\" Aging (albany NY) 10.4 (2018): 573.',\n", " 'doi': 'https://doi.org/10.18632%2Faging.101414',\n", " 'notes': None,\n", " 'research_only': None,\n", " 'version': None}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata.uns['phenoage_metadata']" ] } ], "metadata": { "kernelspec": { "display_name": "research", "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 }