{ "cells": [ { "cell_type": "markdown", "id": "4885915e", "metadata": {}, "source": [ "# In-Silico Perturbation" ] }, { "cell_type": "code", "execution_count": null, "id": "e54fe7f9", "metadata": {}, "outputs": [], "source": [ "import CancerStFormer as cstformer\n", "from cstformer.perturbation.perturb import Perturber\n", "from cstformer.perturbation.perturb_stats import PerturberStats\n", "import pandas as pd \n", "import pickle\n", "import os\n", "import re" ] }, { "cell_type": "markdown", "id": "3ad23a7c", "metadata": {}, "source": [ "### 0.1 Parameter Descriptions" ] }, { "cell_type": "raw", "id": "6aea863b", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "**Parameters:**\n", " mode: {'spot','neighborhood'} \n", " | Type of dataset tokenization option \n", " | 'spot': if dataset is tokenized genes from only spot \n", " | 'neighborhood': if dataset is tokenized from spot and surrounding neighbors\n", " perturb_type : {\"delete\", \"overexpress\", \"inhibit\", \"activate\"}\n", " | Type of perturbation.\n", " | \"delete\": delete gene from rank value encoding\n", " | \"overexpress\": move gene to front of rank value encoding\n", " combos : {0,1}\n", " | Whether to perturb genes individually (0) or in pairs (1).\n", " anchor_gene : None, str\n", " | ENSEMBL ID of gene to use as anchor in combination perturbations.\n", " | For example, if combos=1 and anchor_gene=\"ENSG00000148400\":\n", " | anchor gene will be perturbed in combination with each other gene.\n", " model_type : {\"Pretrained\", \"GeneClassifier\", \"CellClassifier\"}\n", " | Whether model is the pretrained Geneformer or a fine-tuned gene or cell classifier.\n", " num_classes : int\n", " | If model is a gene or cell classifier, specify number of classes it was trained to classify.\n", " | For the pretrained Geneformer model, number of classes is 0 as it is not a classifier.\n", " emb_mode : {\"cell\", \"cell_and_gene\"}\n", " | Whether to output impact of perturbation on cell and/or gene embeddings.\n", " | Gene embedding shifts only available as compared to original cell, not comparing to goal state.\n", " cell_emb_style : \"mean_pool\"\n", " | Method for summarizing cell embeddings.\n", " | Currently only option is mean pooling of gene embeddings for given cell.\n", " filter_data : None, dict\n", " | Default is to use all input data for in silico perturbation study.\n", " | Otherwise, dictionary specifying .dataset column name and list of values to filter by.\n", " cell_states_to_model : None, dict\n", " | Cell states to model if testing perturbations that achieve goal state change.\n", " | Four-item dictionary with keys: state_key, start_state, goal_state, and alt_states\n", " | state_key: key specifying name of column in .dataset that defines the start/goal states\n", " | start_state: value in the state_key column that specifies the start state\n", " | goal_state: value in the state_key column taht specifies the goal end state\n", " | alt_states: list of values in the state_key column that specify the alternate end states\n", " | For example: {\"state_key\": \"disease\",\n", " | \"start_state\": \"dcm\",\n", " | \"goal_state\": \"nf\",\n", " | \"alt_states\": [\"hcm\", \"other1\", \"other2\"]}\n", " state_embs_dict : None, dict\n", " | Embedding positions of each cell state to model shifts from/towards (e.g. mean or median).\n", " | Dictionary with keys specifying each possible cell state to model.\n", " | Values are target embedding positions as torch.tensor.\n", " | For example: {\"nf\": emb_nf,\n", " | \"hcm\": emb_hcm,\n", " | \"dcm\": emb_dcm,\n", " | \"other1\": emb_other1,\n", " | \"other2\": emb_other2}\n", " max_ncells : None, int\n", " | Maximum number of cells to test.\n", " | If None, will test all cells.\n", " cell_inds_to_perturb : \"all\", list\n", " | Default is perturbing each cell in the dataset.\n", " | Otherwise, may provide a dict of indices of cells to perturb with keys start_ind and end_ind.\n", " | start_ind: the first index to perturb.\n", " | end_ind: the last index to perturb (exclusive).\n", " | Indices will be selected *after* the filter_data criteria and sorting.\n", " | Useful for splitting extremely large datasets across separate GPUs.\n", " emb_layer : {-1, 0}\n", " | Embedding layer to use for quantification.\n", " | 0: last layer (recommended for questions closely tied to model's training objective)\n", " | -1: 2nd to last layer (recommended for questions requiring more general representations)\n", " forward_batch_size : int\n", " | Batch size for forward pass.\n", " nproc : int\n", " | Number of CPU processes to use.\n", " token_dictionary_file : Path\n", " | Path to pickle file containing token dictionary (Ensembl ID:token)" ] }, { "cell_type": "markdown", "id": "0539f30a", "metadata": {}, "source": [ "### 1.1 Option A: Delete Single Gene and View both Gene and Cell Embedding Shifts" ] }, { "cell_type": "markdown", "id": "441eaa32", "metadata": {}, "source": [ "Here we look at the following option:\n", "1. Delete Gene: PDCD1\n", "2. Load in pretrained model on masked learning objective\n", "3. want to look at the cosine similarity to null distribution when perturbing PDCD1 in both per gene and per cell embedding\n", "4. batch our perturbations at each model forward pass\n" ] }, { "cell_type": "code", "execution_count": null, "id": "aa0ecf37", "metadata": {}, "outputs": [], "source": [ "isp = Perturber(\n", " mode = 'extended', #perturbing either spot or extended model (based on tokenization)\n", " perturb_type=\"delete\", # in-silico deletion\n", " genes_to_perturb=['PDCD1'], #immune checkpiont\n", " perturb_rank_shift = None,\n", " model_type=\"GeneClassifier\", # GeneClassifier Model (can use CellClassifier, GeneClassifier, Pretrained (ML))\n", " num_classes=2, # classes used in classifier\n", " emb_mode=\"cell_and_gene\", # cell and gene shifts \n", " cell_emb_style='mean_pool',\n", " max_ncells=1000, #num cells use in perturbation\n", " emb_layer=-1, \n", " forward_batch_size=80, #minibatch size\n", " nproc=1, # num threads\n", " token_dictionary_file='new_token_dictionary.pickle', # gene -> token mapping\n", " )\n", " \n", "isp.perturb_dataset(\n", " model_directory='run-8eb93bdf/checkpoint-1000', #which final model to choose\n", " input_data_file='STFormer_TNBC_neighbor.dataset', #tokenized dataset\n", " output_directory='output/perturb/cell_shift', \n", " output_prefix='perturb_extended')" ] }, { "cell_type": "markdown", "id": "06ab3e15", "metadata": {}, "source": [ "We want to create stats to evaluate the effect of PDCD1 gene expression on:\n", "1. Cell embeddings similarity to unperturbed cells\n", "2. Gene embedding similarity to unperturbed genes, where we aggregate the gene shifts for our cells for each other token in our dataset\n", " - ex: how does deletion of PDCD1 effect the expression of another gene like CCR5AS\n", " - These results are ranked by mean cosine similarity (lowest -> highest) where low similarity signifies a greater impact on gene expression and a high dependency on the gene expression of our perturbed gene\n", " - provides standeard deviation of cosine similarity between gene embeddings and the number of detections" ] }, { "cell_type": "code", "execution_count": null, "id": "1a9bc21e", "metadata": {}, "outputs": [], "source": [ "from cstformer.perturbation.perturb_stats import PerturberStats\n", "\n", "ispstats = PerturberStats(\n", " mode='aggregate_gene_shifts', # view gene shifts due to perturbation\n", " gene_id_name_dict='gene_id_dictionary.pickle', # maps gene -> ENS (prints in gene_name)\n", " token_dictionary_file = 'new_token_dictionary.pickle' # gene -> token dict\n", ")\n", "ispstats.compute_stats(\n", " input_data_dir = 'output/perturb', # where embeddings are located\n", " null_data_dir=None, # compare to null distribution\n", " output_directory = 'output/perturb/perturb_stats',\n", " output_prefix= 'perturb_extended'\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "70c8f02e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | Perturbed | \n", "Gene_name | \n", "Ensembl_ID | \n", "Affected | \n", "Affected_gene_name | \n", "Affected_Ensembl_ID | \n", "Cosine_sim_mean | \n", "Cosine_sim_stdev | \n", "N_Detections | \n", "
|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "NEK11 | \n", "NEK11 | \n", "NEK11 | \n", "0.567151 | \n", "0.0 | \n", "2 | \n", "
| 1 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "SYT17 | \n", "SYT17 | \n", "SYT17 | \n", "0.632933 | \n", "0.0 | \n", "2 | \n", "
| 2 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "CASS4 | \n", "CASS4 | \n", "CASS4 | \n", "0.645120 | \n", "0.0 | \n", "2 | \n", "
| 3 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "CAPN10-DT | \n", "CAPN10-DT | \n", "CAPN10-DT | \n", "0.679628 | \n", "0.0 | \n", "2 | \n", "
| 4 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDE1B | \n", "PDE1B | \n", "PDE1B | \n", "0.706005 | \n", "0.0 | \n", "2 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 15370 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "AL133453.1 | \n", "AL133453.1 | \n", "AL133453.1 | \n", "0.999678 | \n", "0.0 | \n", "2 | \n", "
| 15371 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "ACP7 | \n", "ACP7 | \n", "ACP7 | \n", "0.999701 | \n", "0.0 | \n", "2 | \n", "
| 15372 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "AL589182.1 | \n", "AL589182.1 | \n", "AL589182.1 | \n", "0.999710 | \n", "0.0 | \n", "2 | \n", "
| 15373 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "PIH1D2 | \n", "PIH1D2 | \n", "PIH1D2 | \n", "0.999718 | \n", "0.0 | \n", "2 | \n", "
| 15374 | \n", "PDCD1 | \n", "PDCD1 | \n", "PDCD1 | \n", "FAM218A | \n", "FAM218A | \n", "FAM218A | \n", "0.999774 | \n", "0.0 | \n", "2 | \n", "
15375 rows × 9 columns
\n", "| \n", " | Gene | \n", "Gene_name | \n", "Ensembl_ID | \n", "Shift_to_goal_end | \n", "Goal_end_vs_random_pval | \n", "N_Detections | \n", "Shift_to_alt_end_Invasive cancer + stroma | \n", "Alt_end_vs_random_pval_Invasive cancer + stroma | \n", "Shift_to_alt_end_Invasive cancer + stroma + lymphocytes | \n", "Alt_end_vs_random_pval_Invasive cancer + stroma + lymphocytes | \n", "Goal_end_FDR | \n", "Alt_end_FDR_Invasive cancer + stroma | \n", "Alt_end_FDR_Invasive cancer + stroma + lymphocytes | \n", "Sig | \n", "
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2979 | \n", "3907 | \n", "ANKRD37 | \n", "ENSG00000186352 | \n", "0.001014 | \n", "0.027741 | \n", "5 | \n", "0.000712 | \n", "0.174332 | \n", "0.000750 | \n", "0.090140 | \n", "0.924671 | \n", "0.913586 | \n", "0.873315 | \n", "0 | \n", "
| 11646 | \n", "17551 | \n", "SPINK4 | \n", "ENSG00000122711 | \n", "0.000910 | \n", "0.175442 | \n", "6 | \n", "0.001164 | \n", "0.132797 | \n", "0.001139 | \n", "0.133500 | \n", "0.953533 | \n", "0.886458 | \n", "0.888611 | \n", "0 | \n", "
| 7884 | \n", "10285 | \n", "ARID4A | \n", "ENSG00000032219 | \n", "0.000824 | \n", "0.023335 | \n", "10 | \n", "0.000348 | \n", "0.601956 | \n", "0.000403 | \n", "0.424766 | \n", "0.924671 | \n", "0.982160 | \n", "0.959837 | \n", "0 | \n", "
| 9497 | \n", "12278 | \n", "HOXB-AS1 | \n", "ENSG00000230148 | \n", "0.000818 | \n", "0.024909 | \n", "6 | \n", "0.000750 | \n", "0.044214 | \n", "0.000770 | \n", "0.026993 | \n", "0.924671 | \n", "0.823552 | \n", "0.790271 | \n", "0 | \n", "
| 10644 | \n", "13690 | \n", "PBX4 | \n", "ENSG00000105717 | \n", "0.000778 | \n", "0.003643 | \n", "7 | \n", "0.001221 | \n", "0.005439 | \n", "0.001154 | \n", "0.005040 | \n", "0.924671 | \n", "0.734657 | \n", "0.715931 | \n", "0 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 53 | \n", "64 | \n", "TTC34 | \n", "ENSG00000215912 | \n", "-0.000763 | \n", "0.013673 | \n", "9 | \n", "0.000024 | \n", "0.509069 | \n", "-0.000080 | \n", "0.630417 | \n", "0.924671 | \n", "0.974761 | \n", "0.974686 | \n", "0 | \n", "
| 5066 | \n", "6672 | \n", "IDO1 | \n", "ENSG00000131203 | \n", "-0.000782 | \n", "0.055477 | \n", "7 | \n", "-0.000479 | \n", "0.125197 | \n", "-0.000522 | \n", "0.074521 | \n", "0.924671 | \n", "0.886458 | \n", "0.853843 | \n", "0 | \n", "
| 5856 | \n", "7701 | \n", "CAVIN3 | \n", "ENSG00000170955 | \n", "-0.000879 | \n", "0.013125 | \n", "6 | \n", "-0.000491 | \n", "0.008692 | \n", "-0.000545 | \n", "0.005454 | \n", "0.924671 | \n", "0.734657 | \n", "0.715931 | \n", "0 | \n", "
| 479 | \n", "604 | \n", "FYB2 | \n", "ENSG00000187889 | \n", "-0.000925 | \n", "0.005857 | \n", "11 | \n", "-0.000171 | \n", "0.891572 | \n", "-0.000269 | \n", "0.694267 | \n", "0.924671 | \n", "0.996187 | \n", "0.985234 | \n", "0 | \n", "
| 4609 | \n", "6032 | \n", "SHROOM2 | \n", "ENSG00000146950 | \n", "-0.001132 | \n", "0.015731 | \n", "6 | \n", "-0.000631 | \n", "0.063054 | \n", "-0.000729 | \n", "0.040795 | \n", "0.924671 | \n", "0.848050 | \n", "0.828248 | \n", "0 | \n", "
11664 rows × 14 columns
\n", "