{ "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": [ "# Bulk RNA-Seq" ] }, { "cell_type": "markdown", "id": "3ea2b570-56af-4e4f-9606-d4c6d071554c", "metadata": {}, "source": [ "This tutorial is a brief guide for the implementation of BiT Age, a highly accurate bulk transcriptomic clock for C. elegans. Link to [paper](https://onlinelibrary.wiley.com/doi/full/10.1111/acel.13320)." ] }, { "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 the C. elegans RNA-seq dataset from the BiT Age paper." ] }, { "cell_type": "code", "execution_count": 2, "id": "55bbd03e-3953-427e-ab7a-4d523e6bc985", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "|-----> ๐Ÿ—๏ธ Starting download_example_data function\n", "|-----------> Data found in pyaging_data/GSE65765_CPM.pkl\n", "|-----> ๐ŸŽ‰ Done! [0.5749s]\n" ] } ], "source": [ "pya.data.download_example_data('GSE65765')" ] }, { "cell_type": "code", "execution_count": 3, "id": "13aeb69a-4b0e-40f2-8094-194c9a6b42a1", "metadata": {}, "outputs": [], "source": [ "df = pd.read_pickle('pyaging_data/GSE65765_CPM.pkl')" ] }, { "cell_type": "code", "execution_count": 4, "id": "7af12fc3-1418-49df-ba7f-e94730db706e", "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", " \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", "
WBGene00197333WBGene00198386WBGene00015153WBGene00002061WBGene00255704WBGene00235314WBGene00001177WBGene00169236WBGene00219784WBGene00015152...WBGene00010964WBGene00014467WBGene00014468WBGene00014469WBGene00014470WBGene00010965WBGene00014471WBGene00010966WBGene00010967WBGene00014473
SRR17939930.00.03.780174169.2408151.9074270.27744459.3209860.00.0000001.283178...858.9491560.00.0000000.00.052021234.5268460.01734054.48305778.1178150.000000
SRR17939910.00.00.510354412.6285970.0618610.06186122.2390440.00.0154650.201048...1049.9828850.00.0154650.00.015465372.5117130.00000054.54597159.6185770.000000
SRR17939940.00.04.718708274.7336711.2346440.11839142.4007210.00.0000000.642691...664.2554120.00.1014780.00.000000253.2204210.03382619.48369886.4927350.016913
SRR17939920.00.02.389905351.6125580.5058920.06977820.4973580.00.0174451.308342...1298.7998490.00.0348890.00.000000472.2068030.00000089.50803976.4595080.000000
\n", "

4 rows ร— 46755 columns

\n", "
" ], "text/plain": [ " WBGene00197333 WBGene00198386 WBGene00015153 WBGene00002061 \\\n", "SRR1793993 0.0 0.0 3.780174 169.240815 \n", "SRR1793991 0.0 0.0 0.510354 412.628597 \n", "SRR1793994 0.0 0.0 4.718708 274.733671 \n", "SRR1793992 0.0 0.0 2.389905 351.612558 \n", "\n", " WBGene00255704 WBGene00235314 WBGene00001177 WBGene00169236 \\\n", "SRR1793993 1.907427 0.277444 59.320986 0.0 \n", "SRR1793991 0.061861 0.061861 22.239044 0.0 \n", "SRR1793994 1.234644 0.118391 42.400721 0.0 \n", "SRR1793992 0.505892 0.069778 20.497358 0.0 \n", "\n", " WBGene00219784 WBGene00015152 ... WBGene00010964 \\\n", "SRR1793993 0.000000 1.283178 ... 858.949156 \n", "SRR1793991 0.015465 0.201048 ... 1049.982885 \n", "SRR1793994 0.000000 0.642691 ... 664.255412 \n", "SRR1793992 0.017445 1.308342 ... 1298.799849 \n", "\n", " WBGene00014467 WBGene00014468 WBGene00014469 WBGene00014470 \\\n", "SRR1793993 0.0 0.000000 0.0 0.052021 \n", "SRR1793991 0.0 0.015465 0.0 0.015465 \n", "SRR1793994 0.0 0.101478 0.0 0.000000 \n", "SRR1793992 0.0 0.034889 0.0 0.000000 \n", "\n", " WBGene00010965 WBGene00014471 WBGene00010966 WBGene00010967 \\\n", "SRR1793993 234.526846 0.017340 54.483057 78.117815 \n", "SRR1793991 372.511713 0.000000 54.545971 59.618577 \n", "SRR1793994 253.220421 0.033826 19.483698 86.492735 \n", "SRR1793992 472.206803 0.000000 89.508039 76.459508 \n", "\n", " WBGene00014473 \n", "SRR1793993 0.000000 \n", "SRR1793991 0.000000 \n", "SRR1793994 0.016913 \n", "SRR1793992 0.000000 \n", "\n", "[4 rows x 46755 columns]" ] }, "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": "74a99c21-67a7-4adb-8ac9-ea404a6c1e02", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "|-----> ๐Ÿ—๏ธ Starting df_to_adata function\n", "|-----> โš™๏ธ Create anndata object started\n", "|-----> โœ… Create anndata object finished [0.0190s]\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 4 observations\n", "|-----------> There are 46755 features\n", "|-----------> Total missing values: 0\n", "|-----------> Percentage of missing values: 0.00%\n", "|-----> โœ… Log data statistics finished [0.0011s]\n", "|-----> โš™๏ธ Impute missing values started\n", "|-----------> No missing values found. No imputation necessary\n", "|-----> โœ… Impute missing values finished [0.0013s]\n", "|-----> ๐ŸŽ‰ Done! [0.0239s]\n" ] } ], "source": [ "adata = pya.preprocess.df_to_adata(df)" ] }, { "cell_type": "markdown", "id": "94035d2e-2e6b-4927-bb2b-0ddcd1b3cd4e", "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": "5d8b68ec-d3aa-4a10-b7e5-54811bddd68c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AnnData object with n_obs ร— n_vars = 4 ร— 46755\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": "ba48641d-ac0d-430c-9905-30a1349b7c50", "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.0006s]\n", "|-----> ๐Ÿ•’ Processing clock: bitage\n", "|-----------> โš™๏ธ Load clock started\n", "|-----------------> Data found in pyaging_data/bitage.pt\n", "|-----------> โœ… Load clock finished [0.5446s]\n", "|-----------> โš™๏ธ Check features in adata started\n", "|-----------------> All features are present in adata.var_names.\n", "|-----------------> Added prepared input matrix to adata.obsm[X_bitage]\n", "|-----------> โœ… Check features in adata finished [0.0424s]\n", "|-----------> โš™๏ธ Predict ages with model started\n", "|-----------------> The preprocessing method is binarize\n", "|-----------------> There is no postprocessing necessary\n", "|-----------------> in progress: 100.0000%\n", "|-----------> โœ… Predict ages with model finished [0.0044s]\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.6613s]\n" ] } ], "source": [ "pya.pred.predict_age(adata, 'BiTAge')" ] }, { "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", "
bitage
SRR1793993182.353658
SRR179399127.337245
SRR1793994241.629584
SRR179399232.178003
\n", "
" ], "text/plain": [ " bitage\n", "SRR1793993 182.353658\n", "SRR1793991 27.337245\n", "SRR1793994 241.629584\n", "SRR1793992 32.178003" ] }, "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('GSE65765', verbose=False)\n", "df = pd.read_pickle('pyaging_data/GSE65765_CPM.pkl')\n", "adata = pya.preprocess.df_to_adata(df, verbose=False)\n", "pya.pred.predict_age(adata, ['BiTAge'], 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", "
bitage
SRR1793993182.353658
SRR179399127.337245
SRR1793994241.629584
SRR179399232.178003
\n", "
" ], "text/plain": [ " bitage\n", "SRR1793993 182.353658\n", "SRR1793991 27.337245\n", "SRR1793994 241.629584\n", "SRR1793992 32.178003" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata.obs.head()" ] }, { "cell_type": "markdown", "id": "25aedb7e-5cff-42da-a0ea-cc0780395ea7", "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": "61dcb82f-e7f0-4064-8e67-b47b07b48a55", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AnnData object with n_obs ร— n_vars = 4 ร— 46755\n", " obs: 'bitage'\n", " var: 'percent_na'\n", " uns: 'bitage_percent_na', 'bitage_missing_features', 'bitage_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': 'bitage',\n", " 'data_type': 'transcriptomics',\n", " 'species': 'C elegans',\n", " 'year': 2021,\n", " 'approved_by_author': 'โœ…',\n", " 'citation': 'Meyer, David H., and Bjรถrn Schumacher. \"BiT age: A transcriptomeโ€based aging clock near the theoretical limit of accuracy.\" Aging cell 20.3 (2021): e13320.',\n", " 'doi': 'https://doi.org/10.1111/acel.13320',\n", " 'notes': None,\n", " 'version': None}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "adata.uns['bitage_metadata']" ] } ], "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.17" } }, "nbformat": 4, "nbformat_minor": 5 }