{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Non-negative PARAFAC Decomposition of IL-2 Response Data\n\nHere we will provide an example of how to use non-negative PARAFAC tensor \ndecomposition (:func:`tensorly.decomposition.parafac`) to first reduce the dimensionality \nof a tensor of experimental data, and then make insights about the underlying structure \nof that data.\n\nTo do this, we will work with a tensor of experimentally measured cell signaling data.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nimport matplotlib.pyplot as plt\nfrom tensorly.datasets import load_IL2data\nfrom tensorly.decomposition import non_negative_parafac\nfrom tensorly.cp_tensor import cp_normalize"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we will load a tensor of experimentally measured cellular responses to \nIL-2 stimulation. IL-2 is a naturally occurring immune signaling molecule \nwhich has been engineered by pharmaceutical companies and drug designers \nin attempts to act as an effective immunotherapy. In order to make effective IL-2\ntherapies, pharmaceutical engineer have altered IL-2's signaling activity in order to\nincrease or decrease its interactions with particular cell types. \n\nIL-2 signals through the Jak/STAT pathway and transmits a signal into immune cells by \nphosphorylating STAT5 (pSTAT5). When phosphorylated, STAT5 will cause various immune \ncell types to proliferate, and depending on whether regulatory (regulatory T cells, or Tregs) \nor effector cells (helper T cells, natural killer cells, and cytotoxic T cells,\nor Thelpers, NKs, and CD8+ cells) respond, IL-2 signaling can result in \nimmunosuppression or immunostimulation respectively. Thus, when designing a drug\nmeant to repress the immune system, potentially for the treatment of autoimmune\ndiseases, IL-2 which primarily enacts a response in Tregs is desirable. Conversely,\nwhen designing a drug that is meant to stimulate the immune system, potentially for\nthe treatment of cancer, IL-2 which primarily enacts a response in effector cells\nis desirable. In order to achieve either signaling bias, IL-2 variants with altered\naffinity for it's various receptors (IL2R\u03b1 or IL2R\u03b2) have been designed. Furthermore\nIL-2 variants with multiple binding domains have been designed as multivalent \nIL-2 may act as a more effective therapeutic. In order to understand how these mutations\nand alterations affect which cells respond to an IL-2 mutant, we will perform \nnon-negative PARAFAC tensor decomposition on our cell response data tensor.\n\nHere, our data contains the responses of 8 different cell types to 13 different \nIL-2 mutants, at 4 different timepoints, at 12 standardized IL-2 concentrations.\nTherefore, our tensor will have shape (13 x 4 x 12 x 8), with dimensions\nrepresenting IL-2 mutant, stimulation time, dose, and cell type respectively. Each\nmeasured quantity represents the amount of phosphorlyated STAT5 (pSTAT5) in a \ngiven cell population following stimulation with the specified IL-2 mutant.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"response_data = load_IL2data()\nIL2mutants, cells = response_data.ticks[0], response_data.ticks[3]\nprint(response_data.tensor.shape, response_data.dims)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we will run non-negative PARAFAC tensor decomposition to reduce the dimensionality \nof our tensor. We will use 3 components, and normalize our resulting tensor to aid in \nfuture comparisons of correlations across components.\n\nFirst we must preprocess our tensor to ready it for factorization. Our data has a \nfew missing values, and so we must first generate a mask to mark where those values\noccur.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"tensor_mask = np.isfinite(response_data.tensor)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we've marked where those non-finite values occur, we can regenerate our \ntensor without including non-finite values, allowing it to be factorized.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"response_data_fin = np.nan_to_num(response_data.tensor)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using this mask, and finite-value only tensor, we can decompose our signaling data into\nthree components. We will also normalize this tensor, which will allow for easier\ncomparisons to be made between the meanings, and magnitudes of our resulting components.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"sig_tensor_fact = non_negative_parafac(response_data_fin, init='random', rank=3, mask=tensor_mask, n_iter_max=5000, tol=1e-9, random_state=1)\nsig_tensor_fact = cp_normalize(sig_tensor_fact)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we will load the names of our cell types and IL-2 mutants, in the order in which \nthey are present in our original tensor. IL-2 mutant names refer to the specific \nmutations made to their amino acid sequence, as well as their valency \nformat (monovalent or bivalent).\n\nFinally, we label, plot, and analyze our factored tensor of data.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"f, ax = plt.subplots(1, 2, figsize=(9, 4.5))\n\ncomponents = [1, 2, 3]\nwidth = 0.25\n\nlig_facs = sig_tensor_fact[1][0]\nligands = IL2mutants\nx_lig = np.arange(len(ligands))\n\nlig_rects_comp1 = ax[0].bar(x_lig - width, lig_facs[:, 0], width, label='Component 1')\nlig_rects_comp2 = ax[0].bar(x_lig, lig_facs[:, 1], width, label='Component 2')\nlig_rects_comp3 = ax[0].bar(x_lig + width, lig_facs[:, 2], width, label='Component 3')\nax[0].set(xlabel=\"Ligand\", ylabel=\"Component Weight\", ylim=(0, 1))\nax[0].set_xticks(x_lig, ligands)\nax[0].set_xticklabels(ax[0].get_xticklabels(), rotation=60, ha=\"right\", fontsize=9)\nax[0].legend()\n\n\ncell_facs = sig_tensor_fact[1][3]\nx_cell = np.arange(len(cells))\n\ncell_rects_comp1 = ax[1].bar(x_cell - width, cell_facs[:, 0], width, label='Component 1')\ncell_rects_comp2 = ax[1].bar(x_cell, cell_facs[:, 1], width, label='Component 2')\ncell_rects_comp3 = ax[1].bar(x_cell + width, cell_facs[:, 2], width, label='Component 3')\nax[1].set(xlabel=\"Cell\", ylabel=\"Component Weight\", ylim=(0, 1))\nax[1].set_xticks(x_cell, cells)\nax[1].set_xticklabels(ax[1].get_xticklabels(), rotation=45, ha=\"right\")\nax[1].legend()\n\nf.tight_layout()\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we observe the correlations which both ligands and cell types have with each of \nour three components - we can interepret our tensor factorization for looking for \npatterns among these correlations. \n\nFor example, we can see that bivalent mutants generally have higher correlations with\ncomponent two, as do regulatory T cells. Thus we can infer that bivalent ligands \nactivate regulatory T cells more than monovalent ligands. We also see that this \nrelationship is strengthened by the availability of IL2R\u03b1, one subunit of the IL-2 receptor.\n\nThis is just one example of an insight we can make using tensor factorization. \nBy plotting the correlations which time and dose have with each component, we \ncould additionally make inferences as to the dynamics and dose dependence of how mutations \naffect IL-2 signaling in immune cells.\n\n"
]
}
],
"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.10.14"
}
},
"nbformat": 4,
"nbformat_minor": 0
}