Boom5426 commited on
Commit
07fcdfe
·
verified ·
1 Parent(s): b57d50b

Upload GID-Flow project snapshot (deduped: code + key artifacts)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +8 -0
  2. PDGrapher/.gitignore +186 -0
  3. PDGrapher/.pytest_cache/.gitignore +2 -0
  4. PDGrapher/.pytest_cache/CACHEDIR.TAG +4 -0
  5. PDGrapher/.pytest_cache/README.md +8 -0
  6. PDGrapher/.pytest_cache/v/cache/lastfailed +13 -0
  7. PDGrapher/.pytest_cache/v/cache/nodeids +246 -0
  8. PDGrapher/.pytest_cache/v/cache/stepwise +1 -0
  9. PDGrapher/CHANGELOG.md +8 -0
  10. PDGrapher/LICENSE +29 -0
  11. PDGrapher/README.md +121 -0
  12. PDGrapher/TODO.md +10 -0
  13. PDGrapher/conda-env.yml +63 -0
  14. PDGrapher/configs/causal_flow_drug.yaml +119 -0
  15. PDGrapher/configs/drug_rank_phase1.yaml +36 -0
  16. PDGrapher/configs/drug_rank_phase2.yaml +53 -0
  17. PDGrapher/configs/drug_repurposing.yaml +45 -0
  18. PDGrapher/data/README.md +38 -0
  19. PDGrapher/data/check_data_and_splits.ipynb +374 -0
  20. PDGrapher/data/chembl_smiles.csv +167 -0
  21. PDGrapher/data/process_all_data.sh +35 -0
  22. PDGrapher/data/processed/sciplex3_k562_24h_gene_map.json +1978 -0
  23. PDGrapher/data/protein/protein_features.csv +0 -0
  24. PDGrapher/data/raw/cosmic/2022-10-COSMIC/README.md +17 -0
  25. PDGrapher/data/raw/drugbank/2022-11-DrugBank/README.md +24 -0
  26. PDGrapher/data/raw/lincs/2022-02-LINCS_Level3/README.md +21 -0
  27. PDGrapher/data/raw/ppi/2022-03-PPI/README.md +31 -0
  28. PDGrapher/data/raw/ppi/2022-03-PPI/geneinfo_beta.txt +0 -0
  29. PDGrapher/data/raw/ppi/2022-03-PPI/hgnc2map.txt +0 -0
  30. PDGrapher/data/scripts/GRN/GENIE3.py +345 -0
  31. PDGrapher/data/scripts/GRN/GENIEppi-run.py +53 -0
  32. PDGrapher/data/scripts/GRN/README.md +31 -0
  33. PDGrapher/data/scripts/GRN/filter_edge_list.py +89 -0
  34. PDGrapher/data/scripts/GRN/xpr_matrix_generator_datatypesplit.py +82 -0
  35. PDGrapher/data/scripts/cosmic/generate_cell_line_mutations_files.py +60 -0
  36. PDGrapher/data/scripts/drugbank/get_drug_targets.py +59 -0
  37. PDGrapher/data/scripts/lincs/process_data.py +881 -0
  38. PDGrapher/data/scripts/lincs/process_data_chemical_1.py +249 -0
  39. PDGrapher/data/scripts/lincs/process_data_chemical_2.py +697 -0
  40. PDGrapher/data/scripts/lincs/process_data_healthy.py +362 -0
  41. PDGrapher/data/scripts/lincs/process_data_healthy_chemical.py +364 -0
  42. PDGrapher/data/scripts/ppi/README.md +3 -0
  43. PDGrapher/data/scripts/ppi/export_ppi_all_genes.py +70 -0
  44. PDGrapher/data/scripts/ppi/union_ppi.py +143 -0
  45. PDGrapher/data/scripts/random-baseline-cancer-targets/get_drugs_and_targets_cancer_cell_lines.py +147 -0
  46. PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_scgen_chemical.py +55 -0
  47. PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_scgen_genetic.py +70 -0
  48. PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_torch_geometric.py +344 -0
  49. PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_torch_geometric_chemical.py +391 -0
  50. PDGrapher/data/scripts/splits/create_standard_splits.py +97 -0
.gitattributes CHANGED
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ PDGrapher/fonts/Arial[[:space:]]Bold[[:space:]]Italic.ttf filter=lfs diff=lfs merge=lfs -text
37
+ PDGrapher/fonts/Arial[[:space:]]Bold.ttf filter=lfs diff=lfs merge=lfs -text
38
+ PDGrapher/fonts/Arial[[:space:]]Italic.ttf filter=lfs diff=lfs merge=lfs -text
39
+ PDGrapher/fonts/Arial.ttf filter=lfs diff=lfs merge=lfs -text
40
+ PDGrapher/paper/paper.pdf filter=lfs diff=lfs merge=lfs -text
41
+ references/PDGrapher-NBE教你反向设计.pdf filter=lfs diff=lfs merge=lfs -text
42
+ references/SCALE.pdf filter=lfs diff=lfs merge=lfs -text
43
+ references/science.DrugReflector.pdf filter=lfs diff=lfs merge=lfs -text
PDGrapher/.gitignore ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ .idea/
161
+
162
+ # VSCode
163
+ .vscode/
164
+
165
+ # Data folder
166
+ # Ignore everything in data folder. An exception are Python processing files
167
+ # and bash files, .keep files are there to enforce the directory structure.
168
+ # Use `git add -f` to add something to data folder.
169
+ data/
170
+
171
+ tests/PDGrapher_test/*
172
+ !tests/PDGrapher_test/.keep
173
+
174
+
175
+ #jobs scripts
176
+ job_*
177
+
178
+
179
+ #large files
180
+ *ours_to_real.txt
181
+ *random_to_real.txt
182
+ *aggregated_ranking_random.pickle
183
+ *aggregated_ranking.pickle
184
+
185
+ #irrelevant
186
+ *scgen*
PDGrapher/.pytest_cache/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Created by pytest automatically.
2
+ *
PDGrapher/.pytest_cache/CACHEDIR.TAG ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Signature: 8a477f597d28d172789f06886806bc55
2
+ # This file is a cache directory tag created by pytest.
3
+ # For information about cache directory tags, see:
4
+ # https://bford.info/cachedir/spec.html
PDGrapher/.pytest_cache/README.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # pytest cache directory #
2
+
3
+ This directory contains data from the pytest's cache plugin,
4
+ which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
5
+
6
+ **Do not** commit this to version control.
7
+
8
+ See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
PDGrapher/.pytest_cache/v/cache/lastfailed ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_row_sum_le_1": true,
3
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_symmetric_and_positive": true,
4
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_output_not_all_same": true,
5
+ "tests/test__models.py": true,
6
+ "tests/test_pdgrapher.py": true,
7
+ "tests/test_datasets.py::TestDataset::test_multiple_folds": true,
8
+ "tests/test_datasets.py::TestDataset::test_single_fold": true,
9
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_with_protein_features": true,
10
+ "tests/test_package.py::TestPackage::test_multiple_folds": true,
11
+ "tests/test_package.py::TestPackage::test_single_fold": true,
12
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_alpha_beta_weighting": true
13
+ }
PDGrapher/.pytest_cache/v/cache/nodeids ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ "tests/test__utils.py::TestCalculateLossSampleWeights::test_diseased",
3
+ "tests/test__utils.py::TestCalculateLossSampleWeights::test_intervention",
4
+ "tests/test__utils.py::TestCalculateLossSampleWeights::test_output",
5
+ "tests/test__utils.py::TestCalculateLossSampleWeights::test_treated",
6
+ "tests/test__utils.py::TestCalculateLossSampleWeights::test_wrong_kind",
7
+ "tests/test__utils.py::TestDummyWriter::test_create",
8
+ "tests/test__utils.py::TestDummyWriter::test_writing",
9
+ "tests/test__utils.py::TestEarlyStopping::test_saving_loading",
10
+ "tests/test__utils.py::TestGetThresholds::test_output",
11
+ "tests/test__utils.py::TestGetThresholds::test_output_all",
12
+ "tests/test__utils.py::TestGetThresholds::test_wrong_kind",
13
+ "tests/test__utils.py::TestTestCondition::test_assertion_false",
14
+ "tests/test__utils.py::TestTestCondition::test_assertion_true",
15
+ "tests/test__utils.py::TestTicToc::test_output_basic_1",
16
+ "tests/test__utils.py::TestTicToc::test_output_basic_2",
17
+ "tests/test__utils.py::TestTicToc::test_output_custom",
18
+ "tests/test__utils.py::TestTicToc::test_output_custom_format",
19
+ "tests/test__utils.py::TestTicToc::test_output_wrapped",
20
+ "tests/test__utils.py::TestTicToc::test_output_wrapped_custom",
21
+ "tests/test__utils.py::TestTicToc::test_output_wrapped_custom_format",
22
+ "tests/test__utils.py::TestTicToc::test_wrapped_wrong_format",
23
+ "tests/test__utils.py::TestTicToc::test_wrong_format",
24
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_alpha_beta_weighting",
25
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_bce_only",
26
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_gradient_flows",
27
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_perfect_prediction_low_loss",
28
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_sampled_bce_different_neg_counts",
29
+ "tests/test_causal_estimator.py::TestCausalAlignmentLoss::test_with_effect_magnitude",
30
+ "tests/test_causal_estimator.py::TestCausalGPU::test_estimator_on_cuda",
31
+ "tests/test_causal_estimator.py::TestCausalGPU::test_planner_on_cuda",
32
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_build_co_occurrence_graph_basic",
33
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_build_co_occurrence_graph_device",
34
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_build_co_occurrence_graph_symmetric",
35
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_co_occurrence_produces_different_scores",
36
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_deterministic_with_seed",
37
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_different_batch_sizes",
38
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_gradient_flows",
39
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_large_gene_set",
40
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_no_nan_forward",
41
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_output_has_variance",
42
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_output_not_all_same",
43
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_output_range_sigmoid",
44
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_output_shape",
45
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_with_co_occurrence_graph",
46
+ "tests/test_causal_estimator.py::TestCausalGeneEstimator::test_without_co_occurrence_graph",
47
+ "tests/test_causal_estimator.py::TestCausalPlanner::test_forward_output_shapes",
48
+ "tests/test_causal_estimator.py::TestCausalPlanner::test_forward_with_co_occurrence",
49
+ "tests/test_causal_estimator.py::TestCausalPlanner::test_gradient_flows",
50
+ "tests/test_causal_estimator.py::TestCausalPlanner::test_no_nan",
51
+ "tests/test_causal_estimator.py::TestCausalPlanner::test_output_range",
52
+ "tests/test_causal_estimator.py::TestCausalSparsityLoss::test_gradient_flows",
53
+ "tests/test_causal_estimator.py::TestCausalSparsityLoss::test_output_scalar",
54
+ "tests/test_causal_estimator.py::TestCausalSparsityLoss::test_scales_with_mean_score",
55
+ "tests/test_causal_estimator.py::TestCausalSparsityLoss::test_weight_scaling",
56
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGPU::test_forward_on_cuda",
57
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_forward_keys",
58
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_forward_shapes",
59
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_gradient_flows",
60
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_loss_decreases_over_steps",
61
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_no_nan",
62
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_predict_targets",
63
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpace::test_recon_loss_zero",
64
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDGeneSpaceGPU::test_forward_on_cuda",
65
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_causal_scores_informative",
66
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_different_batch_sizes",
67
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_forward_keys",
68
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_forward_shapes",
69
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_gradient_flows",
70
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_loss_components_nonzero",
71
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_loss_is_finite",
72
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_no_nan",
73
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_predict_targets",
74
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_predict_targets_no_topk",
75
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_without_co_occurrence",
76
+ "tests/test_causal_flow_gid.py::TestCausalFlowGIDModel::test_without_true_perturbation",
77
+ "tests/test_datasets.py::TestDataset::test_multiple_folds",
78
+ "tests/test_datasets.py::TestDataset::test_single_fold",
79
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_de_loss_enabled",
80
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_de_zero_when_weight_zero",
81
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_differentiable",
82
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_gpu_if_available",
83
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_loss_lower_when_pred_equals_target",
84
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_no_nan",
85
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_output_keys",
86
+ "tests/test_distributional_cycle_loss.py::TestDistributionalCycleLoss::test_with_masks",
87
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_distant_distributions_high_mmd",
88
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_identical_distributions_low_mmd",
89
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_mmd_differentiable",
90
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_mmd_fixed_sigma",
91
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_mmd_shape",
92
+ "tests/test_distributional_cycle_loss.py::TestMMDRBF::test_mmd_with_mask",
93
+ "tests/test_distributional_cycle_loss.py::TestMaskedStats::test_masked_mean_no_mask",
94
+ "tests/test_distributional_cycle_loss.py::TestMaskedStats::test_masked_mean_with_mask",
95
+ "tests/test_distributional_cycle_loss.py::TestMaskedStats::test_masked_var_shape",
96
+ "tests/test_distributional_cycle_loss.py::TestMaskedStats::test_masked_var_with_mask",
97
+ "tests/test_drug_modules.py::TestDoseConsistencyLoss::test_consistent_predictions",
98
+ "tests/test_drug_modules.py::TestDoseConsistencyLoss::test_inconsistent_predictions",
99
+ "tests/test_drug_modules.py::TestDoseConsistencyLoss::test_no_duplicates",
100
+ "tests/test_drug_modules.py::TestDrugAlignmentLoss::test_forward_with_targets",
101
+ "tests/test_drug_modules.py::TestDrugAlignmentLoss::test_forward_without_dose",
102
+ "tests/test_drug_modules.py::TestDrugEncoder::test_different_emb_dims",
103
+ "tests/test_drug_modules.py::TestDrugEncoder::test_embedding_cache",
104
+ "tests/test_drug_modules.py::TestDrugEncoder::test_empty_input",
105
+ "tests/test_drug_modules.py::TestDrugEncoder::test_morgan_encoding_frozen",
106
+ "tests/test_drug_modules.py::TestDrugEncoder::test_morgan_encoding_shape",
107
+ "tests/test_drug_modules.py::TestDrugEncoder::test_morgan_encoding_trainable",
108
+ "tests/test_drug_modules.py::TestDrugEncoder::test_similarity",
109
+ "tests/test_drug_modules.py::TestDrugGeneBridge::test_forward_shape_with_gene_emb",
110
+ "tests/test_drug_modules.py::TestDrugGeneBridge::test_forward_shape_without_gene_emb",
111
+ "tests/test_drug_modules.py::TestDrugGeneBridge::test_gene_aware_attention",
112
+ "tests/test_drug_modules.py::TestDrugTargetAlignmentLoss::test_perfect_prediction",
113
+ "tests/test_drug_modules.py::TestDrugTargetAlignmentLoss::test_wrong_prediction",
114
+ "tests/test_flow_response.py::TestFlowMatchingGPU::test_forward_on_cuda",
115
+ "tests/test_flow_response.py::TestFlowMatchingGPU::test_sample_on_cuda",
116
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_different_gene_dims",
117
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_forward_loss_no_nan",
118
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_forward_loss_scalar",
119
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_gradient_flows",
120
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_loss_zero_when_source_equals_target",
121
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_no_encoder_decoder",
122
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_reconstruction_loss_zero",
123
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_sample_is_different_from_source",
124
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_sample_no_nan",
125
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_sample_shape",
126
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpace::test_variable_cell_count",
127
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpaceGPU::test_forward_on_cuda",
128
+ "tests/test_flow_response.py::TestFlowMatchingGeneSpaceGPU::test_sample_on_cuda",
129
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_batch_size_one",
130
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_deterministic_with_seed",
131
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_different_gene_dims",
132
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_forward_loss_no_nan",
133
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_forward_loss_scalar",
134
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_loss_lower_for_similar_targets",
135
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_loss_zero_when_source_equals_target",
136
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_more_steps_better",
137
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_sample_gradient_does_not_flow",
138
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_sample_no_nan",
139
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_sample_shape",
140
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_t_at_extremes",
141
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_target_cells_required",
142
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_training_gradient_flows",
143
+ "tests/test_flow_response.py::TestFlowMatchingResponseModel::test_variable_cell_count",
144
+ "tests/test_flow_response.py::TestSinusoidalTimeEmbedding::test_different_for_different_t",
145
+ "tests/test_flow_response.py::TestSinusoidalTimeEmbedding::test_differentiable",
146
+ "tests/test_flow_response.py::TestSinusoidalTimeEmbedding::test_output_shape",
147
+ "tests/test_flow_response.py::TestSinusoidalTimeEmbedding::test_output_shape_odd_dim",
148
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_forward_shapes",
149
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_gcn_off_matches_no_graph",
150
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_gradient_flows_through_gcn",
151
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_no_nan",
152
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_predict_targets_shape",
153
+ "tests/test_gene_graph_encoder.py::TestGIDModelWithGeneGraph::test_with_protein_features_and_graph",
154
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_different_graphs_give_different_embeddings",
155
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_gradient_through_embedding",
156
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_no_nan",
157
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_output_shape",
158
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_real_pdgrapher_graph",
159
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_set_graph_raises_before_forward",
160
+ "tests/test_gene_graph_encoder.py::TestGeneGraphEncoder::test_with_protein_features",
161
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_nonneg_and_diagonal_positive",
162
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_row_sum_le_1",
163
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_symmetric_and_positive",
164
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_adjacency_undirected_is_symmetric",
165
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_build_normalized_adjacency_shape",
166
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_extract_subgraph_correct_remapping",
167
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_extract_subgraph_reduces_edges",
168
+ "tests/test_gene_graph_encoder.py::TestGraphUtils::test_load_pdgrapher_edge_index",
169
+ "tests/test_package.py::TestPackage::test_multiple_folds",
170
+ "tests/test_package.py::TestPackage::test_single_fold",
171
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_dataloader_integration",
172
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_mask_values",
173
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_max_cells_truncation",
174
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_output_type",
175
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_padded_shapes",
176
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_padding_is_zero",
177
+ "tests/test_population_batch.py::TestPopulationCollateFn::test_perturbation_stacked_correctly",
178
+ "tests/test_population_batch.py::TestPopulationPerturbationBatch::test_optional_fields_default_none",
179
+ "tests/test_population_batch.py::TestPopulationPerturbationBatch::test_shapes",
180
+ "tests/test_population_batch.py::TestPopulationPerturbationBatch::test_to_device_cpu",
181
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_cell_counts_in_range",
182
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_different_seeds_differ",
183
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_gene_dim",
184
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_item_keys",
185
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_length",
186
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_perturbation_is_multihot",
187
+ "tests/test_population_batch.py::TestSyntheticPopulationPerturbationDataset::test_reproducible",
188
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_batch_size_1",
189
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_different_n_per_call",
190
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_gpu_if_available",
191
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_gradient_flows",
192
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_mask_accepted",
193
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_no_nan",
194
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_output_shape",
195
+ "tests/test_population_response.py::TestSimplePopulationResponseModel::test_perturbation_changes_output",
196
+ "tests/test_real_data.py::TestGeneSelection::test_hvg_fewer_than_requested",
197
+ "tests/test_real_data.py::TestGeneSelection::test_hvg_shape",
198
+ "tests/test_real_data.py::TestGeneSelection::test_normalize_log1p",
199
+ "tests/test_real_data.py::TestGeneSelection::test_normalize_no_log",
200
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_collate_fn_integration",
201
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_item_shapes",
202
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_length",
203
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_no_nan",
204
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_num_genes",
205
+ "tests/test_real_data.py::TestPDGrapherPseudobulkDataset::test_perturbation_nonzero",
206
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_collate_fn_integration",
207
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_item_shapes",
208
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_most_perts_in_gene_space",
209
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_num_conditions",
210
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_perturbation_is_multihot",
211
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_reproducibility",
212
+ "tests/test_real_data.py::TestScPerturbPopulationDataset::test_source_target_differ",
213
+ "tests/test_sparse_planner.py::TestGapEncoder::test_gradient_flows",
214
+ "tests/test_sparse_planner.py::TestGapEncoder::test_output_shape",
215
+ "tests/test_sparse_planner.py::TestMMDProjected::test_different_dist_higher_mmd",
216
+ "tests/test_sparse_planner.py::TestMMDProjected::test_same_dist_low_mmd",
217
+ "tests/test_sparse_planner.py::TestMMDProjected::test_shape",
218
+ "tests/test_sparse_planner.py::TestPerturbationEval::test_compute_all_returns_keys",
219
+ "tests/test_sparse_planner.py::TestPerturbationEval::test_de_direction_agreement_perfect",
220
+ "tests/test_sparse_planner.py::TestPerturbationEval::test_pearson_r_good_better_than_random",
221
+ "tests/test_sparse_planner.py::TestPerturbationEval::test_pearson_r_perfect",
222
+ "tests/test_sparse_planner.py::TestPerturbationEval::test_pearson_r_topk_de",
223
+ "tests/test_sparse_planner.py::TestPopulationEncoder::test_gradient_flows",
224
+ "tests/test_sparse_planner.py::TestPopulationEncoder::test_mask_accepted",
225
+ "tests/test_sparse_planner.py::TestPopulationEncoder::test_output_shape_no_var",
226
+ "tests/test_sparse_planner.py::TestPopulationEncoder::test_output_shape_with_var",
227
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_end_to_end_gradient",
228
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_forward_keys",
229
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_no_nan",
230
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_predict_targets_shape",
231
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_shapes",
232
+ "tests/test_sparse_planner.py::TestPopulationGIDModel::test_teacher_forcing",
233
+ "tests/test_sparse_planner.py::TestSparsePlanner::test_score_shape",
234
+ "tests/test_sparse_planner.py::TestSparsePlanner::test_soft_mask_range",
235
+ "tests/test_sparse_planner.py::TestSparsePlanner::test_ste_mask_is_binary",
236
+ "tests/test_sparse_planner.py::TestSparsePlanner::test_ste_topk_gradient",
237
+ "tests/test_sparse_planner.py::TestSparsePlanner::test_topk_mask_binary",
238
+ "tests/test_sparse_planner.py::TestTargetMetrics::test_compute_all_returns_keys",
239
+ "tests/test_sparse_planner.py::TestTargetMetrics::test_mrr_perfect",
240
+ "tests/test_sparse_planner.py::TestTargetMetrics::test_ndcg_perfect_vs_random",
241
+ "tests/test_sparse_planner.py::TestTargetMetrics::test_recall_at_k_perfect",
242
+ "tests/test_sparse_planner.py::TestTargetMetrics::test_recall_at_k_random",
243
+ "tests/test_train.py::TestTrainer::test_trainer",
244
+ "tests/test_train.py::TestTrainer::test_trainer_args",
245
+ "tests/test_train.py::TestTrainer::test_trainer_unknown_kwargs"
246
+ ]
PDGrapher/.pytest_cache/v/cache/stepwise ADDED
@@ -0,0 +1 @@
 
 
1
+ []
PDGrapher/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Changelog - PDGrapher
2
+
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [UNRELEASED] - 2023-09-08
6
+
7
+ ### Added
8
+ - Initial PDGrapher project structure.
PDGrapher/LICENSE ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Artificial Intelligence for Medicine and Science @ Harvard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
PDGrapher/README.md ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Combinatorial prediction of therapeutic perturbations using causally-inspired neural networks
2
+ [![ProjectPage](https://img.shields.io/badge/Project-PDGrapher-red)](https://zitniklab.hms.harvard.edu/projects/PDGrapher/) [![CodePage](https://img.shields.io/badge/Code-GitHub-orange)](https://github.com/mims-harvard/PDGrapher) [![Paper](https://img.shields.io/badge/Paper-BioRxiv-green)](https://www.biorxiv.org/content/10.1101/2024.01.03.573985v5) [![Paper](https://img.shields.io/badge/Paper-NBME-green)](https://www.nature.com/articles/s41551-025-01481-x) [![Data](https://img.shields.io/badge/Data-Links-purple)](https://github.com/mims-harvard/PDGrapher/tree/main/data) ![License](https://img.shields.io/badge/license-MIT-blue)
3
+
4
+
5
+
6
+ [Guadalupe Gonzalez*](https://www.guadalupegonzalez.io/), [Xiang Lin*](https://xianglin226.github.io/), [Isuru Herath](https://scholar.google.com/citations?user=F-RC5k0AAAAJ&hl=en), [Kirill Veselkov](https://scholar.google.com/citations?user=0n-5UGYAAAAJ&hl=en),
7
+ [Michael Bronstein](https://scholar.google.com/citations?user=UU3N6-UAAAAJ&hl=en), and [Marinka Zitnik](https://dbmi.hms.harvard.edu/people/marinka-zitnik)
8
+
9
+ ![](https://github.com/mims-harvard/PDGrapher/blob/main/figures/figure1.jpg)
10
+ ## Project structure
11
+
12
+ The project consists of next folders:
13
+ - [data](data/) contains all of the data on which our models were built. On how to obtain this data, refer to [Data](#data) section,
14
+ - [docs](docs/) contains documentation, built with 'sphinx',
15
+ - [src/pdgrapher](src/pdgrapher/) contains the source code for PDGrapher,
16
+ - [tests](tests/) contains unit and integration tests.
17
+
18
+ ## Virtual environment
19
+
20
+ ```
21
+ conda env create -f conda-env.yml
22
+ conda activate pdgrapher
23
+ pip install pip==23.2.1
24
+ pip install -r requirements.txt
25
+
26
+ pip install torch==1.10.1+cu111 torchvision==0.11.2+cu111 torchaudio==0.10.1 -f https://download.pytorch.org/whl/cu111/torch_stable.html
27
+ pip install torch-scatter==2.0.9 -f https://data.pyg.org/whl/torch-1.10.1+cu111.html
28
+ pip install torch-sparse==0.6.12 -f https://data.pyg.org/whl/torch-1.10.1+cu111.html
29
+ pip install torch-cluster==1.5.9 -f https://data.pyg.org/whl/torch-1.10.1+cu111.html
30
+ pip install torch-spline-conv==1.2.1 -f https://data.pyg.org/whl/torch-1.10.1+cu111.html
31
+ pip install torch-geometric==2.0.4 -f https://data.pyg.org/whl/torch-1.10.1+cu111.html
32
+ pip install torchmetrics==0.9.3
33
+ pip install lightning==1.9.5
34
+
35
+ ```
36
+
37
+
38
+ ## Data
39
+
40
+ For processed data, download the compressed folders and place them in `data/processed/` with the following commands:
41
+
42
+ ### Download genetic and splits data from Zenodo
43
+ ```bash
44
+ cd data/processed
45
+ # Download splits and genetic data
46
+ wget -O splits.tar.gz "https://zenodo.org/api/records/15375990/files/splits.tar.gz/content"
47
+ wget -O torch_data_genetic.tar.gz "https://zenodo.org/api/records/15375990/files/torch_data_genetic.tar.gz/content"
48
+
49
+ # Extract splits data
50
+ tar -xzvf splits.tar.gz
51
+
52
+ # Create torch_data directory and extract genetic data into it
53
+ mkdir -p torch_data
54
+ cd torch_data
55
+ tar -xzvf ../torch_data_genetic.tar.gz
56
+ cd ..
57
+ ```
58
+
59
+ ### Download chemical data from Zenodo
60
+ ```bash
61
+ # Download chemical data (run from data/processed directory)
62
+ wget -O torch_data_chemical.tar.gz "https://zenodo.org/api/records/15390483/files/torch_data_chemical.tar.gz/content"
63
+
64
+ # Extract chemical torch data into torch_data directory
65
+ cd torch_data
66
+ tar -xzvf ../torch_data_chemical.tar.gz
67
+ cd ..
68
+ ```
69
+
70
+ ### Data Sources
71
+ - **Genetic data and splits**: [https://zenodo.org/records/15375990](https://zenodo.org/records/15375990)
72
+ - **Chemical data**: [https://zenodo.org/records/15390483](https://zenodo.org/records/15390483)
73
+
74
+
75
+ ## Building
76
+
77
+ This project can be build as a Python library by running `pip install -e .` in the root of this repository.
78
+
79
+
80
+ ## Documentation
81
+
82
+ Documentation can be built with the following commands:
83
+
84
+ ### Prerequisites
85
+ First, install the required documentation dependencies:
86
+ ```bash
87
+ pip install myst-parser
88
+ ```
89
+
90
+ ### Build Documentation
91
+ 1. `sphinx-apidoc -fe -o docs/source/ src/pdgrapher/` updates the source files from which the documentation is built
92
+ 2. `cd docs && make html` builds the documentation
93
+
94
+ Then, the documentation can be accessed locally by going to `docs/build/html/index.html`
95
+ All of the settings along with links to instructions can be found and modified in [docs/source/conf.py](docs/source/conf.py).
96
+
97
+ ## Notebooks
98
+ | Tutorials | Links |
99
+ |----------------|---------------------------------|
100
+ | Train PDGrapher on chemical dataset | [notebook](./notebooks/train_chemical.ipynb) |
101
+ | Train PDGrapher on genetic dataset | [notebook](./notebooks/train_genetic.ipynb) |
102
+ | Test PDGrapher on chemical/genetic dataset | [notebook](./notebooks/test_PDG.ipynb) |
103
+
104
+ ## Additional Resources
105
+ * [Paper](https://www.nature.com/articles/s41551-025-01481-x)
106
+ * [HMS News & Research](https://hms.harvard.edu/news/new-ai-tool-pinpoints-genes-drug-combos-restore-health-diseased-cells)
107
+
108
+ @article{gonzalez2025combinatorial,
109
+ title={Combinatorial Prediction of Therapeutic Perturbations Using Causally-Inspired Neural Networks},
110
+ author={Gonzalez, Guadalupe and Lin, Xiang and Herath, Isuru and Veselkov, Kirill and Bronstein, Michael and Zitnik, Marinka},
111
+ journal={Nature Biomedical Engineering},
112
+ url={https://www.nature.com/articles/s41551-025-01481-x},
113
+ year={2025}
114
+ }
115
+
116
+ ## License
117
+ The code in this package is licensed under the MIT License.
118
+
119
+ ## Questions
120
+ Please leave a Github issue or contact [Guadalupe Gonzalez](mailto:ggonzalezp16@gmail.com), [Xiang Lin](mailto:xianglin226@gmail.com), or [Marinka Zitnik](mailto:marinka@zitnik.si)
121
+
PDGrapher/TODO.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # PDGrapher: TODO
2
+
3
+ This file summarizes things that still need to be done and some observations.
4
+
5
+ ## Bugs:
6
+ - There is some CUDA memory leak, but it is only present when we train a lot of models in one go, as in train them with one `python ...` call. An example is [examples/hyperparameter_tuning.py](examples/hyperparameter_tuning.py) script, which crashed due to OOM error in CUDA after training >130 models for 1 epoch. I suspect it is related to lightning.Fabric, which handles moving tensort to and from GPU.
7
+
8
+ ## TODO:
9
+ - [data](data/) folder has no data currently, and the folder structure with 'raw' folders is not consistent with code in scripts folders. Maybe we can rename them to '2022-03-PPI', '2022-02-LINCS_Level3' and so on. There are two such PPI folders, so we need to be careful there.
10
+ - [main README.md](README.md) needs some updating, like add authors, project description.
PDGrapher/conda-env.yml ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: pdgrapher
2
+ channels:
3
+ - conda-forge
4
+ - conda-canary
5
+ - defaults
6
+ dependencies:
7
+ - _libgcc_mutex
8
+ - _openmp_mutex
9
+ - blas
10
+ - boost
11
+ - boost-cpp
12
+ - bzip2
13
+ - ca-certificates
14
+ - cairo
15
+ - certifi
16
+ - cycler
17
+ - fftw
18
+ - fontconfig
19
+ - freetype
20
+ - glib
21
+ - icu
22
+ #- intel-openmp
23
+ - jpeg
24
+ - ld_impl_linux-64
25
+ - libffi
26
+ - libgcc-ng
27
+ - libgfortran-ng
28
+ - libgfortran5
29
+ - libgomp
30
+ - libiconv
31
+ - libopenblas
32
+ - libpng
33
+ - libstdcxx-ng
34
+ - libtiff
35
+ - libuuid
36
+ - libxcb
37
+ - libxml2
38
+ - lz4-c
39
+ - mkl
40
+ - mkl-service
41
+ - mkl_fft
42
+ - mkl_random
43
+ - ncurses
44
+ #- numpy-base
45
+ - olefile
46
+ - openssl
47
+ - pcre
48
+ - pixman
49
+ - pycairo
50
+ - python=3.8 # Kept the Python version to match your requirement
51
+ - python-dateutil
52
+ - python_abi
53
+ - pytz
54
+ - rdkit
55
+ - readline
56
+ - reportlab
57
+ - six
58
+ - sqlite
59
+ - tk
60
+ - tornado
61
+ - xz
62
+ - zlib
63
+ - zstd
PDGrapher/configs/causal_flow_drug.yaml ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ seed: 42
2
+
3
+ # ──────────────────────────────────────────────
4
+ # Dataset configuration
5
+ # ──────────────────────────────────────────────
6
+ dataset:
7
+ # CRISPRi data (Norman2019)
8
+ type: scperturb
9
+ h5ad_path: /data/boom/Protein/regulatory_field/data/raw/scPerturb/rna_protein/NormanWeissman2019_filtered.h5ad
10
+ n_hvg: 2000
11
+ min_cells_per_cond: 30
12
+ max_source_cells: 64
13
+ max_target_cells: 64
14
+ control_label: control
15
+ use_single_pert_only: false
16
+ include_combos_in_train: true
17
+ force_include_pert_genes: true
18
+ target_sum: 10000.0
19
+
20
+ # Drug data (SciPlex3) — joint training
21
+ sciplex:
22
+ h5ad_path: /data/boom/Protein/regulatory_field/data/raw/scPerturb/rna_protein/SrivatsanTrapnell2020_sciplex3.h5ad
23
+ preprocessed_path: /data/boom/ICLR/data/processed/sciplex3_k562_24h.pt
24
+ enabled: true
25
+ min_cells_per_cond: 30
26
+ max_source_cells: 64
27
+ max_target_cells: 64
28
+ cell_lines: ["K562"]
29
+ doses: [10.0, 100.0, 1000.0, 10000.0]
30
+ times: [24.0]
31
+ drug_emb_dim: 128
32
+ drug_smiles_csv: data/chembl_smiles.csv
33
+
34
+ # ──────────────────────────────────────────────
35
+ # Model configuration
36
+ # ──────────────────────────────────────────────
37
+ model:
38
+ num_genes: 2000
39
+ # Encoder
40
+ encoder_hidden: 512
41
+ encoder_output: 256
42
+ # Gap
43
+ gap_hidden: 256
44
+ gap_output: 256
45
+ # Causal planner
46
+ causal_gene_emb_dim: 128
47
+ causal_n_heads: 4
48
+ causal_n_layers: 2
49
+ planner_hidden: 512
50
+ planner_n_layers: 2
51
+ planner_topk: 1
52
+ # Flow matching
53
+ flow_latent_dim: 256
54
+ flow_hidden_dim: 512
55
+ flow_n_layers: 3
56
+ flow_time_embed_dim: 128
57
+ flow_pert_emb_dim: 256
58
+ n_layers: 2
59
+ # Drug side
60
+ drug_emb_dim: 128
61
+ use_drug_encoder: true
62
+ use_drug_gene_bridge: true
63
+ # Other
64
+ use_cooccurrence: true
65
+ use_latent: false
66
+ lambda_flow: 1.0
67
+ lambda_cycle: 0.5
68
+ lambda_causal: 1.0
69
+ lambda_sparse: 0.01
70
+ lambda_recon: 1.0
71
+ n_neg_samples: 128
72
+ sparse_variance_weight: 0.1
73
+ use_causal_infonce: true
74
+ infonce_neg_samples: 64
75
+ infonce_temperature: 0.1
76
+ # Drug losses
77
+ lambda_drug_target: 5.0
78
+ lambda_drug_contrastive: 1.0
79
+ lambda_drug_dose: 0.5
80
+
81
+ # ──────────────────────────────────────────────
82
+ # Loss configuration
83
+ # ──────────────────────────────────────────────
84
+ loss:
85
+ mmd_weight: 1.0
86
+ mean_weight: 1.0
87
+ var_weight: 0.5
88
+ de_weight: 0.1
89
+ de_topk: 50
90
+
91
+ # ──────────────────────────────────────────────
92
+ # Training configuration
93
+ # ──────────────────────────────────────────────
94
+ train:
95
+ batch_size: 8
96
+ epochs: 200
97
+ lr: 5.0e-5
98
+ weight_decay: 0.0001
99
+ lr_min: 0.000001
100
+ val_split: 0.15
101
+ val_split_type: gene_disjoint
102
+ early_stopping_patience: 50
103
+ device: cuda
104
+ save_every: 10
105
+ # Drug training schedule
106
+ drug_start_epoch: 50 # start drug loss after N epochs of CRISPRi pretraining
107
+ drug_warmup_epochs: 20 # linearly ramp up drug loss weights
108
+ # Mixed training
109
+ crispr_weight: 0.7 # weight for CRISPRi batch in mixed training
110
+ drug_weight: 0.3 # weight for drug batch in mixed training
111
+
112
+ # ──────────────────────────────────────────────
113
+ # Output configuration
114
+ # ──────────────────────────────────────────────
115
+ output:
116
+ dir: outputs/causal_flow_drug
117
+ checkpoint: outputs/causal_flow_drug/checkpoint.pt
118
+ metrics_csv: outputs/causal_flow_drug/metrics.csv
119
+ best_checkpoint: outputs/causal_flow_drug/best_checkpoint.pt
PDGrapher/configs/drug_rank_phase1.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ seed: 42
2
+ data:
3
+ sciplex3_h5ad: /data/boom/ICLR/data/raw/sciplex3.h5ad
4
+ annotation_dir: /data/boom/ICLR/data/annotation
5
+ splits_dir: /data/boom/ICLR/data/splits
6
+ split: drug_disjoint
7
+ max_source_cells: 64
8
+ max_target_cells: 64
9
+ batch_size: 32
10
+
11
+ model:
12
+ num_genes: 2000
13
+ encoder_hidden: 256
14
+ encoder_output: 128
15
+ gap_hidden: 256
16
+ gap_output: 256
17
+ gap_proj_dim: 128
18
+ num_cell_lines: 0 # disabled: was never trained (training omits cell_line_ids); removes dead footgun
19
+ drug_emb_dim: 128
20
+ drug_encoder: morgan
21
+ bridge_hidden_dim: 256
22
+ bridge_proj_dim: 128
23
+ bridge_protein_emb_dim: 64
24
+
25
+ phase1:
26
+ epochs: 40
27
+ lr: 1.0e-3
28
+ weight_decay: 1.0e-4
29
+ bce_pos_weight: 20.0
30
+ lambda_recon: 0.1
31
+ held_out_annotation_frac: 0.15
32
+ early_stop_auroc: 0.65
33
+ early_stop_patience: 5
34
+ device: cuda
35
+ checkpoint_dir: /data/boom/ICLR/PDGrapher/outputs/drug_rank
36
+ checkpoint_every: 5
PDGrapher/configs/drug_rank_phase2.yaml ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ seed: 42
2
+ data:
3
+ sciplex3_h5ad: /data/boom/ICLR/data/raw/sciplex3.h5ad
4
+ annotation_dir: /data/boom/ICLR/data/annotation
5
+ splits_dir: /data/boom/ICLR/data/splits
6
+ split: drug_disjoint
7
+ max_source_cells: 64
8
+ max_target_cells: 64
9
+ batch_size: 32
10
+
11
+ model:
12
+ num_genes: 2000
13
+ encoder_hidden: 256
14
+ encoder_output: 128
15
+ gap_hidden: 256
16
+ gap_output: 256
17
+ gap_proj_dim: 128
18
+ num_cell_lines: 0 # disabled: was never trained (training omits cell_line_ids); removes dead footgun
19
+ drug_emb_dim: 128
20
+ drug_encoder: morgan
21
+ bridge_hidden_dim: 256
22
+ bridge_proj_dim: 128
23
+ bridge_protein_emb_dim: 64
24
+
25
+ phase1:
26
+ epochs: 40
27
+ lr: 1.0e-3
28
+ weight_decay: 1.0e-4
29
+ bce_pos_weight: 20.0
30
+ lambda_recon: 0.1
31
+ held_out_annotation_frac: 0.15
32
+ early_stop_auroc: 0.65
33
+ early_stop_patience: 5
34
+ device: cuda
35
+ checkpoint_dir: /data/boom/ICLR/PDGrapher/outputs/drug_rank
36
+ checkpoint_every: 5
37
+
38
+ phase2:
39
+ epochs: 200
40
+ lr: 3.0e-4
41
+ weight_decay: 1.0e-4
42
+ temp_start: 0.20
43
+ temp_end: 0.10
44
+ lambda_start: 50.0
45
+ lambda_end: 5.0
46
+ gallery_update_every: 15
47
+ # Full-library gallery negatives: empirically HURT (harder objective under-trains
48
+ # given BCE-dominated lambda schedule). Keep in-batch InfoNCE + same-drug/MOA
49
+ # masking (which fixes the false-negative bug) by leaving this false.
50
+ use_gallery_negatives: false
51
+ device: cuda
52
+ checkpoint_dir: /data/boom/ICLR/PDGrapher/outputs/drug_rank
53
+ val_every: 10
PDGrapher/configs/drug_repurposing.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GIDFlow Drug Repurposing Configuration
2
+ # Reference: configs/drug_repurposing.yaml
3
+
4
+ predictor:
5
+ device: auto # 'cuda', 'cpu', or 'auto'
6
+ n_bootstrap: 10 # Bootstrap samples for confidence intervals
7
+ top_k: 50 # Number of top drugs to return
8
+ seed: 42 # Random seed
9
+
10
+ # Similarity scoring weights
11
+ similarity_weights:
12
+ pearson_r: 0.35
13
+ cosine_sim: 0.15
14
+ de_overlap: 0.20
15
+ de_precision: 0.10
16
+ lfc_spearman: 0.15
17
+ de_direction_agreement: 0.05
18
+
19
+ drug_library:
20
+ name: norman2019
21
+ # Built-in libraries: "norman2019", "replogle"
22
+ # Or provide path to h5ad file:
23
+ # h5ad_path: /path/to/your/data.h5ad
24
+ h5ad_path: /data/boom/Protein/regulatory_field/data/raw/scPerturb/rna_protein/NormanWeissman2019_filtered.h5ad
25
+ cell_type: null # Filter to specific cell type (e.g., "K562")
26
+ use_single_pert_only: false # Include combinatorial perturbations
27
+ min_cells_per_cond: 20 # Minimum cells per condition
28
+
29
+ similarity:
30
+ de_topk: 50 # Top-k DE genes for overlap metrics
31
+ lfc_epsilon: 1e-6 # Epsilon for log fold change computation
32
+
33
+ pathway:
34
+ enabled: true
35
+ gene_sets: "MSigDB_Hallmark_2020"
36
+ organism: "human"
37
+ min_size: 10
38
+ max_size: 500
39
+ cutoff: 0.05
40
+
41
+ output:
42
+ dir: outputs/drug_repurposing
43
+ rankings_csv: outputs/drug_repurposing/drug_rankings.csv
44
+ populations_dir: outputs/drug_repurposing/predicted_populations
45
+ pathways_dir: outputs/drug_repurposing/pathways
PDGrapher/data/README.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+
5
+ # Downloading and expanding processed datasets:
6
+
7
+ ## Download genetic and splits data from Zenodo
8
+ ```bash
9
+ mkdir -p processed
10
+ cd processed
11
+ # Download splits and genetic data
12
+ wget -O splits.tar.gz "https://zenodo.org/api/records/15375990/files/splits.tar.gz/content"
13
+ wget -O torch_data_genetic.tar.gz "https://zenodo.org/api/records/15375990/files/torch_data_genetic.tar.gz/content"
14
+
15
+ # Extract splits data
16
+ tar -xzvf splits.tar.gz
17
+
18
+ # Create torch_data directory and extract genetic data into it
19
+ mkdir -p torch_data
20
+ cd torch_data
21
+ tar -xzvf ../torch_data_genetic.tar.gz
22
+ cd ..
23
+ ```
24
+
25
+ ## Download chemical data from Zenodo
26
+ ```bash
27
+ # Download chemical data (run from data/processed directory)
28
+ wget -O torch_data_chemical.tar.gz "https://zenodo.org/api/records/15390483/files/torch_data_chemical.tar.gz/content"
29
+
30
+ # Extract chemical torch data into torch_data directory
31
+ cd torch_data
32
+ tar -xzvf ../torch_data_chemical.tar.gz
33
+ cd ..
34
+ ```
35
+
36
+ ## Data Sources
37
+ - **Genetic data and splits**: [https://zenodo.org/records/15375990](https://zenodo.org/records/15375990)
38
+ - **Chemical data**: [https://zenodo.org/records/15390483](https://zenodo.org/records/15390483)
PDGrapher/data/check_data_and_splits.ipynb ADDED
@@ -0,0 +1,374 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "import torch\n",
10
+ "import pandas as pd"
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "code",
15
+ "execution_count": 26,
16
+ "metadata": {},
17
+ "outputs": [
18
+ {
19
+ "name": "stdout",
20
+ "output_type": "stream",
21
+ "text": [
22
+ "Cell line: A375\n",
23
+ " Split: 1\n",
24
+ " Passed test\n",
25
+ " Split: 2\n",
26
+ " Passed test\n",
27
+ " Split: 3\n",
28
+ " Passed test\n",
29
+ " Split: 4\n",
30
+ " Passed test\n",
31
+ " Split: 5\n",
32
+ " Passed test\n",
33
+ "Cell line: A549\n",
34
+ " Split: 1\n",
35
+ " Passed test\n",
36
+ " Split: 2\n",
37
+ " Passed test\n",
38
+ " Split: 3\n",
39
+ " Passed test\n",
40
+ " Split: 4\n",
41
+ " Passed test\n",
42
+ " Split: 5\n",
43
+ " Passed test\n",
44
+ "Cell line: BT20\n",
45
+ " Split: 1\n",
46
+ " Passed test\n",
47
+ " Split: 2\n",
48
+ " Passed test\n",
49
+ " Split: 3\n",
50
+ " Passed test\n",
51
+ " Split: 4\n",
52
+ " Passed test\n",
53
+ " Split: 5\n",
54
+ " Passed test\n",
55
+ "Cell line: HA1E\n",
56
+ " Split: 1\n",
57
+ " Passed test\n",
58
+ " Split: 2\n",
59
+ " Passed test\n",
60
+ " Split: 3\n",
61
+ " Passed test\n",
62
+ " Split: 4\n",
63
+ " Passed test\n",
64
+ " Split: 5\n",
65
+ " Passed test\n",
66
+ "Cell line: HELA\n",
67
+ " Split: 1\n",
68
+ " Passed test\n",
69
+ " Split: 2\n",
70
+ " Passed test\n",
71
+ " Split: 3\n",
72
+ " Passed test\n",
73
+ " Split: 4\n",
74
+ " Passed test\n",
75
+ " Split: 5\n",
76
+ " Passed test\n",
77
+ "Cell line: HT29\n",
78
+ " Split: 1\n",
79
+ " Passed test\n",
80
+ " Split: 2\n",
81
+ " Passed test\n",
82
+ " Split: 3\n",
83
+ " Passed test\n",
84
+ " Split: 4\n",
85
+ " Passed test\n",
86
+ " Split: 5\n",
87
+ " Passed test\n",
88
+ "Cell line: MCF7\n",
89
+ " Split: 1\n",
90
+ " Passed test\n",
91
+ " Split: 2\n",
92
+ " Passed test\n",
93
+ " Split: 3\n",
94
+ " Passed test\n",
95
+ " Split: 4\n",
96
+ " Passed test\n",
97
+ " Split: 5\n",
98
+ " Passed test\n",
99
+ "Cell line: MDAMB231\n",
100
+ " Split: 1\n",
101
+ " Passed test\n",
102
+ " Split: 2\n",
103
+ " Passed test\n",
104
+ " Split: 3\n",
105
+ " Passed test\n",
106
+ " Split: 4\n",
107
+ " Passed test\n",
108
+ " Split: 5\n",
109
+ " Passed test\n",
110
+ "Cell line: PC3\n",
111
+ " Split: 1\n",
112
+ " Passed test\n",
113
+ " Split: 2\n",
114
+ " Passed test\n",
115
+ " Split: 3\n",
116
+ " Passed test\n",
117
+ " Split: 4\n",
118
+ " Passed test\n",
119
+ " Split: 5\n",
120
+ " Passed test\n",
121
+ "Cell line: VCAP\n",
122
+ " Split: 1\n",
123
+ " Passed test\n",
124
+ " Split: 2\n",
125
+ " Passed test\n",
126
+ " Split: 3\n",
127
+ " Passed test\n",
128
+ " Split: 4\n",
129
+ " Passed test\n",
130
+ " Split: 5\n",
131
+ " Passed test\n"
132
+ ]
133
+ }
134
+ ],
135
+ "source": [
136
+ "##Chemical perturbations\n",
137
+ "cell_line = ['A375', 'A549', 'BT20', 'HA1E', 'HELA', 'HT29', 'MCF7', 'MDAMB231', 'PC3', 'VCAP']\n",
138
+ "\n",
139
+ "for cl in cell_line:\n",
140
+ " split = torch.load('processed/splits/chemical/{}/random/5fold/splits.pt'.format(cl))\n",
141
+ "\n",
142
+ " print('Cell line: {}'.format(cl))\n",
143
+ "\n",
144
+ " #Loads data\n",
145
+ " b_data = torch.load('processed/torch_data/chemical/real_lognorm/data_backward_{}.pt'.format(cl))\n",
146
+ " f_data = torch.load('processed/torch_data/chemical/real_lognorm/data_forward_{}.pt'.format(cl))\n",
147
+ "\n",
148
+ " for i in range(1, 6):\n",
149
+ " print(' Split: {}'.format(i))\n",
150
+ "\n",
151
+ " error = False\n",
152
+ " #Backward data\n",
153
+ " d = b_data\n",
154
+ " if len(d) != len(split[i]['train_index_backward']) + len(split[i]['val_index_backward']) + len(split[i]['test_index_backward']):\n",
155
+ " print('length is not the same for splits: {}'.format(cl))\n",
156
+ " error = True\n",
157
+ " \n",
158
+ " #Forward data\n",
159
+ " d = f_data\n",
160
+ " if len(d) == 0:\n",
161
+ " if split[i]['train_index_forward'] is not None or split[i]['val_index_forward'] is not None or split[i]['test_index_forward'] is not None:\n",
162
+ " print('split is not None when it should be (no forward data)')\n",
163
+ " error = True\n",
164
+ " else:\n",
165
+ " if len(d) != len(split[i]['train_index_forward']) + len(split[i]['val_index_forward']) + len(split[i]['test_index_forward']):\n",
166
+ " print('length is not the same for splits: {}'.format(cl))\n",
167
+ " error = True\n",
168
+ " \n",
169
+ " if not error:\n",
170
+ " print(' Passed test')\n",
171
+ " else:\n",
172
+ " print(' Failed test')\n",
173
+ " \n",
174
+ "\n",
175
+ "\n",
176
+ "\n"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": 27,
182
+ "metadata": {},
183
+ "outputs": [
184
+ {
185
+ "name": "stdout",
186
+ "output_type": "stream",
187
+ "text": [
188
+ "Cell line: A375\n",
189
+ " Split: 1\n",
190
+ " Passed test\n",
191
+ " Split: 2\n",
192
+ " Passed test\n",
193
+ " Split: 3\n",
194
+ " Passed test\n",
195
+ " Split: 4\n",
196
+ " Passed test\n",
197
+ " Split: 5\n",
198
+ " Passed test\n",
199
+ "Cell line: A549\n",
200
+ " Split: 1\n",
201
+ " Passed test\n",
202
+ " Split: 2\n",
203
+ " Passed test\n",
204
+ " Split: 3\n",
205
+ " Passed test\n",
206
+ " Split: 4\n",
207
+ " Passed test\n",
208
+ " Split: 5\n",
209
+ " Passed test\n",
210
+ "Cell line: AGS\n",
211
+ " Split: 1\n",
212
+ " Passed test\n",
213
+ " Split: 2\n",
214
+ " Passed test\n",
215
+ " Split: 3\n",
216
+ " Passed test\n",
217
+ " Split: 4\n",
218
+ " Passed test\n",
219
+ " Split: 5\n",
220
+ " Passed test\n",
221
+ "Cell line: BICR6\n",
222
+ " Split: 1\n",
223
+ " Passed test\n",
224
+ " Split: 2\n",
225
+ " Passed test\n",
226
+ " Split: 3\n",
227
+ " Passed test\n",
228
+ " Split: 4\n",
229
+ " Passed test\n",
230
+ " Split: 5\n",
231
+ " Passed test\n",
232
+ "Cell line: ES2\n",
233
+ " Split: 1\n",
234
+ " Passed test\n",
235
+ " Split: 2\n",
236
+ " Passed test\n",
237
+ " Split: 3\n",
238
+ " Passed test\n",
239
+ " Split: 4\n",
240
+ " Passed test\n",
241
+ " Split: 5\n",
242
+ " Passed test\n",
243
+ "Cell line: HT29\n",
244
+ " Split: 1\n",
245
+ " Passed test\n",
246
+ " Split: 2\n",
247
+ " Passed test\n",
248
+ " Split: 3\n",
249
+ " Passed test\n",
250
+ " Split: 4\n",
251
+ " Passed test\n",
252
+ " Split: 5\n",
253
+ " Passed test\n",
254
+ "Cell line: MCF7\n",
255
+ " Split: 1\n",
256
+ " Passed test\n",
257
+ " Split: 2\n",
258
+ " Passed test\n",
259
+ " Split: 3\n",
260
+ " Passed test\n",
261
+ " Split: 4\n",
262
+ " Passed test\n",
263
+ " Split: 5\n",
264
+ " Passed test\n",
265
+ "Cell line: PC3\n",
266
+ " Split: 1\n",
267
+ " Passed test\n",
268
+ " Split: 2\n",
269
+ " Passed test\n",
270
+ " Split: 3\n",
271
+ " Passed test\n",
272
+ " Split: 4\n",
273
+ " Passed test\n",
274
+ " Split: 5\n",
275
+ " Passed test\n",
276
+ "Cell line: U251MG\n",
277
+ " Split: 1\n",
278
+ " Passed test\n",
279
+ " Split: 2\n",
280
+ " Passed test\n",
281
+ " Split: 3\n",
282
+ " Passed test\n",
283
+ " Split: 4\n",
284
+ " Passed test\n",
285
+ " Split: 5\n",
286
+ " Passed test\n",
287
+ "Cell line: YAPC\n",
288
+ " Split: 1\n",
289
+ " Passed test\n",
290
+ " Split: 2\n",
291
+ " Passed test\n",
292
+ " Split: 3\n",
293
+ " Passed test\n",
294
+ " Split: 4\n",
295
+ " Passed test\n",
296
+ " Split: 5\n",
297
+ " Passed test\n"
298
+ ]
299
+ }
300
+ ],
301
+ "source": [
302
+ "##Genetic perturbations\n",
303
+ "cell_line = ['A375', 'A549', 'AGS', 'BICR6', 'ES2', 'HT29', 'MCF7', 'PC3', 'U251MG', 'YAPC']\n",
304
+ "\n",
305
+ "for cl in cell_line:\n",
306
+ " split = torch.load('processed/splits/genetic/{}/random/5fold/splits.pt'.format(cl))\n",
307
+ "\n",
308
+ " print('Cell line: {}'.format(cl))\n",
309
+ "\n",
310
+ " #Loads data\n",
311
+ " b_data = torch.load('processed/torch_data/real_lognorm/data_backward_{}.pt'.format(cl))\n",
312
+ " f_data = torch.load('processed/torch_data/real_lognorm/data_forward_{}.pt'.format(cl))\n",
313
+ "\n",
314
+ " for i in range(1, 6):\n",
315
+ " print(' Split: {}'.format(i))\n",
316
+ "\n",
317
+ " error = False\n",
318
+ " #Backward data\n",
319
+ " d = b_data\n",
320
+ " if len(d) != len(split[i]['train_index_backward']) + len(split[i]['val_index_backward']) + len(split[i]['test_index_backward']):\n",
321
+ " print('length is not the same for splits: {}'.format(cl))\n",
322
+ " error = True\n",
323
+ " \n",
324
+ " #Forward data\n",
325
+ " d = f_data\n",
326
+ " if len(d) == 0:\n",
327
+ " if split[i]['train_index_forward'] is not None or split[i]['val_index_forward'] is not None or split[i]['test_index_forward'] is not None:\n",
328
+ " print('split is not None when it should be (no forward data)')\n",
329
+ " error = True\n",
330
+ " else:\n",
331
+ " if len(d) != len(split[i]['train_index_forward']) + len(split[i]['val_index_forward']) + len(split[i]['test_index_forward']):\n",
332
+ " print('length is not the same for splits: {}'.format(cl))\n",
333
+ " error = True\n",
334
+ " \n",
335
+ " if not error:\n",
336
+ " print(' Passed test')\n",
337
+ " else:\n",
338
+ " print(' Failed test')\n",
339
+ " \n",
340
+ "\n",
341
+ "\n",
342
+ "\n"
343
+ ]
344
+ },
345
+ {
346
+ "cell_type": "code",
347
+ "execution_count": null,
348
+ "metadata": {},
349
+ "outputs": [],
350
+ "source": []
351
+ }
352
+ ],
353
+ "metadata": {
354
+ "kernelspec": {
355
+ "display_name": "myenv",
356
+ "language": "python",
357
+ "name": "myenv"
358
+ },
359
+ "language_info": {
360
+ "codemirror_mode": {
361
+ "name": "ipython",
362
+ "version": 3
363
+ },
364
+ "file_extension": ".py",
365
+ "mimetype": "text/x-python",
366
+ "name": "python",
367
+ "nbconvert_exporter": "python",
368
+ "pygments_lexer": "ipython3",
369
+ "version": "3.8.12"
370
+ }
371
+ },
372
+ "nbformat": 4,
373
+ "nbformat_minor": 2
374
+ }
PDGrapher/data/chembl_smiles.csv ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ chembl_id,smiles
2
+ CHEMBL1078178,N#CCNC(=O)c1ccc(-c2ccnc(Nc3ccc(N4CCOCC4)cc3)n2)cc1
3
+ CHEMBL109,CCCC(CCC)C(=O)O
4
+ CHEMBL1090479,CCn1cc(-c2ccnc3[nH]c(-c4cccc(CN(C)C)c4)cc23)c(-c2ccc(NC(=O)N(C)C)cc2)n1
5
+ CHEMBL1090771,NC(=O)[C@@H](CCC(F)(F)F)N(Cc1ccc(-c2ncon2)cc1F)S(=O)(=O)c1ccc(Cl)cc1
6
+ CHEMBL109480,C=CCNC1=C2C[C@@H](C)C[C@H](OC)[C@H](O)[C@@H](C)/C=C(\C)[C@H](OC(N)=O)[C@@H](OC)/C=C\C=C(/C)C(=O)NC(=CC1=O)C2=O
7
+ CHEMBL1098319,O=S(=O)(O)CCS
8
+ CHEMBL1156461,
9
+ CHEMBL116438,
10
+ CHEMBL1170047,NC(=O)c1ccc(I)c([N+](=O)[O-])c1
11
+ CHEMBL1173055,CNCc1ccc(-c2[nH]c3cc(F)cc4c3c2CCNC4=O)cc1
12
+ CHEMBL118,Cc1ccc(-c2cc(C(F)(F)F)nn2-c2ccc(S(N)(=O)=O)cc2)cc1
13
+ CHEMBL1200485,CNC(=O)c1cc(Oc2ccc(NC(=O)Nc3ccc(Cl)c(C(F)(F)F)c3)cc2)ccn1.Cc1ccc(S(=O)(=O)O)cc1
14
+ CHEMBL1200675,CN(C)CCOc1ccc(/C(=C(/CCCl)c2ccccc2)c2ccccc2)cc1.O=C(O)CC(O)(CC(=O)O)C(=O)O
15
+ CHEMBL1200751,O.S=c1[nH]cnc2nc[nH]c12
16
+ CHEMBL1201129,Nc1ncn([C@H]2C[C@H](O)[C@@H](CO)O2)c(=O)n1
17
+ CHEMBL1201148,C[C@H]1C[C@H]2[C@@H]3CCC4=CC(=O)C=C[C@]4(C)[C@H]3C(=O)C[C@]2(C)[C@@]1(O)C(=O)CO
18
+ CHEMBL1201182,CO[C@H]1C[C@@H]2CC[C@@H](C)[C@@](O)(O2)C(=O)C(=O)N2CCCC[C@H]2C(=O)O[C@H]([C@H](C)C[C@@H]2CC[C@@H](OC(=O)C(C)(CO)CO)[C@H](OC)C2)CC(=O)[C@H](C)/C=C(\C)[C@@H](O)[C@@H](OC)C(=O)[C@H](C)C[C@H](C)/C=C/C=C/C=C/1C
19
+ CHEMBL1201187,Cc1nnc(C(C)C)n1[C@@H]1C[C@H]2CC[C@@H](C1)N2CC[C@H](NC(=O)C1CCC(F)(F)CC1)c1ccccc1
20
+ CHEMBL1201616,
21
+ CHEMBL1213492,CCN(CC)Cc1ccc2cc(COC(=O)Nc3ccc(C(=O)NO)cc3)ccc2c1
22
+ CHEMBL1218,CCC(=O)NCC[C@@H]1CCc2ccc3c(c21)CCO3
23
+ CHEMBL1231124,Cc1cc(Nc2nc(N[C@@H](C)c3ncc(F)cn3)ncc2Cl)[nH]n1
24
+ CHEMBL1231461,Br
25
+ CHEMBL1241855,COc1cc(OC)c(/C=C/S(=O)(=O)Cc2ccc(OC)c(NCC(=O)O)c2)c(OC)c1
26
+ CHEMBL1257042,N#C/C(=C/c1ccc(O)c(O)c1)C(=O)NCc1ccccc1
27
+ CHEMBL1287853,Cc1cnc(Nc2ccc(OCCN3CCCC3)cc2)nc1Nc1cccc(S(=O)(=O)NC(C)(C)C)c1
28
+ CHEMBL1358,C[C@]12CC[C@@H]3c4ccc(O)cc4C[C@@H](CCCCCCCCC[S+]([O-])CCCC(F)(F)C(F)(F)F)[C@H]3[C@@H]1CC[C@@H]2O
29
+ CHEMBL1421,Cc1nc(Nc2ncc(C(=O)Nc3c(C)cccc3Cl)s2)cc(N2CCN(CCO)CC2)n1
30
+ CHEMBL1425,Sc1ncnc2nc[nH]c12
31
+ CHEMBL1455,CN(C)c1nc(N(C)C)nc(N(C)C)n1
32
+ CHEMBL14762,CC[C@H](CO)Nc1nc(NCc2ccccc2)c2ncn(C(C)C)c2n1
33
+ CHEMBL1489,Nc1ncn([C@@H]2O[C@H](CO)[C@@H](O)[C@H]2O)c(=O)n1
34
+ CHEMBL1504,CC1(C)O[C@@H]2C[C@H]3[C@@H]4CCC5=CC(=O)C=C[C@]5(C)[C@@]4(F)[C@@H](O)C[C@]3(C)[C@]2(C(=O)CO)O1
35
+ CHEMBL1551724,NC(=O)c1ncn([C@@H]2O[C@H](CO)[C@@H](O)[C@H]2O)c1N
36
+ CHEMBL1556,O=c1[nH]cnc2c1ncn2[C@@H]1O[C@H](CO)[C@@H](O)[C@H]1O
37
+ CHEMBL1645462,Cc1c(NC(=O)OC[C@@H]2COCCN2)cn2ncnc(Nc3ccc4c(cnn4Cc4cccc(F)c4)c3)c12
38
+ CHEMBL165,Oc1ccc(/C=C/c2cc(O)cc(O)c2)cc1
39
+ CHEMBL1651524,O=C(Nc1cccnc1)N1CCC(Cc2cccc(Oc3ccc(C(F)(F)F)cn3)c2)CC1
40
+ CHEMBL1651906,CN(N=O)C(=O)N[C@H]1C(O)O[C@H](CO)[C@@H](O)[C@@H]1O
41
+ CHEMBL1746,O=C([O-])CCCc1ccccc1.[Na+]
42
+ CHEMBL1773,CCCCCOC(=O)Nc1nc(=O)n([C@@H]2O[C@H](C)[C@@H](O)[C@H]2O)cc1F
43
+ CHEMBL1789941,N#CC[C@H](C1CCCC1)n1cc(-c2ncnc3[nH]ccc23)cn1
44
+ CHEMBL185,O=c1[nH]cc(F)c(=O)[nH]1
45
+ CHEMBL1851943,CCCCc1nc2cc(/C=C/C(=O)NO)ccc2n1CCN(CC)CC
46
+ CHEMBL189584,CCN(CC)CCCCNc1ncc2cc(-c3cc(OC)cc(OC)c3)c(NC(=O)NC(C)(C)C)nc2n1
47
+ CHEMBL1908397,O=C(c1ccc(/C=C/c2n[nH]c3ccccc23)cc1)N1CCNCC1
48
+ CHEMBL191003,Nc1nc(Nc2ccc(S(N)(=O)=O)cc2)nn1C(=O)c1c(F)cccc1F
49
+ CHEMBL191482,CC(C)[C@H](C(=O)Nc1ccc(C(=O)NO)cc1)c1ccccc1
50
+ CHEMBL1923234,C[C@H](NC(=O)/C(C#N)=C/c1cccc(Br)n1)c1ccccc1
51
+ CHEMBL1946170,CNC(=O)c1cc(Oc2ccc(NC(=O)Nc3ccc(Cl)c(C(F)(F)F)c3)c(F)c2)ccn1
52
+ CHEMBL1952329,CN1CCC(CNc2ccc3ncc(-c4cccc(OC(F)(F)F)c4)n3n2)CC1
53
+ CHEMBL202721,COc1cc2c(Nc3ccc(NC(=O)c4ccccc4)cc3)ncnc2cc1OCCCN1CCOCC1
54
+ CHEMBL2062804,CN1CCN(c2cccc(Nc3nc4c(-c5ccc(S(C)(=O)=O)cc5)cccn4n3)c2)CC1
55
+ CHEMBL2103863,CN(C)Cc1c(C(=O)NCCOc2ccc(C(=O)NO)cc2)oc2ccccc12
56
+ CHEMBL2103875,CC(=O)Nc1cccc(-n2c(=O)n(C3CC3)c(=O)c3c(Nc4ccc(I)cc4F)n(C)c(=O)c(C)c32)c1
57
+ CHEMBL2105613,CCCC(CCC)C(=O)O.CCCC(CCC)C(=O)[O-].[Na+]
58
+ CHEMBL2105734,COCC[n+]1c2c(n(Cc3cnccn3)c1C)C(=O)c1ccccc1C2=O.[Br-]
59
+ CHEMBL2105759,CCS(=O)(=O)N1CC(CC#N)(n2cc(-c3ncnc4[nH]ccc34)cn2)C1
60
+ CHEMBL2105763,Cn1cc(CNCC2CCN(c3ncc(C(=O)NO)cn3)CC2)c2ccccc21
61
+ CHEMBL2107823,Cc1cc(Nc2cc(CN3CCOCC3)c3nc(C)c(Cc4ccc(Cl)cc4F)n3n2)n[nH]1
62
+ CHEMBL2110734,COCC[n+]1c2c(n(Cc3cnccn3)c1C)C(=O)c1ccccc1C2=O
63
+ CHEMBL2137530,c1ccc2c(CCNc3ccc(Nc4ccncc4)cc3)c[nH]c2c1
64
+ CHEMBL2140408,Cc1csc(-c2nnc(Nc3ccc(Oc4ncccc4-c4ccnc(N)n4)cc3)c3ccccc23)c1
65
+ CHEMBL215152,CCN(CCO)CCCOc1ccc2c(Nc3cc(CC(=O)Nc4cccc(F)c4)[nH]n3)ncnc2c1
66
+ CHEMBL221959,C[C@@H]1CCN(C(=O)CC#N)C[C@@H]1N(C)c1ncnc2[nH]ccc12
67
+ CHEMBL223360,Cc1ccc(F)c(NC(=O)Nc2ccc(-c3cccc4[nH]nc(N)c34)cc2)c1
68
+ CHEMBL225071,Cc1nc(=O)c2cc(CN(C)c3ccc(C(=O)N[C@@H](CCC(=O)O)C(=O)O)s3)ccc2[nH]1
69
+ CHEMBL2338329,Cc1nc(C(=O)NCC(=O)O)c(O)c2ccc(Oc3ccccc3)cc12
70
+ CHEMBL235191,CC(=O)Nc1ccc(C(=O)Nc2ccccc2N)cc1
71
+ CHEMBL2354444,COc1cccc2c1C(=O)c1c(O)c3c(c(O)c1C2=O)C[C@@](O)(C(=O)CO)C[C@@H]3O[C@H]1C[C@H](N)[C@H](O[C@@H]2CCCCO2)[C@H](C)O1
72
+ CHEMBL243712,CCN1CCCC1CNC(=O)c1cc(S(=O)(=O)CC)c(N)cc1OC
73
+ CHEMBL244948,O=c1ccc2ccc(O)c(O)c2o1
74
+ CHEMBL24828,COc1cc2/c(=N/c3ccc(Br)cc3F)nc[nH]c2cc1OCC1CCN(C)CC1
75
+ CHEMBL252164,CCNC(=O)c1noc(-c2cc(C(C)C)c(O)cc2O)c1-c1ccc(CN2CCOCC2)cc1
76
+ CHEMBL255863,Cc1cn(-c2cc(NC(=O)c3ccc(C)c(Nc4nccc(-c5cccnc5)n4)c3)cc(C(F)(F)F)c2)cn1
77
+ CHEMBL257990,N[C@H]1C[C@@H]1c1ccccc1
78
+ CHEMBL259084,O=C(O)c1ccc(Nc2ncc3c(n2)-c2ccc(Cl)cc2C(c2c(F)cccc2F)=NC3)cc1
79
+ CHEMBL261237,N#C/C(=C(/N)Sc1ccc(N)cc1)c1ccccc1C(F)(F)F
80
+ CHEMBL272980,Nc1ccccc1NC(=O)c1ccc(CNc2nccc(-c3cccnc3)n2)cc1
81
+ CHEMBL27759,Nc1ccccc1NC(=O)c1ccc(CNC(=O)OCc2cccnc2)cc1
82
+ CHEMBL288441,COc1cc(Nc2c(C#N)cnc3cc(OCCCN4CCN(C)CC4)c(OC)cc23)c(Cl)cc1Cl
83
+ CHEMBL299613,COc1cc2c(cc1O)CC[C@@H]1[C@@H]2CC[C@]2(C)[C@@H](O)CC[C@@H]12
84
+ CHEMBL30,CN/C(=N\CCSCc1nc[nH]c1C)NC#N
85
+ CHEMBL300138,Cn1cc(C2=C(c3cn(C4CCN(Cc5ccccn5)CC4)c4ccccc34)C(=O)NC2=O)c2ccccc21
86
+ CHEMBL313833,NC1CC1c1ccccc1
87
+ CHEMBL3182444,
88
+ CHEMBL3233481,CN(C)CC(=O)Nc1ccc2[nH]c(=O)c3ccccc3c2c1.Cl
89
+ CHEMBL329993,C/C(=C\c1csc(C)n1)[C@@H]1C[C@@H]2O[C@@H]2CCC[C@H](C)[C@H](O)[C@@H](C)C(=O)C(C)(C)[C@@H](O)CC(=O)O1
90
+ CHEMBL3301607,O=C(Nc1nc2cccc(-c3ccc(CN4CCS(=O)(=O)CC4)cc3)n2n1)C1CC1
91
+ CHEMBL33778,CCCCCCCCCCCCCCCc1cccc(O)c1C(=O)O
92
+ CHEMBL3414621,CCN(c1cc(-c2ccc(CN3CCOCC3)cc2)cc(C(=O)NCc2c(C)cc(C)[nH]c2=O)c1C)C1CCOCC1
93
+ CHEMBL3544932,CCS(=O)(=O)c1cccc(-c2cc(C(=O)NC3CCN(C)CC3)c(C)c3[nH]c4ncc(C)cc4c23)c1
94
+ CHEMBL3544989,
95
+ CHEMBL3545215,CCn1c(C(=O)N(C2CC2)C2CC2)cc2c3c(ncn3C)c(Nc3cc(C)n(C)n3)nc21
96
+ CHEMBL3545320,
97
+ CHEMBL35482,COc1cccc(-c2cc(=O)c3ccccc3o2)c1N
98
+ CHEMBL356066,O=C(/C=C/c1ccc(CN(CCO)CCc2c[nH]c3ccccc23)cc1)NO
99
+ CHEMBL3621988,Nc1cc(F)ccc1NC(=O)c1ccc(CNC(=O)/C=C/c2cccnc2)cc1
100
+ CHEMBL3622533,COc1ccc(-c2nc(N3CCOCC3)c3sc(CN(C)c4ncc(C(=O)NO)cn4)cc3n2)cn1
101
+ CHEMBL363160,CCc1cccc(CC)c1NC(=O)N1Cc2[nH]nc(NC(=O)c3ccc(N4CCN(C)CC4)cc3)c2C1
102
+ CHEMBL372303,CN(C)CC(=O)Nc1ccc2[nH]c(=O)c3ccccc3c2c1
103
+ CHEMBL376408,CN(C)CC[C@H](CSc1ccccc1)Nc1ccc(S(=O)(=O)NC(=O)c2ccc(N3CCN(Cc4ccccc4-c4ccc(Cl)cc4)CC3)cc2)cc1[N+](=O)[O-]
104
+ CHEMBL380797,CC(NC(=O)c1ccccc1/N=C/c1c(O)ccc2ccccc12)c1ccccc1
105
+ CHEMBL38380,O=S(=O)(c1cccc2cnccc12)N1CCCNCC1
106
+ CHEMBL383824,CO[C@H]1/C=C\C=C(/C)C(=O)NC2=CC(=O)C(NCCN(C)C)=C(C[C@@H](C)C[C@H](OC)[C@H](O)[C@@H](C)/C=C(\C)[C@@H]1OC(N)=O)C2=O
107
+ CHEMBL3989843,N[C@@H]1C[C@H]1c1ccccc1.N[C@H]1C[C@@H]1c1ccccc1
108
+ CHEMBL3989914,COCCNCc1ccc(-c2cc3nccc(Oc4ccc(NC(=S)NC(=O)Cc5ccc(F)cc5)cc4F)c3s2)nc1
109
+ CHEMBL3989958,N#Cc1ccnc(N2C(=O)CC[C@H]2C(=O)N(c2cncc(F)c2)[C@H](C(=O)NC2CC(F)(F)C2)c2ccccc2Cl)c1
110
+ CHEMBL4,CC1COc2c(N3CCN(C)CC3)c(F)cc3c(=O)c(C(=O)O)cn1c23
111
+ CHEMBL401930,Cc1cc(N2CCOCC2)cc2[nH]c(-c3c(NC[C@@H](O)c4cccc(Cl)c4)cc[nH]c3=O)nc12
112
+ CHEMBL402548,CO[C@@H](C(=O)N1Cc2[nH]nc(NC(=O)c3ccc(N4CCN(C)CC4)cc3)c2C1)c1ccccc1
113
+ CHEMBL408194,COC1=CC(c2cc3ccccc3[nH]2)=N/C1=C\c1[nH]c(C)cc1C
114
+ CHEMBL408513,O=C(/C=C/c1cccc(S(=O)(=O)Nc2ccccc2)c1)NO
115
+ CHEMBL4116008,CCS(=O)(=O)N1CCN(c2ccc(Nc3ncc(C(N)=O)c(NC4CC4)n3)cc2)CC1
116
+ CHEMBL4205422,O=C(O)CC[C@H]1CC[C@@](c2cc(F)ccc2F)(S(=O)(=O)c2ccc(Cl)cc2)CC1
117
+ CHEMBL428690,CN1CC[C@H](c2c(O)cc(O)c3c(=O)cc(-c4ccccc4Cl)oc23)[C@H](O)C1
118
+ CHEMBL4296717,CN(C)Cc1ccc(S(=O)(=O)n2ccc(/C=C/C(=O)NO)c2)cc1
119
+ CHEMBL4297436,Cc1nc(-c2cccnc2)sc1C(=O)Nc1ccccc1-c1cn2c(CN3CCOCC3)csc2n1
120
+ CHEMBL4303060,CCOC(=O)[C@H](Cc1ccc(F)cc1)NC(=O)[C@@H](N)Cc1ccc(N(CCCl)CCCl)cc1
121
+ CHEMBL440084,NC(=O)c1ccc(-c2nc(-c3ccccn3)c(-c3ccc4c(c3)OCO4)[nH]2)cc1
122
+ CHEMBL443684,CC1(C)CCC(c2ccc(Cl)cc2)=C(CN2CCN(c3ccc(C(=O)NS(=O)(=O)c4ccc(N[C@H](CCN5CCOCC5)CSc5ccccc5)c(S(=O)(=O)C(F)(F)F)c4)cc3)CC2)C1
123
+ CHEMBL455368,C=CC/C=C\C/C=C\CCCCCCCc1cccc(O)c1C(=O)O
124
+ CHEMBL458875,Cc1cn([C@H]2O[C@@H](CO)[C@H](O)[C@H]2F)c(=O)[nH]c1=O
125
+ CHEMBL460499,CCCCCCNC(=O)n1cc(F)c(=O)[nH]c1=O
126
+ CHEMBL4650286,Nc1nn2cc(F)cnc2c1C(=O)Nc1cncc(F)c1N1CCC(C(=O)N2CCN(C3COC3)CC2)CC1
127
+ CHEMBL468,O=C1CCC(N2C(=O)c3ccccc3C2=O)C(=O)N1
128
+ CHEMBL473773,COc1cc2ncnc(Nc3ccc(O)c(Br)c3)c2cc1OC
129
+ CHEMBL477936,Cc1ccc(S(=O)(=O)OCC(=O)Nc2ccc(C(=O)O)c(O)c2)cc1
130
+ CHEMBL482767,O=C(Nc1cccc(Cl)c1)Nc1ncc(CCNc2ncnc3ccsc23)s1
131
+ CHEMBL482967,Cc1nc(N)sc1-c1ccnc(Nc2ccc(N3CCOCC3)cc2)n1
132
+ CHEMBL482968,Cc1cc(Nc2cc(N3CCN(C)CC3)nc(/C=C/c3ccccc3)n2)n[nH]1
133
+ CHEMBL483158,COc1cc(Nc2ncc3c(n2)-c2ccc(Cl)cc2C(c2c(F)cccc2OC)=NC3)ccc1C(=O)O
134
+ CHEMBL483254,Cc1[nH]c2ccccc2c1CCNCc1ccc(/C=C/C(=O)NO)cc1
135
+ CHEMBL488,CCC1(c2ccc(N)cc2)CCC(=O)NC1=O
136
+ CHEMBL491473,COc1cc2c(Oc3ccc4[nH]c(C)cc4c3F)ncnc2cc1OCCCN1CCCC1
137
+ CHEMBL495727,O=C(Nc1c[nH]nc1-c1nc2ccc(CN3CCOCC3)cc2[nH]1)NC1CC1
138
+ CHEMBL50,O=c1c(O)c(-c2ccc(O)c(O)c2)oc2cc(O)cc(O)c12
139
+ CHEMBL502835,COC(=O)c1ccc2c(c1)NC(=O)/C2=C(\Nc1ccc(N(C)C(=O)CN2CCN(C)CC2)cc1)c1ccccc1
140
+ CHEMBL506871,C[C@]1(c2nc3c(C(N)=O)cccc3[nH]2)CCCN1
141
+ CHEMBL514,O=NN(CCCl)C(=O)NC1CCCCC1
142
+ CHEMBL514409,CCS(=O)(=O)Nc1ccc2c(c1)/C(=C(/Nc1ccc(CN3CCCCC3)cc1)c1ccccc1)C(=O)N2
143
+ CHEMBL52885,Cn1cc(C2=C(c3cn(C)c4cc([N+](=O)[O-])ccc34)C(=O)NC2=O)c2ccccc21
144
+ CHEMBL554,CS(=O)(=O)CCNCc1ccc(-c2ccc3ncnc(Nc4ccc(OCc5cccc(F)c5)c(Cl)c4)c3c2)o1
145
+ CHEMBL572878,Cc1cc(Nc2cc(N3CCN(C)CC3)nc(Sc3ccc(NC(=O)C4CC4)cc3)n2)n[nH]1
146
+ CHEMBL572881,CC1(C)CNc2cc(NC(=O)c3cccnc3NCc3ccncc3)ccc21
147
+ CHEMBL575448,C[C@@]1(C(=O)Nc2ccc(F)nc2)CCCN1c1nc(Nc2cc(C3CC3)n[nH]2)c2cccn2n1
148
+ CHEMBL598797,C#Cc1cccc(Nc2ncnc3cc(OC)c(OCCCCCCC(=O)NO)cc23)c1
149
+ CHEMBL601719,C[C@@H](Oc1cc(-c2cnn(C3CCNCC3)c2)cnc1N)c1c(Cl)ccc(F)c1Cl
150
+ CHEMBL607707,CCOc1cc2ncc(C#N)c(Nc3ccc(F)c(Cl)c3)c2cc1NC(=O)/C=C/CN(C)C
151
+ CHEMBL6246,O=c1oc2c(O)c(O)cc3c(=O)oc4c(O)c(O)cc1c4c23
152
+ CHEMBL6291,Cn1cc(C2=C(c3cn(CCCSC(=N)N)c4ccccc34)C(=O)NC2=O)c2ccccc21
153
+ CHEMBL635,C[C@]12C=CC(=O)C=C1CC[C@@H]1[C@@H]2C(=O)C[C@@]2(C)[C@H]1CC[C@]2(O)C(=O)CO
154
+ CHEMBL65892,CN(C)Cc1ccc(-c2nc3cccc4c3n2CCNC4=O)cc1
155
+ CHEMBL671,S=P(N1CC1)(N1CC1)N1CC1
156
+ CHEMBL675,NCCCC(O)(P(=O)([O-])O)P(=O)(O)O.[Na+]
157
+ CHEMBL81977,NC(=O)c1cccc(N)c1
158
+ CHEMBL820,CS(=O)(=O)OCCCCOS(C)(=O)=O
159
+ CHEMBL84617,CCC(=O)N(c1ccccc1F)C1(c2ccccc2)CCN(CCn2nnn(CC)c2=O)CC1
160
+ CHEMBL848,Nc1cccc2c1CN(C1CCC(=O)NC1=O)C2=O
161
+ CHEMBL86416,C=C1C(=O)O[C@@H]2/C=C(\C)CC/C=C(\C)CC[C@@H]12
162
+ CHEMBL93,CC(c1cc2ccccc2s1)N(O)C(N)=O
163
+ CHEMBL94657,C/C(=C\c1csc(C)n1)[C@@H]1C[C@@H]2O[C@]2(C)CCC[C@H](C)[C@H](O)[C@@H](C)C(=O)C(C)(C)[C@@H](O)CC(=O)O1
164
+ CHEMBL953,CCN(CC)C(=O)/C(C#N)=C/c1cc(O)c(O)c([N+](=O)[O-])c1
165
+ CHEMBL964,CCN(CC)C(=S)SSC(=S)N(CC)CC
166
+ CHEMBL975,O=S(=O)([O-])CCS.[Na+]
167
+ CHEMBL99,CC(/C=C/C(=O)NO)=C\[C@@H](C)C(=O)c1ccc(N(C)C)cc1
PDGrapher/data/process_all_data.sh ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Process COSMIC data
4
+ cd scripts/cosmic
5
+ python3 generate_cell_line_mutations_files.py
6
+ cd ../..
7
+
8
+
9
+ # Process COSMIC data
10
+ cd scripts/drugbank
11
+ python3 get_drug_targets.py
12
+ cd ../..
13
+
14
+ # Process PPI data
15
+ cd scripts/ppi
16
+ python3 export_ppi_all_genes.py
17
+ cd ../..
18
+
19
+
20
+ # Process LINCS data
21
+ cd scripts/lincs
22
+ python3 process_data.py
23
+ python3 process_data_healthy.py
24
+ python3 process_data_chemical_1.py
25
+ python3 process_data_chemical_2.py
26
+ python3 process_data_healthy_chemical.py
27
+ cd ../..
28
+
29
+
30
+
31
+ # Data preparation
32
+ cd scripts/rep-learning-approach-3
33
+ python3 export_data_for_torch_geometric.py
34
+ python3 export_data_for_torch_geometric_chemical.py
35
+ cd ../..
PDGrapher/data/processed/sciplex3_k562_24h_gene_map.json ADDED
@@ -0,0 +1,1978 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ENSG00000000971": "CFH",
3
+ "ENSG00000001629": "ANKIB1",
4
+ "ENSG00000001631": "KRIT1",
5
+ "ENSG00000002822": "MAD1L1",
6
+ "ENSG00000002834": "LASP1",
7
+ "ENSG00000003402": "CFLAR",
8
+ "ENSG00000003436": "TFPI",
9
+ "ENSG00000004487": "KDM1A",
10
+ "ENSG00000004534": "RBM6",
11
+ "ENSG00000004864": "SLC25A13",
12
+ "ENSG00000004866": "ST7",
13
+ "ENSG00000004897": "CDC27",
14
+ "ENSG00000005187": "ACSM3",
15
+ "ENSG00000005249": "PRKAR2B",
16
+ "ENSG00000005339": "CREBBP",
17
+ "ENSG00000005483": "KMT2E",
18
+ "ENSG00000005700": "IBTK",
19
+ "ENSG00000005810": "MYCBP2",
20
+ "ENSG00000005893": "LAMP2",
21
+ "ENSG00000006125": "AP2B1",
22
+ "ENSG00000006576": "PHTF2",
23
+ "ENSG00000006704": "GTF2IRD1",
24
+ "ENSG00000006831": "ADIPOR2",
25
+ "ENSG00000007047": "MARK4",
26
+ "ENSG00000007168": "PAFAH1B1",
27
+ "ENSG00000007202": "BLTP2",
28
+ "ENSG00000007392": "LUC7L",
29
+ "ENSG00000007923": "DNAJC11",
30
+ "ENSG00000007944": "MYLIP",
31
+ "ENSG00000008083": "JARID2",
32
+ "ENSG00000008294": "SPAG9",
33
+ "ENSG00000009307": "CSDE1",
34
+ "ENSG00000009335": "UBE3C",
35
+ "ENSG00000009413": "REV3L",
36
+ "ENSG00000009694": "TENM1",
37
+ "ENSG00000009954": "BAZ1B",
38
+ "ENSG00000010017": "RANBP9",
39
+ "ENSG00000010244": "ZNF207",
40
+ "ENSG00000010292": "NCAPD2",
41
+ "ENSG00000010803": "SCMH1",
42
+ "ENSG00000011114": "BTBD7",
43
+ "ENSG00000011198": "ABHD5",
44
+ "ENSG00000011243": "AKAP8L",
45
+ "ENSG00000011258": "MBTD1",
46
+ "ENSG00000011275": "RNF216",
47
+ "ENSG00000011304": "PTBP1",
48
+ "ENSG00000011376": "LARS2",
49
+ "ENSG00000011405": "PIK3C2A",
50
+ "ENSG00000011454": "RABGAP1",
51
+ "ENSG00000011566": "MAP4K3",
52
+ "ENSG00000012048": "BRCA1",
53
+ "ENSG00000012660": "ELOVL5",
54
+ "ENSG00000014824": "SLC30A9",
55
+ "ENSG00000018189": "RUFY3",
56
+ "ENSG00000018510": "AGPS",
57
+ "ENSG00000018699": "TTC27",
58
+ "ENSG00000020577": "SAMD4A",
59
+ "ENSG00000021776": "AQR",
60
+ "ENSG00000023228": "NDUFS1",
61
+ "ENSG00000023287": "RB1CC1",
62
+ "ENSG00000023909": "GCLM",
63
+ "ENSG00000024048": "UBR2",
64
+ "ENSG00000025293": "PHF20",
65
+ "ENSG00000025796": "SEC63",
66
+ "ENSG00000025800": "KPNA6",
67
+ "ENSG00000026025": "VIM",
68
+ "ENSG00000028203": "VEZT",
69
+ "ENSG00000029363": "BCLAF1",
70
+ "ENSG00000029534": "ANK1",
71
+ "ENSG00000029725": "RABEP1",
72
+ "ENSG00000030066": "NUP160",
73
+ "ENSG00000031003": "FAM13B",
74
+ "ENSG00000031698": "SARS1",
75
+ "ENSG00000033178": "UBA6",
76
+ "ENSG00000033327": "GAB2",
77
+ "ENSG00000033627": "ATP6V0A1",
78
+ "ENSG00000033800": "PIAS1",
79
+ "ENSG00000034053": "APBA2",
80
+ "ENSG00000034510": "TMSB10",
81
+ "ENSG00000035403": "VCL",
82
+ "ENSG00000036257": "CUL3",
83
+ "ENSG00000036549": "ZZZ3",
84
+ "ENSG00000037637": "FBXO42",
85
+ "ENSG00000038532": "CLEC16A",
86
+ "ENSG00000039123": "MTREX",
87
+ "ENSG00000039560": "RAI14",
88
+ "ENSG00000040341": "STAU2",
89
+ "ENSG00000042062": "RIPOR3",
90
+ "ENSG00000044115": "CTNNA1",
91
+ "ENSG00000044574": "HSPA5",
92
+ "ENSG00000046604": "DSG2",
93
+ "ENSG00000047410": "TPR",
94
+ "ENSG00000047579": "DTNBP1",
95
+ "ENSG00000047648": "ARHGAP6",
96
+ "ENSG00000047849": "MAP4",
97
+ "ENSG00000048405": "ZNF800",
98
+ "ENSG00000048471": "SNX29",
99
+ "ENSG00000048649": "RSF1",
100
+ "ENSG00000048707": "VPS13D",
101
+ "ENSG00000048828": "FAM120A",
102
+ "ENSG00000048991": "R3HDM1",
103
+ "ENSG00000049323": "LTBP1",
104
+ "ENSG00000049618": "ARID1B",
105
+ "ENSG00000049759": "NEDD4L",
106
+ "ENSG00000050405": "LIMA1",
107
+ "ENSG00000050426": "LETMD1",
108
+ "ENSG00000051382": "PIK3CB",
109
+ "ENSG00000051825": "MPHOSPH9",
110
+ "ENSG00000052126": "PLEKHA5",
111
+ "ENSG00000052841": "TTC17",
112
+ "ENSG00000054118": "THRAP3",
113
+ "ENSG00000054267": "ARID4B",
114
+ "ENSG00000054282": "SDCCAG8",
115
+ "ENSG00000054523": "KIF1B",
116
+ "ENSG00000054611": "TBC1D22A",
117
+ "ENSG00000054965": "FAM168A",
118
+ "ENSG00000055044": "NOP58",
119
+ "ENSG00000055130": "CUL1",
120
+ "ENSG00000055208": "TAB2",
121
+ "ENSG00000055609": "KMT2C",
122
+ "ENSG00000055917": "PUM2",
123
+ "ENSG00000056097": "ZFR",
124
+ "ENSG00000056586": "RC3H2",
125
+ "ENSG00000057608": "GDI2",
126
+ "ENSG00000057663": "ATG5",
127
+ "ENSG00000058063": "ATP11B",
128
+ "ENSG00000058272": "PPP1R12A",
129
+ "ENSG00000058668": "ATP2B4",
130
+ "ENSG00000058804": "NDC1",
131
+ "ENSG00000059758": "CDK17",
132
+ "ENSG00000059804": "SLC2A3",
133
+ "ENSG00000060237": "WNK1",
134
+ "ENSG00000060339": "CCAR1",
135
+ "ENSG00000060749": "QSER1",
136
+ "ENSG00000060982": "BCAT1",
137
+ "ENSG00000061676": "NCKAP1",
138
+ "ENSG00000061936": "SFSWAP",
139
+ "ENSG00000061987": "MON2",
140
+ "ENSG00000062194": "GPBP1",
141
+ "ENSG00000062650": "WAPL",
142
+ "ENSG00000062716": "VMP1",
143
+ "ENSG00000062725": "APPBP2",
144
+ "ENSG00000063046": "EIF4B",
145
+ "ENSG00000063177": "RPL18",
146
+ "ENSG00000063978": "RNF4",
147
+ "ENSG00000064313": "TAF2",
148
+ "ENSG00000064393": "HIPK2",
149
+ "ENSG00000064419": "TNPO3",
150
+ "ENSG00000064607": "SUGP2",
151
+ "ENSG00000064999": "ANKS1A",
152
+ "ENSG00000065060": "BLTP3A",
153
+ "ENSG00000065243": "PKN2",
154
+ "ENSG00000065526": "SPEN",
155
+ "ENSG00000065833": "ME1",
156
+ "ENSG00000065883": "CDK13",
157
+ "ENSG00000066027": "PPP2R5A",
158
+ "ENSG00000066084": "DIP2B",
159
+ "ENSG00000066279": "ASPM",
160
+ "ENSG00000066777": "ARFGEF1",
161
+ "ENSG00000066933": "MYO9A",
162
+ "ENSG00000067208": "EVI5",
163
+ "ENSG00000067225": "PKM",
164
+ "ENSG00000067369": "TP53BP1",
165
+ "ENSG00000067560": "RHOA",
166
+ "ENSG00000067900": "ROCK1",
167
+ "ENSG00000067955": "CBFB",
168
+ "ENSG00000068305": "MEF2A",
169
+ "ENSG00000068366": "ACSL4",
170
+ "ENSG00000068489": "PRR11",
171
+ "ENSG00000068650": "ATP11A",
172
+ "ENSG00000068654": "POLR1A",
173
+ "ENSG00000068784": "SRBD1",
174
+ "ENSG00000068796": "KIF2A",
175
+ "ENSG00000068878": "PSME4",
176
+ "ENSG00000069275": "NUCKS1",
177
+ "ENSG00000069702": "TGFBR3",
178
+ "ENSG00000069849": "ATP1B3",
179
+ "ENSG00000069869": "NEDD4",
180
+ "ENSG00000069956": "MAPK6",
181
+ "ENSG00000069974": "RAB27A",
182
+ "ENSG00000070010": "UFD1",
183
+ "ENSG00000070366": "SMG6",
184
+ "ENSG00000070371": "CLTCL1",
185
+ "ENSG00000070413": "DGCR2",
186
+ "ENSG00000070756": "PABPC1",
187
+ "ENSG00000070785": "EIF2B3",
188
+ "ENSG00000070882": "OSBPL3",
189
+ "ENSG00000070950": "RAD18",
190
+ "ENSG00000070961": "ATP2B1",
191
+ "ENSG00000071054": "MAP4K4",
192
+ "ENSG00000071082": "RPL31",
193
+ "ENSG00000071909": "MYO3B",
194
+ "ENSG00000072274": "TFRC",
195
+ "ENSG00000072364": "AFF4",
196
+ "ENSG00000072518": "MARK2",
197
+ "ENSG00000072736": "NFATC3",
198
+ "ENSG00000072803": "FBXW11",
199
+ "ENSG00000073060": "SCARB1",
200
+ "ENSG00000073417": "PDE8A",
201
+ "ENSG00000073614": "KDM5A",
202
+ "ENSG00000073792": "IGF2BP2",
203
+ "ENSG00000073849": "ST6GAL1",
204
+ "ENSG00000073921": "PICALM",
205
+ "ENSG00000074054": "CLASP1",
206
+ "ENSG00000074201": "CLNS1A",
207
+ "ENSG00000074370": "ATP2A3",
208
+ "ENSG00000074603": "DPP8",
209
+ "ENSG00000074695": "LMAN1",
210
+ "ENSG00000074696": "HACD3",
211
+ "ENSG00000074800": "ENO1",
212
+ "ENSG00000075151": "EIF4G3",
213
+ "ENSG00000075292": "ZNF638",
214
+ "ENSG00000075413": "MARK3",
215
+ "ENSG00000075420": "FNDC3B",
216
+ "ENSG00000075539": "FRYL",
217
+ "ENSG00000075568": "TMEM131",
218
+ "ENSG00000075624": "ACTB",
219
+ "ENSG00000075651": "PLD1",
220
+ "ENSG00000075711": "DLG1",
221
+ "ENSG00000075785": "RAB7A",
222
+ "ENSG00000076108": "BAZ2A",
223
+ "ENSG00000076321": "KLHL20",
224
+ "ENSG00000076685": "NT5C2",
225
+ "ENSG00000076706": "MCAM",
226
+ "ENSG00000077097": "TOP2B",
227
+ "ENSG00000077157": "PPP1R12B",
228
+ "ENSG00000077254": "USP33",
229
+ "ENSG00000077549": "CAPZB",
230
+ "ENSG00000078114": "NEBL",
231
+ "ENSG00000078124": "ACER3",
232
+ "ENSG00000078140": "UBE2K",
233
+ "ENSG00000078269": "SYNJ2",
234
+ "ENSG00000078304": "PPP2R5C",
235
+ "ENSG00000078369": "GNB1",
236
+ "ENSG00000078403": "MLLT10",
237
+ "ENSG00000078618": "NRDC",
238
+ "ENSG00000078674": "PCM1",
239
+ "ENSG00000078699": "CBFA2T2",
240
+ "ENSG00000078747": "ITCH",
241
+ "ENSG00000079246": "XRCC5",
242
+ "ENSG00000079335": "CDC14A",
243
+ "ENSG00000079459": "FDFT1",
244
+ "ENSG00000079805": "DNM2",
245
+ "ENSG00000080298": "RFX3",
246
+ "ENSG00000080345": "RIF1",
247
+ "ENSG00000080608": "PUM3",
248
+ "ENSG00000080802": "CNOT4",
249
+ "ENSG00000080824": "HSP90AA1",
250
+ "ENSG00000080839": "RBL1",
251
+ "ENSG00000081026": "MAGI3",
252
+ "ENSG00000081189": "MEF2C",
253
+ "ENSG00000081237": "PTPRC",
254
+ "ENSG00000081913": "PHLPP1",
255
+ "ENSG00000082068": "WDR70",
256
+ "ENSG00000082269": "FAM135A",
257
+ "ENSG00000082701": "GSK3B",
258
+ "ENSG00000082805": "ERC1",
259
+ "ENSG00000082898": "XPO1",
260
+ "ENSG00000083168": "KAT6A",
261
+ "ENSG00000083312": "TNPO1",
262
+ "ENSG00000083444": "PLOD1",
263
+ "ENSG00000083535": "PIBF1",
264
+ "ENSG00000083845": "RPS5",
265
+ "ENSG00000084070": "SMAP2",
266
+ "ENSG00000084234": "APLP2",
267
+ "ENSG00000084623": "EIF3I",
268
+ "ENSG00000084676": "NCOA1",
269
+ "ENSG00000084733": "RAB10",
270
+ "ENSG00000084754": "HADHA",
271
+ "ENSG00000085224": "ATRX",
272
+ "ENSG00000085511": "MAP3K4",
273
+ "ENSG00000085832": "EPS15",
274
+ "ENSG00000086015": "MAST2",
275
+ "ENSG00000086102": "NFX1",
276
+ "ENSG00000086200": "IPO11",
277
+ "ENSG00000086232": "EIF2AK1",
278
+ "ENSG00000086666": "ZFAND6",
279
+ "ENSG00000086758": "HUWE1",
280
+ "ENSG00000087086": "FTL",
281
+ "ENSG00000087095": "NLK",
282
+ "ENSG00000087206": "UIMC1",
283
+ "ENSG00000087274": "ADD1",
284
+ "ENSG00000087460": "GNAS",
285
+ "ENSG00000087589": "CASS4",
286
+ "ENSG00000087903": "RFX2",
287
+ "ENSG00000088179": "PTPN4",
288
+ "ENSG00000088247": "KHSRP",
289
+ "ENSG00000088325": "TPX2",
290
+ "ENSG00000088387": "DOCK9",
291
+ "ENSG00000088854": "DNAAF9",
292
+ "ENSG00000088888": "MAVS",
293
+ "ENSG00000089053": "ANAPC5",
294
+ "ENSG00000089094": "KDM2B",
295
+ "ENSG00000089154": "GCN1",
296
+ "ENSG00000089157": "RPLP0",
297
+ "ENSG00000089280": "FUS",
298
+ "ENSG00000089597": "GANAB",
299
+ "ENSG00000089902": "RCOR1",
300
+ "ENSG00000090006": "LTBP4",
301
+ "ENSG00000090013": "BLVRB",
302
+ "ENSG00000090273": "NUDC",
303
+ "ENSG00000090686": "USP48",
304
+ "ENSG00000090861": "AARS1",
305
+ "ENSG00000090863": "GLG1",
306
+ "ENSG00000090905": "TNRC6A",
307
+ "ENSG00000091039": "OSBPL8",
308
+ "ENSG00000091127": "PUS7",
309
+ "ENSG00000091436": "MAP3K20",
310
+ "ENSG00000091490": "SEL1L3",
311
+ "ENSG00000091592": "NLRP1",
312
+ "ENSG00000092108": "SCFD1",
313
+ "ENSG00000092148": "HECTD1",
314
+ "ENSG00000092199": "HNRNPC",
315
+ "ENSG00000092439": "TRPM7",
316
+ "ENSG00000092820": "EZR",
317
+ "ENSG00000092847": "AGO1",
318
+ "ENSG00000092853": "CLSPN",
319
+ "ENSG00000092929": "UNC13D",
320
+ "ENSG00000092931": "MFSD11",
321
+ "ENSG00000093009": "CDC45",
322
+ "ENSG00000093010": "COMT",
323
+ "ENSG00000093167": "LRRFIP2",
324
+ "ENSG00000094916": "CBX5",
325
+ "ENSG00000094975": "SUCO",
326
+ "ENSG00000095002": "MSH2",
327
+ "ENSG00000095261": "PSMD5",
328
+ "ENSG00000095564": "BTAF1",
329
+ "ENSG00000095637": "SORBS1",
330
+ "ENSG00000095787": "WAC",
331
+ "ENSG00000095951": "HIVEP1",
332
+ "ENSG00000096060": "FKBP5",
333
+ "ENSG00000096063": "SRPK1",
334
+ "ENSG00000096384": "HSP90AB1",
335
+ "ENSG00000096968": "JAK2",
336
+ "ENSG00000097007": "ABL1",
337
+ "ENSG00000099194": "SCD",
338
+ "ENSG00000099331": "MYO9B",
339
+ "ENSG00000099783": "HNRNPM",
340
+ "ENSG00000099910": "KLHL22",
341
+ "ENSG00000099917": "MED15",
342
+ "ENSG00000099940": "SNAP29",
343
+ "ENSG00000099942": "CRKL",
344
+ "ENSG00000099968": "BCL2L13",
345
+ "ENSG00000099991": "CABIN1",
346
+ "ENSG00000100023": "PPIL2",
347
+ "ENSG00000100030": "MAPK1",
348
+ "ENSG00000100034": "PPM1F",
349
+ "ENSG00000100075": "SLC25A1",
350
+ "ENSG00000100084": "HIRA",
351
+ "ENSG00000100154": "TTC28",
352
+ "ENSG00000100181": "TPTEP1",
353
+ "ENSG00000100201": "DDX17",
354
+ "ENSG00000100239": "PPP6R2",
355
+ "ENSG00000100266": "PACSIN2",
356
+ "ENSG00000100316": "RPL3",
357
+ "ENSG00000100320": "RBFOX2",
358
+ "ENSG00000100354": "TNRC6B",
359
+ "ENSG00000100372": "SLC25A17",
360
+ "ENSG00000100376": "SIRAL2",
361
+ "ENSG00000100393": "EP300",
362
+ "ENSG00000100485": "SOS2",
363
+ "ENSG00000100596": "SPTLC2",
364
+ "ENSG00000100749": "VRK1",
365
+ "ENSG00000100784": "RPS6KA5",
366
+ "ENSG00000100811": "YY1",
367
+ "ENSG00000100813": "ACIN1",
368
+ "ENSG00000100888": "CHD8",
369
+ "ENSG00000100991": "TRPC4AP",
370
+ "ENSG00000101040": "ZMYND8",
371
+ "ENSG00000101126": "ADNP",
372
+ "ENSG00000101152": "DNAJC5",
373
+ "ENSG00000101191": "DIDO1",
374
+ "ENSG00000101236": "RNF24",
375
+ "ENSG00000101266": "CSNK2A1",
376
+ "ENSG00000101294": "HM13",
377
+ "ENSG00000101337": "TM9SF4",
378
+ "ENSG00000101557": "USP14",
379
+ "ENSG00000101558": "VAPA",
380
+ "ENSG00000101577": "LPIN2",
381
+ "ENSG00000101596": "SMCHD1",
382
+ "ENSG00000101639": "CEP192",
383
+ "ENSG00000101745": "ANKRD12",
384
+ "ENSG00000101752": "MIB1",
385
+ "ENSG00000101782": "RIOK3",
386
+ "ENSG00000101849": "TBL1X",
387
+ "ENSG00000101868": "POLA1",
388
+ "ENSG00000101966": "XIAP",
389
+ "ENSG00000101972": "STAG2",
390
+ "ENSG00000101974": "ATP11C",
391
+ "ENSG00000102144": "PGK1",
392
+ "ENSG00000102145": "GATA1",
393
+ "ENSG00000102189": "EEA1",
394
+ "ENSG00000102265": "TIMP1",
395
+ "ENSG00000102531": "FNDC3A",
396
+ "ENSG00000102595": "UGGT2",
397
+ "ENSG00000102763": "VWA8",
398
+ "ENSG00000102786": "INTS6",
399
+ "ENSG00000102893": "PHKB",
400
+ "ENSG00000102908": "NFAT5",
401
+ "ENSG00000102910": "LONP2",
402
+ "ENSG00000102974": "CTCF",
403
+ "ENSG00000103047": "TANGO6",
404
+ "ENSG00000103091": "WDR59",
405
+ "ENSG00000103148": "NPRL3",
406
+ "ENSG00000103194": "USP10",
407
+ "ENSG00000103222": "ABCC1",
408
+ "ENSG00000103319": "EEF2K",
409
+ "ENSG00000103335": "PIEZO1",
410
+ "ENSG00000103342": "GSPT1",
411
+ "ENSG00000103365": "GGA2",
412
+ "ENSG00000103381": "CPPED1",
413
+ "ENSG00000103485": "QPRT",
414
+ "ENSG00000103657": "HERC1",
415
+ "ENSG00000103978": "TMEM87A",
416
+ "ENSG00000103994": "ZNF106",
417
+ "ENSG00000103995": "CEP152",
418
+ "ENSG00000104067": "TJP1",
419
+ "ENSG00000104093": "DMXL2",
420
+ "ENSG00000104133": "SPG11",
421
+ "ENSG00000104218": "CSPP1",
422
+ "ENSG00000104299": "INTS9",
423
+ "ENSG00000104341": "LAPTM4B",
424
+ "ENSG00000104375": "STK3",
425
+ "ENSG00000104388": "RAB2A",
426
+ "ENSG00000104447": "TRPS1",
427
+ "ENSG00000104490": "NCALD",
428
+ "ENSG00000104517": "UBR5",
429
+ "ENSG00000104529": "EEF1D",
430
+ "ENSG00000104549": "SQLE",
431
+ "ENSG00000104626": "ERI1",
432
+ "ENSG00000104687": "GSR",
433
+ "ENSG00000104723": "TUSC3",
434
+ "ENSG00000104738": "MCM4",
435
+ "ENSG00000104765": "BNIP3L",
436
+ "ENSG00000104805": "NUCB1",
437
+ "ENSG00000104852": "SNRNP70",
438
+ "ENSG00000104904": "OAZ1",
439
+ "ENSG00000105176": "URI1",
440
+ "ENSG00000105186": "ANKRD27",
441
+ "ENSG00000105193": "RPS16",
442
+ "ENSG00000105220": "GPI",
443
+ "ENSG00000105223": "PLD3",
444
+ "ENSG00000105281": "SLC1A5",
445
+ "ENSG00000105323": "HNRNPUL1",
446
+ "ENSG00000105329": "TGFB1",
447
+ "ENSG00000105355": "PLIN3",
448
+ "ENSG00000105372": "RPS19",
449
+ "ENSG00000105426": "PTPRS",
450
+ "ENSG00000105438": "KDELR1",
451
+ "ENSG00000105464": "GRIN2D",
452
+ "ENSG00000105576": "TNPO2",
453
+ "ENSG00000105738": "SIPA1L3",
454
+ "ENSG00000105778": "AVL9",
455
+ "ENSG00000105810": "CDK6",
456
+ "ENSG00000105887": "MTPN",
457
+ "ENSG00000105889": "STEAP1B",
458
+ "ENSG00000105939": "ZC3HAV1",
459
+ "ENSG00000105953": "OGDH",
460
+ "ENSG00000105968": "H2AZ2",
461
+ "ENSG00000105983": "LMBR1",
462
+ "ENSG00000105993": "DNAJB6",
463
+ "ENSG00000106034": "CPED1",
464
+ "ENSG00000106049": "HIBADH",
465
+ "ENSG00000106052": "TAX1BP1",
466
+ "ENSG00000106070": "GRB10",
467
+ "ENSG00000106105": "GARS1",
468
+ "ENSG00000106153": "CHCHD2",
469
+ "ENSG00000106211": "HSPB1",
470
+ "ENSG00000106261": "ZKSCAN1",
471
+ "ENSG00000106263": "EIF3B",
472
+ "ENSG00000106299": "WASL",
473
+ "ENSG00000106327": "TFR2",
474
+ "ENSG00000106443": "PHF14",
475
+ "ENSG00000106459": "NRF1",
476
+ "ENSG00000106462": "EZH2",
477
+ "ENSG00000106526": "ACTR3C",
478
+ "ENSG00000106554": "CHCHD3",
479
+ "ENSG00000106603": "COA1",
480
+ "ENSG00000106615": "RHEB",
481
+ "ENSG00000106665": "CLIP2",
482
+ "ENSG00000106771": "TMEM245",
483
+ "ENSG00000106868": "SUSD1",
484
+ "ENSG00000107077": "KDM4C",
485
+ "ENSG00000107099": "DOCK8",
486
+ "ENSG00000107164": "FUBP3",
487
+ "ENSG00000107242": "PIP5K1B",
488
+ "ENSG00000107263": "RAPGEF1",
489
+ "ENSG00000107290": "SETX",
490
+ "ENSG00000107341": "UBE2R2",
491
+ "ENSG00000107581": "EIF3A",
492
+ "ENSG00000107625": "DDX50",
493
+ "ENSG00000107643": "MAPK8",
494
+ "ENSG00000107745": "MICU1",
495
+ "ENSG00000107758": "PPP3CB",
496
+ "ENSG00000107771": "CCSER2",
497
+ "ENSG00000107779": "BMPR1A",
498
+ "ENSG00000107862": "GBF1",
499
+ "ENSG00000107863": "ARHGAP21",
500
+ "ENSG00000107929": "LARP4B",
501
+ "ENSG00000108018": "SORCS1",
502
+ "ENSG00000108021": "TASOR2",
503
+ "ENSG00000108100": "CCNY",
504
+ "ENSG00000108107": "RPL28",
505
+ "ENSG00000108175": "ZMIZ1",
506
+ "ENSG00000108256": "NUFIP2",
507
+ "ENSG00000108298": "RPL19",
508
+ "ENSG00000108306": "FBXL20",
509
+ "ENSG00000108395": "TRIM37",
510
+ "ENSG00000108405": "P2RX1",
511
+ "ENSG00000108424": "KPNB1",
512
+ "ENSG00000108474": "PIGL",
513
+ "ENSG00000108510": "MED13",
514
+ "ENSG00000108518": "PFN1",
515
+ "ENSG00000108848": "LUC7L3",
516
+ "ENSG00000108883": "EFTUD2",
517
+ "ENSG00000108953": "YWHAE",
518
+ "ENSG00000109046": "WSB1",
519
+ "ENSG00000109111": "SUPT6H",
520
+ "ENSG00000109118": "PHF12",
521
+ "ENSG00000109180": "OCIAD1",
522
+ "ENSG00000109255": "NMU",
523
+ "ENSG00000109332": "UBE2D3",
524
+ "ENSG00000109381": "ELF2",
525
+ "ENSG00000109475": "RPL34",
526
+ "ENSG00000109572": "CLCN3",
527
+ "ENSG00000109586": "GALNT7",
528
+ "ENSG00000109606": "DHX15",
529
+ "ENSG00000109670": "FBXW7",
530
+ "ENSG00000109685": "NSD2",
531
+ "ENSG00000109756": "RAPGEF2",
532
+ "ENSG00000109762": "SNX25",
533
+ "ENSG00000109861": "CTSC",
534
+ "ENSG00000109911": "ELP4",
535
+ "ENSG00000109920": "FNBP4",
536
+ "ENSG00000110048": "OSBP",
537
+ "ENSG00000110075": "PPP6R3",
538
+ "ENSG00000110344": "UBE4A",
539
+ "ENSG00000110367": "DDX6",
540
+ "ENSG00000110395": "CBL",
541
+ "ENSG00000110497": "AMBRA1",
542
+ "ENSG00000110619": "CARS1",
543
+ "ENSG00000110651": "CD81",
544
+ "ENSG00000110693": "SOX6",
545
+ "ENSG00000110713": "NUP98",
546
+ "ENSG00000110880": "CORO1C",
547
+ "ENSG00000110917": "MLEC",
548
+ "ENSG00000110955": "ATP5F1B",
549
+ "ENSG00000110958": "PTGES3",
550
+ "ENSG00000111057": "KRT18",
551
+ "ENSG00000111110": "PPM1H",
552
+ "ENSG00000111252": "SH2B3",
553
+ "ENSG00000111300": "NAA25",
554
+ "ENSG00000111371": "SLC38A1",
555
+ "ENSG00000111581": "NUP107",
556
+ "ENSG00000111596": "CNOT2",
557
+ "ENSG00000111640": "GAPDH",
558
+ "ENSG00000111642": "CHD4",
559
+ "ENSG00000111666": "CHPT1",
560
+ "ENSG00000111669": "TPI1",
561
+ "ENSG00000111860": "CEP85L",
562
+ "ENSG00000111880": "RNGTT",
563
+ "ENSG00000111885": "MAN1A1",
564
+ "ENSG00000112033": "PPARD",
565
+ "ENSG00000112062": "MAPK14",
566
+ "ENSG00000112077": "RHAG",
567
+ "ENSG00000112078": "KCTD20",
568
+ "ENSG00000112079": "STK38",
569
+ "ENSG00000112159": "MDN1",
570
+ "ENSG00000112182": "BACH2",
571
+ "ENSG00000112200": "ZNF451",
572
+ "ENSG00000112242": "E2F3",
573
+ "ENSG00000112249": "ASCC3",
574
+ "ENSG00000112306": "RPS12",
575
+ "ENSG00000112308": "C6ORF62",
576
+ "ENSG00000112339": "HBS1L",
577
+ "ENSG00000112419": "PHACTR2",
578
+ "ENSG00000112531": "QKI",
579
+ "ENSG00000112576": "CCND3",
580
+ "ENSG00000112624": "BICRAL",
581
+ "ENSG00000112699": "GMDS",
582
+ "ENSG00000112701": "SENP6",
583
+ "ENSG00000112739": "PRP4K",
584
+ "ENSG00000112851": "ERBIN",
585
+ "ENSG00000112893": "MAN2A1",
586
+ "ENSG00000112972": "HMGCS1",
587
+ "ENSG00000112977": "DAP",
588
+ "ENSG00000113013": "HSPA9",
589
+ "ENSG00000113048": "MRPS27",
590
+ "ENSG00000113163": "CERT1",
591
+ "ENSG00000113194": "FAF2",
592
+ "ENSG00000113269": "RNF130",
593
+ "ENSG00000113282": "CLINT1",
594
+ "ENSG00000113318": "MSH3",
595
+ "ENSG00000113384": "GOLPH3",
596
+ "ENSG00000113391": "ARB2A",
597
+ "ENSG00000113441": "LNPEP",
598
+ "ENSG00000113569": "NUP155",
599
+ "ENSG00000113580": "NR3C1",
600
+ "ENSG00000113615": "SEC24A",
601
+ "ENSG00000113643": "RARS1",
602
+ "ENSG00000113648": "MACROH2A1",
603
+ "ENSG00000113649": "TCERG1",
604
+ "ENSG00000113712": "CSNK1A1",
605
+ "ENSG00000113732": "ATP6V0E1",
606
+ "ENSG00000113742": "CPEB4",
607
+ "ENSG00000113810": "SMC4",
608
+ "ENSG00000114062": "UBE3A",
609
+ "ENSG00000114126": "TFDP2",
610
+ "ENSG00000114127": "XRN1",
611
+ "ENSG00000114268": "PFKFB4",
612
+ "ENSG00000114302": "PRKAR2A",
613
+ "ENSG00000114331": "ACAP2",
614
+ "ENSG00000114439": "BBX",
615
+ "ENSG00000114480": "GBE1",
616
+ "ENSG00000114650": "SCAP",
617
+ "ENSG00000114770": "ABCC5",
618
+ "ENSG00000114857": "NKTR",
619
+ "ENSG00000114861": "FOXP1",
620
+ "ENSG00000114867": "EIF4G1",
621
+ "ENSG00000115084": "SLC35F5",
622
+ "ENSG00000115091": "ACTR3",
623
+ "ENSG00000115170": "ACVR1",
624
+ "ENSG00000115233": "PSMD14",
625
+ "ENSG00000115241": "PPM1G",
626
+ "ENSG00000115268": "RPS15",
627
+ "ENSG00000115306": "SPTBN1",
628
+ "ENSG00000115310": "RTN4",
629
+ "ENSG00000115355": "CCDC88A",
630
+ "ENSG00000115464": "USP34",
631
+ "ENSG00000115484": "CCT4",
632
+ "ENSG00000115504": "EHBP1",
633
+ "ENSG00000115677": "HDLBP",
634
+ "ENSG00000115756": "HPCAL1",
635
+ "ENSG00000115760": "BIRC6",
636
+ "ENSG00000115761": "NOL10",
637
+ "ENSG00000115762": "PLEKHB2",
638
+ "ENSG00000115808": "STRN",
639
+ "ENSG00000115839": "RAB3GAP1",
640
+ "ENSG00000115840": "SLC25A12",
641
+ "ENSG00000115866": "DARS1",
642
+ "ENSG00000115896": "PLCL1",
643
+ "ENSG00000115904": "SOS1",
644
+ "ENSG00000115934": "LINC02566",
645
+ "ENSG00000115942": "ORC2",
646
+ "ENSG00000115966": "ATF2",
647
+ "ENSG00000115970": "THADA",
648
+ "ENSG00000115977": "AAK1",
649
+ "ENSG00000116017": "ARID3A",
650
+ "ENSG00000116044": "NFE2L2",
651
+ "ENSG00000116117": "PARD3B",
652
+ "ENSG00000116199": "FAM20B",
653
+ "ENSG00000116350": "SRSF4",
654
+ "ENSG00000116406": "EDEM3",
655
+ "ENSG00000116473": "RAP1A",
656
+ "ENSG00000116478": "HDAC1",
657
+ "ENSG00000116489": "CAPZA1",
658
+ "ENSG00000116497": "S100PBP",
659
+ "ENSG00000116539": "ASH1L",
660
+ "ENSG00000116560": "SFPQ",
661
+ "ENSG00000116580": "GON4L",
662
+ "ENSG00000116584": "ARHGEF2",
663
+ "ENSG00000116675": "DNAJC6",
664
+ "ENSG00000116698": "SMG7",
665
+ "ENSG00000116747": "RO60",
666
+ "ENSG00000116754": "SRSF11",
667
+ "ENSG00000116786": "PLEKHM2",
668
+ "ENSG00000116815": "CD58",
669
+ "ENSG00000116830": "TTF2",
670
+ "ENSG00000116984": "MTR",
671
+ "ENSG00000117000": "RLF",
672
+ "ENSG00000117139": "KDM5B",
673
+ "ENSG00000117298": "ECE1",
674
+ "ENSG00000117335": "CD46",
675
+ "ENSG00000117394": "SLC2A1",
676
+ "ENSG00000117523": "PRRC2C",
677
+ "ENSG00000117569": "PTBP2",
678
+ "ENSG00000117592": "PRDX6",
679
+ "ENSG00000117616": "RSRP1",
680
+ "ENSG00000117697": "NSL1",
681
+ "ENSG00000117713": "ARID1A",
682
+ "ENSG00000117724": "CENPF",
683
+ "ENSG00000117859": "OSBPL9",
684
+ "ENSG00000117868": "ESYT2",
685
+ "ENSG00000117984": "CTSD",
686
+ "ENSG00000118007": "STAG1",
687
+ "ENSG00000118058": "KMT2A",
688
+ "ENSG00000118193": "KIF14",
689
+ "ENSG00000118217": "ATF6",
690
+ "ENSG00000118260": "CREB1",
691
+ "ENSG00000118412": "CASP8AP2",
692
+ "ENSG00000118420": "UBE3D",
693
+ "ENSG00000118454": "ANKRD13C",
694
+ "ENSG00000118482": "PHF3",
695
+ "ENSG00000118513": "MYB",
696
+ "ENSG00000118689": "FOXO3",
697
+ "ENSG00000118705": "RPN2",
698
+ "ENSG00000118816": "CCNI",
699
+ "ENSG00000118873": "RAB3GAP2",
700
+ "ENSG00000118900": "UBN1",
701
+ "ENSG00000118961": "LDAH",
702
+ "ENSG00000119042": "SATB2",
703
+ "ENSG00000119048": "UBE2B",
704
+ "ENSG00000119125": "GDA",
705
+ "ENSG00000119231": "SENP5",
706
+ "ENSG00000119285": "HEATR1",
707
+ "ENSG00000119314": "PTBP3",
708
+ "ENSG00000119318": "RAD23B",
709
+ "ENSG00000119335": "SET",
710
+ "ENSG00000119471": "HSDL2",
711
+ "ENSG00000119487": "MAPKAP1",
712
+ "ENSG00000119509": "INVS",
713
+ "ENSG00000119522": "DENND1A",
714
+ "ENSG00000119715": "ESRRB",
715
+ "ENSG00000119778": "ATAD2B",
716
+ "ENSG00000119787": "ATL2",
717
+ "ENSG00000119820": "YIPF4",
718
+ "ENSG00000120071": "KANSL1",
719
+ "ENSG00000120158": "RCL1",
720
+ "ENSG00000120254": "MTHFD1L",
721
+ "ENSG00000120265": "PCMT1",
722
+ "ENSG00000120519": "SLC10A7",
723
+ "ENSG00000120616": "EPC1",
724
+ "ENSG00000120690": "ELF1",
725
+ "ENSG00000120725": "SIL1",
726
+ "ENSG00000120733": "KDM3B",
727
+ "ENSG00000120742": "SERP1",
728
+ "ENSG00000120802": "TMPO",
729
+ "ENSG00000120899": "PTK2B",
730
+ "ENSG00000120910": "PPP3CC",
731
+ "ENSG00000120992": "LYPLA1",
732
+ "ENSG00000121104": "FAM117A",
733
+ "ENSG00000121210": "TMEM131L",
734
+ "ENSG00000121741": "ZMYM2",
735
+ "ENSG00000121774": "KHDRBS1",
736
+ "ENSG00000121879": "PIK3CA",
737
+ "ENSG00000121892": "PDS5A",
738
+ "ENSG00000121988": "ZRANB3",
739
+ "ENSG00000122008": "POLK",
740
+ "ENSG00000122218": "COPA",
741
+ "ENSG00000122257": "RBBP6",
742
+ "ENSG00000122376": "SHLD2",
743
+ "ENSG00000122406": "RPL5",
744
+ "ENSG00000122482": "ZNF644",
745
+ "ENSG00000122483": "CCDC18",
746
+ "ENSG00000122484": "RPAP2",
747
+ "ENSG00000122545": "SEPTIN7",
748
+ "ENSG00000122566": "HNRNPA2B1",
749
+ "ENSG00000122643": "NT5C3A",
750
+ "ENSG00000122741": "DCAF10",
751
+ "ENSG00000122779": "TRIM24",
752
+ "ENSG00000122862": "SRGN",
753
+ "ENSG00000122884": "P4HA1",
754
+ "ENSG00000122912": "SLC25A16",
755
+ "ENSG00000122966": "CIT",
756
+ "ENSG00000123066": "MED13L",
757
+ "ENSG00000123106": "CCDC91",
758
+ "ENSG00000123146": "ADGRE5",
759
+ "ENSG00000123200": "ZC3H13",
760
+ "ENSG00000123352": "SPATS2",
761
+ "ENSG00000123416": "TUBA1B",
762
+ "ENSG00000123473": "STIL",
763
+ "ENSG00000123600": "METTL8",
764
+ "ENSG00000123636": "BAZ2B",
765
+ "ENSG00000123908": "AGO2",
766
+ "ENSG00000123983": "ACSL3",
767
+ "ENSG00000124151": "NCOA3",
768
+ "ENSG00000124177": "CHD6",
769
+ "ENSG00000124198": "ARFGEF2",
770
+ "ENSG00000124207": "CSE1L",
771
+ "ENSG00000124214": "STAU1",
772
+ "ENSG00000124486": "USP9X",
773
+ "ENSG00000124571": "XPO5",
774
+ "ENSG00000124588": "NQO2",
775
+ "ENSG00000124767": "GLO1",
776
+ "ENSG00000124782": "RREB1",
777
+ "ENSG00000124783": "SSR1",
778
+ "ENSG00000124789": "NUP153",
779
+ "ENSG00000124795": "DEK",
780
+ "ENSG00000124831": "LRRFIP1",
781
+ "ENSG00000124942": "AHNAK",
782
+ "ENSG00000125037": "EMC3",
783
+ "ENSG00000125107": "CNOT1",
784
+ "ENSG00000125257": "ABCC4",
785
+ "ENSG00000125354": "SEPTIN6",
786
+ "ENSG00000125386": "FAM193A",
787
+ "ENSG00000125505": "MBOAT7",
788
+ "ENSG00000125676": "THOC2",
789
+ "ENSG00000125691": "RPL23",
790
+ "ENSG00000125741": "OPA3",
791
+ "ENSG00000125944": "HNRNPR",
792
+ "ENSG00000125970": "RALY",
793
+ "ENSG00000125977": "EIF2S2",
794
+ "ENSG00000126070": "AGO3",
795
+ "ENSG00000126091": "ST3GAL3",
796
+ "ENSG00000126261": "UBA2",
797
+ "ENSG00000126561": "STAT5A",
798
+ "ENSG00000126602": "TRAP1",
799
+ "ENSG00000126653": "NSRP1",
800
+ "ENSG00000126777": "KTN1",
801
+ "ENSG00000126858": "RHOT1",
802
+ "ENSG00000126870": "DYNC2I1",
803
+ "ENSG00000126883": "NUP214",
804
+ "ENSG00000127022": "CANX",
805
+ "ENSG00000127314": "RAP1B",
806
+ "ENSG00000127481": "UBR4",
807
+ "ENSG00000127483": "HP1BP3",
808
+ "ENSG00000127603": "MACF1",
809
+ "ENSG00000127616": "SMARCA4",
810
+ "ENSG00000127663": "KDM4B",
811
+ "ENSG00000127914": "AKAP9",
812
+ "ENSG00000127928": "GNGT1",
813
+ "ENSG00000127946": "HIP1",
814
+ "ENSG00000127947": "PTPN12",
815
+ "ENSG00000127948": "POR",
816
+ "ENSG00000128050": "PAICS",
817
+ "ENSG00000128191": "DGCR8",
818
+ "ENSG00000128294": "TPST2",
819
+ "ENSG00000128563": "PRKRIP1",
820
+ "ENSG00000128578": "STRIP2",
821
+ "ENSG00000128585": "MKLN1",
822
+ "ENSG00000128595": "CALU",
823
+ "ENSG00000128607": "KLHDC10",
824
+ "ENSG00000128708": "HAT1",
825
+ "ENSG00000128731": "HERC2",
826
+ "ENSG00000128881": "TTBK2",
827
+ "ENSG00000128908": "INO80",
828
+ "ENSG00000128918": "ALDH1A2",
829
+ "ENSG00000128923": "MINDY2",
830
+ "ENSG00000129003": "VPS13C",
831
+ "ENSG00000129083": "COPB1",
832
+ "ENSG00000129084": "PSMA1",
833
+ "ENSG00000129351": "ILF3",
834
+ "ENSG00000129515": "SNX6",
835
+ "ENSG00000129636": "ITFG1",
836
+ "ENSG00000129682": "FGF13",
837
+ "ENSG00000129691": "ASH2L",
838
+ "ENSG00000129933": "MAU2",
839
+ "ENSG00000129993": "CBFA2T3",
840
+ "ENSG00000130164": "LDLR",
841
+ "ENSG00000130175": "PRKCSH",
842
+ "ENSG00000130202": "NECTIN2",
843
+ "ENSG00000130227": "XPO7",
844
+ "ENSG00000130338": "TULP4",
845
+ "ENSG00000130340": "SNX9",
846
+ "ENSG00000130396": "AFDN",
847
+ "ENSG00000130402": "ACTN4",
848
+ "ENSG00000130449": "ZSWIM6",
849
+ "ENSG00000130517": "PGPEP1",
850
+ "ENSG00000130560": "UBAC1",
851
+ "ENSG00000130695": "CEP85",
852
+ "ENSG00000130726": "TRIM28",
853
+ "ENSG00000130741": "EIF2S3",
854
+ "ENSG00000130766": "SESN2",
855
+ "ENSG00000130779": "CLIP1",
856
+ "ENSG00000130816": "DNMT1",
857
+ "ENSG00000130821": "SLC6A8",
858
+ "ENSG00000130939": "UBE4B",
859
+ "ENSG00000131023": "LATS1",
860
+ "ENSG00000131051": "RBM39",
861
+ "ENSG00000131069": "ACSS2",
862
+ "ENSG00000131149": "GSE1",
863
+ "ENSG00000131236": "CAP1",
864
+ "ENSG00000131368": "MRPS25",
865
+ "ENSG00000131374": "TBC1D5",
866
+ "ENSG00000131389": "SLC6A6",
867
+ "ENSG00000131504": "DIAPH1",
868
+ "ENSG00000131508": "UBE2D2",
869
+ "ENSG00000131558": "EXOC4",
870
+ "ENSG00000131591": "C1ORF159",
871
+ "ENSG00000131626": "PPFIA1",
872
+ "ENSG00000131711": "MAP1B",
873
+ "ENSG00000131725": "WDR44",
874
+ "ENSG00000131747": "TOP2A",
875
+ "ENSG00000132155": "RAF1",
876
+ "ENSG00000132182": "NUP210",
877
+ "ENSG00000132199": "ENOSF1",
878
+ "ENSG00000132204": "LINC00470",
879
+ "ENSG00000132300": "PTCD3",
880
+ "ENSG00000132305": "IMMT",
881
+ "ENSG00000132388": "UBE2G1",
882
+ "ENSG00000132405": "TBC1D14",
883
+ "ENSG00000132424": "PNISR",
884
+ "ENSG00000132466": "ANKRD17",
885
+ "ENSG00000132475": "H3-3B",
886
+ "ENSG00000132485": "ZRANB2",
887
+ "ENSG00000132549": "VPS13B",
888
+ "ENSG00000132670": "PTPRA",
889
+ "ENSG00000132676": "DAP3",
890
+ "ENSG00000132680": "KHDC4",
891
+ "ENSG00000132780": "NASP",
892
+ "ENSG00000132842": "AP3B1",
893
+ "ENSG00000132953": "XPO4",
894
+ "ENSG00000133026": "MYH10",
895
+ "ENSG00000133059": "DSTYK",
896
+ "ENSG00000133112": "TPT1",
897
+ "ENSG00000133195": "SLC39A11",
898
+ "ENSG00000133226": "SRRM1",
899
+ "ENSG00000133315": "MACROD1",
900
+ "ENSG00000133318": "RTN3",
901
+ "ENSG00000133454": "MYO18B",
902
+ "ENSG00000133612": "AGAP3",
903
+ "ENSG00000133624": "ZNF767P",
904
+ "ENSG00000133657": "ATP13A3",
905
+ "ENSG00000133706": "LARS1",
906
+ "ENSG00000133812": "SBF2",
907
+ "ENSG00000133816": "MICAL2",
908
+ "ENSG00000133858": "ZFC3H1",
909
+ "ENSG00000133961": "NUMB",
910
+ "ENSG00000134108": "ARL8B",
911
+ "ENSG00000134138": "MEIS2",
912
+ "ENSG00000134152": "KATNBL1",
913
+ "ENSG00000134243": "SORT1",
914
+ "ENSG00000134278": "SPIRE1",
915
+ "ENSG00000134283": "PPHLN1",
916
+ "ENSG00000134294": "SLC38A2",
917
+ "ENSG00000134313": "KIDINS220",
918
+ "ENSG00000134318": "ROCK2",
919
+ "ENSG00000134324": "LPIN1",
920
+ "ENSG00000134333": "LDHA",
921
+ "ENSG00000134352": "IL6ST",
922
+ "ENSG00000134369": "NAV1",
923
+ "ENSG00000134371": "CDC73",
924
+ "ENSG00000134452": "FBH1",
925
+ "ENSG00000134490": "SLC35D4",
926
+ "ENSG00000134644": "PUM1",
927
+ "ENSG00000134684": "YARS1",
928
+ "ENSG00000134744": "TUT4",
929
+ "ENSG00000134759": "ELP2",
930
+ "ENSG00000134851": "TMEM165",
931
+ "ENSG00000134852": "CLOCK",
932
+ "ENSG00000134882": "UBAC2",
933
+ "ENSG00000134982": "APC",
934
+ "ENSG00000135090": "TAOK3",
935
+ "ENSG00000135250": "SRPK2",
936
+ "ENSG00000135298": "ADGRB3",
937
+ "ENSG00000135317": "SNX14",
938
+ "ENSG00000135336": "ORC3",
939
+ "ENSG00000135365": "PHF21A",
940
+ "ENSG00000135387": "CAPRIN1",
941
+ "ENSG00000135457": "TFCP2",
942
+ "ENSG00000135486": "HNRNPA1",
943
+ "ENSG00000135541": "AHI1",
944
+ "ENSG00000135549": "PKIB",
945
+ "ENSG00000135605": "TEC",
946
+ "ENSG00000135655": "USP15",
947
+ "ENSG00000135766": "EGLN1",
948
+ "ENSG00000135821": "GLUL",
949
+ "ENSG00000135829": "DHX9",
950
+ "ENSG00000135837": "CEP350",
951
+ "ENSG00000135842": "NIBAN1",
952
+ "ENSG00000135870": "RC3H1",
953
+ "ENSG00000135932": "CAB39",
954
+ "ENSG00000135968": "GCC2",
955
+ "ENSG00000135999": "EPC2",
956
+ "ENSG00000136068": "FLNB",
957
+ "ENSG00000136167": "LCP1",
958
+ "ENSG00000136231": "IGF2BP3",
959
+ "ENSG00000136261": "BZW2",
960
+ "ENSG00000136280": "CCM2",
961
+ "ENSG00000136381": "IREB2",
962
+ "ENSG00000136448": "NMT1",
963
+ "ENSG00000136485": "DCAF7",
964
+ "ENSG00000136492": "BRIP1",
965
+ "ENSG00000136536": "MARCHF7",
966
+ "ENSG00000136542": "GALNT5",
967
+ "ENSG00000136560": "TANK",
968
+ "ENSG00000136628": "EPRS1",
969
+ "ENSG00000136643": "RPS6KC1",
970
+ "ENSG00000136709": "WDR33",
971
+ "ENSG00000136731": "UGGT1",
972
+ "ENSG00000136758": "YME1L1",
973
+ "ENSG00000136770": "DNAJC1",
974
+ "ENSG00000136813": "ECPAS",
975
+ "ENSG00000136819": "C9ORF78",
976
+ "ENSG00000136842": "TMOD1",
977
+ "ENSG00000136861": "CDK5RAP2",
978
+ "ENSG00000136868": "SLC31A1",
979
+ "ENSG00000136878": "USP20",
980
+ "ENSG00000136938": "ANP32B",
981
+ "ENSG00000136942": "RPL35",
982
+ "ENSG00000137073": "UBAP2",
983
+ "ENSG00000137074": "APTX",
984
+ "ENSG00000137075": "RNF38",
985
+ "ENSG00000137076": "TLN1",
986
+ "ENSG00000137145": "DENND4C",
987
+ "ENSG00000137154": "RPS6",
988
+ "ENSG00000137177": "KIF13A",
989
+ "ENSG00000137198": "GMPR",
990
+ "ENSG00000137309": "HMGA1",
991
+ "ENSG00000137478": "FCHSD2",
992
+ "ENSG00000137491": "SLCO2B1",
993
+ "ENSG00000137513": "NARS2",
994
+ "ENSG00000137601": "NEK1",
995
+ "ENSG00000137710": "RDX",
996
+ "ENSG00000137764": "MAP2K5",
997
+ "ENSG00000137770": "CTDSPL2",
998
+ "ENSG00000137776": "SLTM",
999
+ "ENSG00000137804": "NUSAP1",
1000
+ "ENSG00000137812": "KNL1",
1001
+ "ENSG00000137818": "RPLP1",
1002
+ "ENSG00000137845": "ADAM10",
1003
+ "ENSG00000137968": "SLC44A5",
1004
+ "ENSG00000138018": "SELENOI",
1005
+ "ENSG00000138029": "HADHB",
1006
+ "ENSG00000138069": "RAB1A",
1007
+ "ENSG00000138071": "ACTR2",
1008
+ "ENSG00000138081": "FBXO11",
1009
+ "ENSG00000138095": "LRPPRC",
1010
+ "ENSG00000138182": "KIF20B",
1011
+ "ENSG00000138190": "EXOC6",
1012
+ "ENSG00000138303": "ASCC1",
1013
+ "ENSG00000138316": "ADAMTS14",
1014
+ "ENSG00000138326": "RPS24",
1015
+ "ENSG00000138336": "TET1",
1016
+ "ENSG00000138346": "DNA2",
1017
+ "ENSG00000138398": "PPIG",
1018
+ "ENSG00000138399": "FASTKD1",
1019
+ "ENSG00000138430": "OLA1",
1020
+ "ENSG00000138592": "USP8",
1021
+ "ENSG00000138594": "TMOD3",
1022
+ "ENSG00000138600": "SPPL2A",
1023
+ "ENSG00000138639": "ARHGAP24",
1024
+ "ENSG00000138640": "FAM13A",
1025
+ "ENSG00000138668": "HNRNPD",
1026
+ "ENSG00000138674": "SEC31A",
1027
+ "ENSG00000138709": "LARP1B",
1028
+ "ENSG00000138756": "BMP2K",
1029
+ "ENSG00000138757": "G3BP2",
1030
+ "ENSG00000138758": "SEPTIN11",
1031
+ "ENSG00000138768": "USO1",
1032
+ "ENSG00000138778": "CENPE",
1033
+ "ENSG00000138802": "SEC24B",
1034
+ "ENSG00000138814": "PPP3CA",
1035
+ "ENSG00000139083": "ETV6",
1036
+ "ENSG00000139116": "KIF21A",
1037
+ "ENSG00000139163": "ETNK1",
1038
+ "ENSG00000139218": "SCAF11",
1039
+ "ENSG00000139613": "SMARCC2",
1040
+ "ENSG00000139641": "ESYT1",
1041
+ "ENSG00000139644": "TMBIM6",
1042
+ "ENSG00000139668": "WDFY2",
1043
+ "ENSG00000139697": "SBNO1",
1044
+ "ENSG00000139734": "DIAPH3",
1045
+ "ENSG00000139746": "RBM26",
1046
+ "ENSG00000139793": "MBNL2",
1047
+ "ENSG00000140022": "STON2",
1048
+ "ENSG00000140105": "WARS1",
1049
+ "ENSG00000140262": "TCF12",
1050
+ "ENSG00000140350": "ANP32A",
1051
+ "ENSG00000140374": "ETFA",
1052
+ "ENSG00000140396": "NCOA2",
1053
+ "ENSG00000140455": "USP3",
1054
+ "ENSG00000140479": "PCSK6",
1055
+ "ENSG00000140525": "FANCI",
1056
+ "ENSG00000140526": "ABHD2",
1057
+ "ENSG00000140545": "MFGE8",
1058
+ "ENSG00000140575": "IQGAP1",
1059
+ "ENSG00000140612": "SEC11A",
1060
+ "ENSG00000140632": "GLYR1",
1061
+ "ENSG00000140694": "PARN",
1062
+ "ENSG00000140718": "FTO",
1063
+ "ENSG00000140743": "CDR2",
1064
+ "ENSG00000140988": "RPS2",
1065
+ "ENSG00000141002": "TCF25",
1066
+ "ENSG00000141027": "NCOR1",
1067
+ "ENSG00000141068": "KSR1",
1068
+ "ENSG00000141084": "RANBP10",
1069
+ "ENSG00000141252": "VPS53",
1070
+ "ENSG00000141279": "NPEPPS",
1071
+ "ENSG00000141298": "SSH2",
1072
+ "ENSG00000141367": "CLTC",
1073
+ "ENSG00000141376": "BCAS3",
1074
+ "ENSG00000141425": "RPRD1A",
1075
+ "ENSG00000141524": "TMC6",
1076
+ "ENSG00000141556": "TBCD",
1077
+ "ENSG00000141562": "NARF",
1078
+ "ENSG00000141564": "RPTOR",
1079
+ "ENSG00000141568": "FOXK2",
1080
+ "ENSG00000141576": "RNF157",
1081
+ "ENSG00000141627": "DYM",
1082
+ "ENSG00000141867": "BRD4",
1083
+ "ENSG00000141905": "NFIC",
1084
+ "ENSG00000142207": "URB1",
1085
+ "ENSG00000142230": "SAE1",
1086
+ "ENSG00000142534": "RPS11",
1087
+ "ENSG00000142541": "RPL13A",
1088
+ "ENSG00000142599": "RERE",
1089
+ "ENSG00000142655": "PEX14",
1090
+ "ENSG00000142657": "PGD",
1091
+ "ENSG00000142676": "RPL11",
1092
+ "ENSG00000142687": "KIAA0319L",
1093
+ "ENSG00000142798": "HSPG2",
1094
+ "ENSG00000142864": "SERBP1",
1095
+ "ENSG00000142937": "RPS8",
1096
+ "ENSG00000142945": "KIF2C",
1097
+ "ENSG00000143033": "MTF2",
1098
+ "ENSG00000143106": "PSMA5",
1099
+ "ENSG00000143164": "DCAF6",
1100
+ "ENSG00000143190": "POU2F1",
1101
+ "ENSG00000143207": "COP1",
1102
+ "ENSG00000143322": "ABL2",
1103
+ "ENSG00000143324": "XPR1",
1104
+ "ENSG00000143420": "ENSA",
1105
+ "ENSG00000143442": "POGZ",
1106
+ "ENSG00000143476": "DTL",
1107
+ "ENSG00000143493": "INTS7",
1108
+ "ENSG00000143549": "TPM3",
1109
+ "ENSG00000143614": "GATAD2B",
1110
+ "ENSG00000143641": "GALNT2",
1111
+ "ENSG00000143702": "CEP170",
1112
+ "ENSG00000143748": "NVL",
1113
+ "ENSG00000143756": "FBXO28",
1114
+ "ENSG00000143761": "ARF1",
1115
+ "ENSG00000143776": "CDC42BPA",
1116
+ "ENSG00000143797": "MBOAT2",
1117
+ "ENSG00000143815": "LBR",
1118
+ "ENSG00000143851": "PTPN7",
1119
+ "ENSG00000143870": "PDIA6",
1120
+ "ENSG00000143919": "CAMKMT",
1121
+ "ENSG00000143924": "EML4",
1122
+ "ENSG00000143951": "WDPCP",
1123
+ "ENSG00000143952": "VPS54",
1124
+ "ENSG00000143970": "ASXL2",
1125
+ "ENSG00000144036": "EXOC6B",
1126
+ "ENSG00000144040": "SFXN5",
1127
+ "ENSG00000144224": "UBXN4",
1128
+ "ENSG00000144283": "PKP4",
1129
+ "ENSG00000144320": "LNPK",
1130
+ "ENSG00000144357": "UBR3",
1131
+ "ENSG00000144381": "HSPD1",
1132
+ "ENSG00000144407": "PTH2R",
1133
+ "ENSG00000144426": "NBEAL1",
1134
+ "ENSG00000144455": "SUMF1",
1135
+ "ENSG00000144554": "FANCD2",
1136
+ "ENSG00000144566": "RAB5A",
1137
+ "ENSG00000144674": "GOLGA4",
1138
+ "ENSG00000144713": "RPL32",
1139
+ "ENSG00000144791": "LIMD1",
1140
+ "ENSG00000145348": "TBCK",
1141
+ "ENSG00000145375": "AFG2A",
1142
+ "ENSG00000145495": "MARCHF6",
1143
+ "ENSG00000145592": "RPL37",
1144
+ "ENSG00000145687": "SSBP2",
1145
+ "ENSG00000145703": "IQGAP2",
1146
+ "ENSG00000145715": "RASA1",
1147
+ "ENSG00000145725": "PPIP5K2",
1148
+ "ENSG00000145734": "BDP1",
1149
+ "ENSG00000145740": "SLC30A5",
1150
+ "ENSG00000145743": "FBXL17",
1151
+ "ENSG00000145779": "TNFAIP8",
1152
+ "ENSG00000145781": "COMMD10",
1153
+ "ENSG00000145833": "DDX46",
1154
+ "ENSG00000145907": "G3BP1",
1155
+ "ENSG00000145982": "FARS2",
1156
+ "ENSG00000145990": "GFOD1",
1157
+ "ENSG00000145996": "CDKAL1",
1158
+ "ENSG00000146143": "PRIM2",
1159
+ "ENSG00000146223": "RPL7L1",
1160
+ "ENSG00000146247": "PHIP",
1161
+ "ENSG00000146263": "MMS22L",
1162
+ "ENSG00000146373": "RNF217",
1163
+ "ENSG00000146376": "ARHGAP18",
1164
+ "ENSG00000146414": "SHPRH",
1165
+ "ENSG00000146416": "AIG1",
1166
+ "ENSG00000146426": "TIAM2",
1167
+ "ENSG00000146433": "TMEM181",
1168
+ "ENSG00000146463": "ZMYM4",
1169
+ "ENSG00000146530": "VWDE",
1170
+ "ENSG00000146776": "ATXN7L1",
1171
+ "ENSG00000146842": "TMEM209",
1172
+ "ENSG00000146872": "TLK2",
1173
+ "ENSG00000146918": "NCAPG2",
1174
+ "ENSG00000147050": "KDM6A",
1175
+ "ENSG00000147065": "MSN",
1176
+ "ENSG00000147099": "HDAC8",
1177
+ "ENSG00000147133": "TAF1",
1178
+ "ENSG00000147162": "OGT",
1179
+ "ENSG00000147251": "DOCK11",
1180
+ "ENSG00000147274": "RBMX",
1181
+ "ENSG00000147316": "MCPH1",
1182
+ "ENSG00000147403": "RPL10",
1183
+ "ENSG00000147421": "HMBOX1",
1184
+ "ENSG00000147454": "SLC25A37",
1185
+ "ENSG00000147526": "TACC1",
1186
+ "ENSG00000147548": "NSD3",
1187
+ "ENSG00000147649": "MTDH",
1188
+ "ENSG00000147650": "LRP12",
1189
+ "ENSG00000147677": "EIF3H",
1190
+ "ENSG00000147689": "SACK1A",
1191
+ "ENSG00000147905": "ZCCHC7",
1192
+ "ENSG00000148120": "AOPEP",
1193
+ "ENSG00000148200": "NR6A1",
1194
+ "ENSG00000148303": "RPL7A",
1195
+ "ENSG00000148358": "GPR107",
1196
+ "ENSG00000148429": "USP6NL",
1197
+ "ENSG00000148488": "ST8SIA6",
1198
+ "ENSG00000148498": "PARD3",
1199
+ "ENSG00000148634": "HERC4",
1200
+ "ENSG00000148700": "ADD3",
1201
+ "ENSG00000148773": "MKI67",
1202
+ "ENSG00000148842": "CNNM2",
1203
+ "ENSG00000148843": "PDCD11",
1204
+ "ENSG00000148950": "IMMP1L",
1205
+ "ENSG00000149177": "PTPRJ",
1206
+ "ENSG00000149179": "CSTPP1",
1207
+ "ENSG00000149187": "CELF1",
1208
+ "ENSG00000149262": "INTS4",
1209
+ "ENSG00000149273": "RPS3",
1210
+ "ENSG00000149308": "NPAT",
1211
+ "ENSG00000149311": "ATM",
1212
+ "ENSG00000149485": "FADS1",
1213
+ "ENSG00000149639": "MTCL2",
1214
+ "ENSG00000149806": "FAU",
1215
+ "ENSG00000149925": "ALDOA",
1216
+ "ENSG00000150093": "ITGB1",
1217
+ "ENSG00000150477": "KIAA1328",
1218
+ "ENSG00000150867": "PIP4K2A",
1219
+ "ENSG00000150961": "SEC24D",
1220
+ "ENSG00000150991": "UBC",
1221
+ "ENSG00000150995": "ITPR1",
1222
+ "ENSG00000151012": "SLC7A11",
1223
+ "ENSG00000151090": "THRB",
1224
+ "ENSG00000151092": "NGLY1",
1225
+ "ENSG00000151150": "ANK3",
1226
+ "ENSG00000151208": "DLG5",
1227
+ "ENSG00000151229": "SLC2A13",
1228
+ "ENSG00000151247": "EIF4E",
1229
+ "ENSG00000151276": "MAGI1",
1230
+ "ENSG00000151338": "MIPOL1",
1231
+ "ENSG00000151414": "NEK7",
1232
+ "ENSG00000151422": "FER",
1233
+ "ENSG00000151461": "UPF2",
1234
+ "ENSG00000151466": "SCLT1",
1235
+ "ENSG00000151532": "VTI1A",
1236
+ "ENSG00000151694": "ADAM17",
1237
+ "ENSG00000151718": "WWC2",
1238
+ "ENSG00000151746": "BICD1",
1239
+ "ENSG00000151779": "NBAS",
1240
+ "ENSG00000151914": "DST",
1241
+ "ENSG00000152061": "RABGAP1L",
1242
+ "ENSG00000152102": "FAM168B",
1243
+ "ENSG00000152127": "MGAT5",
1244
+ "ENSG00000152256": "PDK1",
1245
+ "ENSG00000152270": "PDE3B",
1246
+ "ENSG00000152291": "TGOLN2",
1247
+ "ENSG00000152348": "ATG10",
1248
+ "ENSG00000152520": "PAN3",
1249
+ "ENSG00000152601": "MBNL1",
1250
+ "ENSG00000152818": "UTRN",
1251
+ "ENSG00000153046": "CDYL",
1252
+ "ENSG00000153113": "CAST",
1253
+ "ENSG00000153179": "RASSF3",
1254
+ "ENSG00000153187": "HNRNPU",
1255
+ "ENSG00000153201": "RANBP2",
1256
+ "ENSG00000153207": "AHCTF1",
1257
+ "ENSG00000153310": "CYRIB",
1258
+ "ENSG00000153317": "ASAP1",
1259
+ "ENSG00000153339": "TRAPPC8",
1260
+ "ENSG00000153721": "CNKSR3",
1261
+ "ENSG00000153774": "CFDP1",
1262
+ "ENSG00000153815": "CMIP",
1263
+ "ENSG00000153827": "TRIP12",
1264
+ "ENSG00000153922": "CHD1",
1265
+ "ENSG00000153936": "HS2ST1",
1266
+ "ENSG00000153944": "MSI2",
1267
+ "ENSG00000153976": "HS3ST3A1",
1268
+ "ENSG00000154001": "PPP2R5E",
1269
+ "ENSG00000154188": "ANGPT1",
1270
+ "ENSG00000154229": "PRKCA",
1271
+ "ENSG00000154269": "ENPP3",
1272
+ "ENSG00000154310": "TNIK",
1273
+ "ENSG00000154654": "NCAM2",
1274
+ "ENSG00000154743": "TSEN2",
1275
+ "ENSG00000154845": "PPP4R1",
1276
+ "ENSG00000155111": "CDK19",
1277
+ "ENSG00000155307": "SAMSN1",
1278
+ "ENSG00000155313": "USP25",
1279
+ "ENSG00000155380": "SLC16A1",
1280
+ "ENSG00000155506": "LARP1",
1281
+ "ENSG00000155561": "NUP205",
1282
+ "ENSG00000155660": "PDIA4",
1283
+ "ENSG00000155846": "PPARGC1B",
1284
+ "ENSG00000156026": "MCU",
1285
+ "ENSG00000156052": "GNAQ",
1286
+ "ENSG00000156110": "ADK",
1287
+ "ENSG00000156140": "ADAMTS3",
1288
+ "ENSG00000156206": "CFAP161",
1289
+ "ENSG00000156273": "BACH1",
1290
+ "ENSG00000156304": "SCAF4",
1291
+ "ENSG00000156482": "RPL30",
1292
+ "ENSG00000156515": "HK1",
1293
+ "ENSG00000156639": "ZFAND3",
1294
+ "ENSG00000156650": "KAT6B",
1295
+ "ENSG00000156671": "SAMD8",
1296
+ "ENSG00000156675": "RAB11FIP1",
1297
+ "ENSG00000156802": "ATAD2",
1298
+ "ENSG00000156831": "NSMCE2",
1299
+ "ENSG00000156931": "VPS8",
1300
+ "ENSG00000156958": "GALK2",
1301
+ "ENSG00000157077": "ZFYVE9",
1302
+ "ENSG00000157106": "SMG1",
1303
+ "ENSG00000157216": "SSBP3",
1304
+ "ENSG00000157350": "ST3GAL2",
1305
+ "ENSG00000157450": "RNF111",
1306
+ "ENSG00000157540": "DYRK1A",
1307
+ "ENSG00000157600": "TMEM164",
1308
+ "ENSG00000157741": "UBN2",
1309
+ "ENSG00000157764": "BRAF",
1310
+ "ENSG00000157837": "SPPL3",
1311
+ "ENSG00000157985": "AGAP1",
1312
+ "ENSG00000158019": "BABAM2",
1313
+ "ENSG00000158161": "EYA3",
1314
+ "ENSG00000158169": "FANCC",
1315
+ "ENSG00000158195": "WASF2",
1316
+ "ENSG00000158201": "ABHD3",
1317
+ "ENSG00000158417": "EIF5B",
1318
+ "ENSG00000158467": "AHCYL2",
1319
+ "ENSG00000158470": "B4GALT5",
1320
+ "ENSG00000158636": "EMSY",
1321
+ "ENSG00000158710": "TAGLN2",
1322
+ "ENSG00000158985": "CDC42SE2",
1323
+ "ENSG00000159023": "EPB41",
1324
+ "ENSG00000159131": "GART",
1325
+ "ENSG00000159140": "SON",
1326
+ "ENSG00000159216": "RUNX1",
1327
+ "ENSG00000159217": "IGF2BP1",
1328
+ "ENSG00000159256": "MORC3",
1329
+ "ENSG00000159267": "HLCS",
1330
+ "ENSG00000159459": "UBR1",
1331
+ "ENSG00000159592": "GPBP1L1",
1332
+ "ENSG00000159733": "ZFYVE28",
1333
+ "ENSG00000160007": "ARHGAP35",
1334
+ "ENSG00000160049": "DFFA",
1335
+ "ENSG00000160194": "NDUFV3",
1336
+ "ENSG00000160211": "G6PD",
1337
+ "ENSG00000160216": "AGPAT3",
1338
+ "ENSG00000160218": "TRAPPC10",
1339
+ "ENSG00000160285": "LSS",
1340
+ "ENSG00000160294": "MCM3AP",
1341
+ "ENSG00000160299": "PCNT",
1342
+ "ENSG00000160305": "DIP2A",
1343
+ "ENSG00000160551": "TAOK1",
1344
+ "ENSG00000160563": "MED27",
1345
+ "ENSG00000160584": "SIK3",
1346
+ "ENSG00000160633": "SAFB",
1347
+ "ENSG00000160746": "ANO10",
1348
+ "ENSG00000160752": "FDPS",
1349
+ "ENSG00000160789": "LMNA",
1350
+ "ENSG00000160799": "CCDC12",
1351
+ "ENSG00000160991": "ORAI2",
1352
+ "ENSG00000161011": "SQSTM1",
1353
+ "ENSG00000161016": "RPL8",
1354
+ "ENSG00000161040": "FBXL13",
1355
+ "ENSG00000161638": "ITGA5",
1356
+ "ENSG00000161813": "LARP4",
1357
+ "ENSG00000162039": "MEIOB",
1358
+ "ENSG00000162378": "ZYG11B",
1359
+ "ENSG00000162402": "USP24",
1360
+ "ENSG00000162408": "NOL9",
1361
+ "ENSG00000162434": "JAK1",
1362
+ "ENSG00000162521": "RBBP4",
1363
+ "ENSG00000162599": "NFIA",
1364
+ "ENSG00000162852": "CNST",
1365
+ "ENSG00000162909": "CAPN2",
1366
+ "ENSG00000162923": "WDR26",
1367
+ "ENSG00000162980": "ARL5A",
1368
+ "ENSG00000163006": "CCDC138",
1369
+ "ENSG00000163029": "SMC6",
1370
+ "ENSG00000163110": "PDLIM5",
1371
+ "ENSG00000163125": "RPRD2",
1372
+ "ENSG00000163162": "RNF149",
1373
+ "ENSG00000163297": "ANTXR2",
1374
+ "ENSG00000163399": "ATP1A1",
1375
+ "ENSG00000163468": "CCT3",
1376
+ "ENSG00000163479": "SSR2",
1377
+ "ENSG00000163527": "STT3B",
1378
+ "ENSG00000163539": "CLASP2",
1379
+ "ENSG00000163558": "PRKCI",
1380
+ "ENSG00000163602": "RYBP",
1381
+ "ENSG00000163655": "GMPS",
1382
+ "ENSG00000163681": "SLMAP",
1383
+ "ENSG00000163714": "U2SURP",
1384
+ "ENSG00000163811": "WDR43",
1385
+ "ENSG00000163814": "CDCP1",
1386
+ "ENSG00000163848": "ZNF148",
1387
+ "ENSG00000163872": "YEATS2",
1388
+ "ENSG00000163939": "PBRM1",
1389
+ "ENSG00000163960": "UBXN7",
1390
+ "ENSG00000163961": "RNF168",
1391
+ "ENSG00000164074": "ABHD18",
1392
+ "ENSG00000164134": "NAA15",
1393
+ "ENSG00000164190": "NIPBL",
1394
+ "ENSG00000164199": "ADGRV1",
1395
+ "ENSG00000164237": "CMBL",
1396
+ "ENSG00000164292": "RHOBTB3",
1397
+ "ENSG00000164327": "RICTOR",
1398
+ "ENSG00000164329": "TENT2",
1399
+ "ENSG00000164466": "SFXN1",
1400
+ "ENSG00000164494": "PDSS2",
1401
+ "ENSG00000164506": "STXBP5",
1402
+ "ENSG00000164548": "TRA2A",
1403
+ "ENSG00000164574": "GALNT10",
1404
+ "ENSG00000164587": "RPS14",
1405
+ "ENSG00000164597": "COG5",
1406
+ "ENSG00000164659": "ELAPOR2",
1407
+ "ENSG00000164715": "LMTK2",
1408
+ "ENSG00000164733": "CTSB",
1409
+ "ENSG00000164808": "SPIDR",
1410
+ "ENSG00000164916": "FOXK1",
1411
+ "ENSG00000164924": "YWHAZ",
1412
+ "ENSG00000164944": "VIRMA",
1413
+ "ENSG00000165185": "KIAA1958",
1414
+ "ENSG00000165209": "STRBP",
1415
+ "ENSG00000165219": "GAPVD1",
1416
+ "ENSG00000165280": "VCP",
1417
+ "ENSG00000165322": "ARHGAP12",
1418
+ "ENSG00000165392": "WRN",
1419
+ "ENSG00000165476": "REEP3",
1420
+ "ENSG00000165525": "NEMF",
1421
+ "ENSG00000165632": "TAF3",
1422
+ "ENSG00000165650": "PDZD8",
1423
+ "ENSG00000165671": "NSD1",
1424
+ "ENSG00000165675": "ENOX2",
1425
+ "ENSG00000165732": "DDX21",
1426
+ "ENSG00000165914": "TTC7B",
1427
+ "ENSG00000166128": "RAB8B",
1428
+ "ENSG00000166233": "ARIH1",
1429
+ "ENSG00000166266": "CUL5",
1430
+ "ENSG00000166295": "ANAPC16",
1431
+ "ENSG00000166326": "TRIM44",
1432
+ "ENSG00000166435": "XRRA1",
1433
+ "ENSG00000166441": "RPL27A",
1434
+ "ENSG00000166471": "TMEM41B",
1435
+ "ENSG00000166501": "PRKCB",
1436
+ "ENSG00000166575": "TMEM135",
1437
+ "ENSG00000166598": "HSP90B1",
1438
+ "ENSG00000166669": "ATF7IP2",
1439
+ "ENSG00000166734": "GOLM2",
1440
+ "ENSG00000166747": "AP1G1",
1441
+ "ENSG00000166794": "PPIB",
1442
+ "ENSG00000166913": "YWHAB",
1443
+ "ENSG00000166949": "SMAD3",
1444
+ "ENSG00000167004": "PDIA3",
1445
+ "ENSG00000167110": "GOLGA2",
1446
+ "ENSG00000167193": "CRK",
1447
+ "ENSG00000167258": "CDK12",
1448
+ "ENSG00000167323": "STIM1",
1449
+ "ENSG00000167460": "TPM4",
1450
+ "ENSG00000167491": "GATAD2A",
1451
+ "ENSG00000167522": "ANKRD11",
1452
+ "ENSG00000167526": "RPL13",
1453
+ "ENSG00000167632": "TRAPPC9",
1454
+ "ENSG00000167635": "ZNF146",
1455
+ "ENSG00000167645": "YIF1B",
1456
+ "ENSG00000167658": "EEF2",
1457
+ "ENSG00000167766": "ZNF83",
1458
+ "ENSG00000167972": "ABCA3",
1459
+ "ENSG00000167978": "SRRM2",
1460
+ "ENSG00000167996": "FTH1",
1461
+ "ENSG00000168003": "SLC3A2",
1462
+ "ENSG00000168028": "RPSA",
1463
+ "ENSG00000168036": "CTNNB1",
1464
+ "ENSG00000168092": "PAFAH1B2",
1465
+ "ENSG00000168137": "SETD5",
1466
+ "ENSG00000168172": "HOOK3",
1467
+ "ENSG00000168214": "RBPJ",
1468
+ "ENSG00000168259": "DNAJC7",
1469
+ "ENSG00000168385": "SEPTIN2",
1470
+ "ENSG00000168411": "RFWD3",
1471
+ "ENSG00000168421": "RHOH",
1472
+ "ENSG00000168461": "RAB31",
1473
+ "ENSG00000168575": "SLC20A2",
1474
+ "ENSG00000168610": "STAT3",
1475
+ "ENSG00000168710": "AHCYL1",
1476
+ "ENSG00000168754": "FAM178B",
1477
+ "ENSG00000169032": "MAP2K1",
1478
+ "ENSG00000169057": "MECP2",
1479
+ "ENSG00000169071": "ROR2",
1480
+ "ENSG00000169180": "XPO6",
1481
+ "ENSG00000169372": "CRADD",
1482
+ "ENSG00000169398": "PTK2",
1483
+ "ENSG00000169432": "SCN9A",
1484
+ "ENSG00000169504": "CLIC4",
1485
+ "ENSG00000169519": "METTL15",
1486
+ "ENSG00000169554": "ZEB2",
1487
+ "ENSG00000169635": "HIC2",
1488
+ "ENSG00000169679": "BUB1",
1489
+ "ENSG00000169710": "FASN",
1490
+ "ENSG00000169756": "LIMS1",
1491
+ "ENSG00000169813": "HNRNPF",
1492
+ "ENSG00000169871": "TRIM56",
1493
+ "ENSG00000169905": "TOR1AIP2",
1494
+ "ENSG00000169946": "ZFPM2",
1495
+ "ENSG00000169967": "MAP3K2",
1496
+ "ENSG00000170027": "YWHAG",
1497
+ "ENSG00000170142": "UBE2E1",
1498
+ "ENSG00000170144": "HNRNPA3",
1499
+ "ENSG00000170145": "SIK2",
1500
+ "ENSG00000170242": "USP47",
1501
+ "ENSG00000170248": "PDCD6IP",
1502
+ "ENSG00000170315": "UBB",
1503
+ "ENSG00000170421": "KRT8",
1504
+ "ENSG00000170515": "PA2G4",
1505
+ "ENSG00000170522": "ELOVL6",
1506
+ "ENSG00000170606": "HSPA4",
1507
+ "ENSG00000170634": "ACYP2",
1508
+ "ENSG00000170734": "POLH",
1509
+ "ENSG00000170759": "KIF5B",
1510
+ "ENSG00000170832": "USP32",
1511
+ "ENSG00000170871": "KIAA0232",
1512
+ "ENSG00000170889": "RPS9",
1513
+ "ENSG00000170921": "TANC2",
1514
+ "ENSG00000171310": "CHST11",
1515
+ "ENSG00000171316": "CHD7",
1516
+ "ENSG00000171345": "KRT19",
1517
+ "ENSG00000171456": "ASXL1",
1518
+ "ENSG00000171490": "RSL1D1",
1519
+ "ENSG00000171530": "TBCA",
1520
+ "ENSG00000171552": "BCL2L1",
1521
+ "ENSG00000171634": "BPTF",
1522
+ "ENSG00000171723": "GPHN",
1523
+ "ENSG00000171735": "CAMTA1",
1524
+ "ENSG00000171853": "TRAPPC12",
1525
+ "ENSG00000171858": "RPS21",
1526
+ "ENSG00000171988": "JMJD1C",
1527
+ "ENSG00000172262": "ZBTB35",
1528
+ "ENSG00000172270": "BSG",
1529
+ "ENSG00000172292": "CERS6",
1530
+ "ENSG00000172340": "SUCLG2",
1531
+ "ENSG00000172493": "AFF1",
1532
+ "ENSG00000172534": "HCFC1",
1533
+ "ENSG00000172613": "RAD9A",
1534
+ "ENSG00000172757": "CFL1",
1535
+ "ENSG00000172765": "TMCC1",
1536
+ "ENSG00000172795": "DCP2",
1537
+ "ENSG00000172809": "RPL38",
1538
+ "ENSG00000172845": "SP3",
1539
+ "ENSG00000172869": "DMXL1",
1540
+ "ENSG00000172893": "DHCR7",
1541
+ "ENSG00000172954": "LCLAT1",
1542
+ "ENSG00000172965": "MIR4435-2HG",
1543
+ "ENSG00000172967": "XKR3",
1544
+ "ENSG00000172992": "DCAKD",
1545
+ "ENSG00000173064": "HECTD4",
1546
+ "ENSG00000173065": "FAM222B",
1547
+ "ENSG00000173120": "KDM2A",
1548
+ "ENSG00000173163": "COMMD1",
1549
+ "ENSG00000173230": "GOLGB1",
1550
+ "ENSG00000173273": "TNKS",
1551
+ "ENSG00000173473": "SMARCC1",
1552
+ "ENSG00000173517": "PEAK1",
1553
+ "ENSG00000173542": "MOB1B",
1554
+ "ENSG00000173575": "CHD2",
1555
+ "ENSG00000173611": "SCAI",
1556
+ "ENSG00000173660": "UQCRH",
1557
+ "ENSG00000173692": "PSMD1",
1558
+ "ENSG00000173715": "TOP6BL",
1559
+ "ENSG00000173726": "TOMM20",
1560
+ "ENSG00000173727": "FAUP4",
1561
+ "ENSG00000173744": "AGFG1",
1562
+ "ENSG00000173757": "STAT5B",
1563
+ "ENSG00000173821": "RNF213",
1564
+ "ENSG00000173889": "PHC3",
1565
+ "ENSG00000173926": "MARCHF3",
1566
+ "ENSG00000173960": "UBXN2A",
1567
+ "ENSG00000174197": "MGA",
1568
+ "ENSG00000174231": "PRPF8",
1569
+ "ENSG00000174437": "ATP2A2",
1570
+ "ENSG00000174444": "RPL4",
1571
+ "ENSG00000174469": "CNTNAP2",
1572
+ "ENSG00000174485": "DENND4A",
1573
+ "ENSG00000174574": "AKIRIN1",
1574
+ "ENSG00000174718": "RESF1",
1575
+ "ENSG00000174748": "RPL15",
1576
+ "ENSG00000174780": "SRP72",
1577
+ "ENSG00000174891": "RSRC1",
1578
+ "ENSG00000175029": "CTBP2",
1579
+ "ENSG00000175048": "ZDHHC14",
1580
+ "ENSG00000175054": "ATR",
1581
+ "ENSG00000175061": "SNHG29",
1582
+ "ENSG00000175115": "PACS1",
1583
+ "ENSG00000175161": "CADM2",
1584
+ "ENSG00000175164": "ABO",
1585
+ "ENSG00000175175": "PPM1E",
1586
+ "ENSG00000175198": "PCCA",
1587
+ "ENSG00000175216": "CKAP5",
1588
+ "ENSG00000175582": "RAB6A",
1589
+ "ENSG00000175727": "MLXIP",
1590
+ "ENSG00000176014": "TUBB6",
1591
+ "ENSG00000176095": "IP6K1",
1592
+ "ENSG00000176105": "YES1",
1593
+ "ENSG00000176124": "DLEU1",
1594
+ "ENSG00000176155": "CCDC57",
1595
+ "ENSG00000176208": "ATAD5",
1596
+ "ENSG00000176261": "ZBTB8OS",
1597
+ "ENSG00000176340": "COX8A",
1598
+ "ENSG00000176407": "KCMF1",
1599
+ "ENSG00000176658": "MYO1D",
1600
+ "ENSG00000176953": "NFATC2IP",
1601
+ "ENSG00000177000": "MTHFR",
1602
+ "ENSG00000177119": "ANO6",
1603
+ "ENSG00000177156": "TALDO1",
1604
+ "ENSG00000177189": "RPS6KA3",
1605
+ "ENSG00000177200": "CHD9",
1606
+ "ENSG00000177311": "ZBTB38",
1607
+ "ENSG00000177463": "NR2C2",
1608
+ "ENSG00000177469": "CAVIN1",
1609
+ "ENSG00000177479": "ARIH2",
1610
+ "ENSG00000177565": "TBL1XR1",
1611
+ "ENSG00000177600": "RPLP2",
1612
+ "ENSG00000177853": "ZNF518A",
1613
+ "ENSG00000177885": "GRB2",
1614
+ "ENSG00000178105": "DDX10",
1615
+ "ENSG00000178177": "LCORL",
1616
+ "ENSG00000178209": "PLEC",
1617
+ "ENSG00000178234": "GALNT11",
1618
+ "ENSG00000178538": "CA8",
1619
+ "ENSG00000178691": "SUZ12",
1620
+ "ENSG00000178974": "FBXO34",
1621
+ "ENSG00000179134": "SAMD4B",
1622
+ "ENSG00000179218": "CALR",
1623
+ "ENSG00000179295": "PTPN11",
1624
+ "ENSG00000179399": "GPC5",
1625
+ "ENSG00000179406": "LINC00174",
1626
+ "ENSG00000179715": "PCED1B",
1627
+ "ENSG00000179820": "MYADM",
1628
+ "ENSG00000179912": "R3HDM2",
1629
+ "ENSG00000180098": "TRNAU1AP",
1630
+ "ENSG00000180198": "RCC1",
1631
+ "ENSG00000180263": "FGD6",
1632
+ "ENSG00000180357": "ZNF609",
1633
+ "ENSG00000180370": "PAK2",
1634
+ "ENSG00000180385": "EMC3-AS1",
1635
+ "ENSG00000180530": "NRIP1",
1636
+ "ENSG00000180573": "H2AC6",
1637
+ "ENSG00000181090": "EHMT1",
1638
+ "ENSG00000181163": "NPM1",
1639
+ "ENSG00000181555": "SETD2",
1640
+ "ENSG00000181722": "ZBTB20",
1641
+ "ENSG00000181827": "RFX7",
1642
+ "ENSG00000182095": "TNRC18",
1643
+ "ENSG00000182158": "CREB3L2",
1644
+ "ENSG00000182185": "RAD51B",
1645
+ "ENSG00000182256": "GABRG3",
1646
+ "ENSG00000182446": "NPLOC4",
1647
+ "ENSG00000182606": "TRAK1",
1648
+ "ENSG00000182621": "PLCB1",
1649
+ "ENSG00000182628": "SKA2",
1650
+ "ENSG00000182670": "TTC3",
1651
+ "ENSG00000182774": "RPS17",
1652
+ "ENSG00000182827": "ACBD3",
1653
+ "ENSG00000182899": "RPL35A",
1654
+ "ENSG00000182973": "CNOT10",
1655
+ "ENSG00000183032": "SLC25A21",
1656
+ "ENSG00000183117": "CSMD1",
1657
+ "ENSG00000183166": "CALN1",
1658
+ "ENSG00000183291": "SELENOF",
1659
+ "ENSG00000183337": "BCOR",
1660
+ "ENSG00000183431": "SF3A3",
1661
+ "ENSG00000183495": "EP400",
1662
+ "ENSG00000183530": "PRR14L",
1663
+ "ENSG00000183597": "TANGO2",
1664
+ "ENSG00000183742": "MACC1",
1665
+ "ENSG00000184007": "PTP4A2",
1666
+ "ENSG00000184009": "ACTG1",
1667
+ "ENSG00000184014": "DENND5A",
1668
+ "ENSG00000184029": "DSCR4",
1669
+ "ENSG00000184178": "SCFD2",
1670
+ "ENSG00000184220": "CMSS1",
1671
+ "ENSG00000184226": "PCDH9",
1672
+ "ENSG00000184384": "MAML2",
1673
+ "ENSG00000184445": "KNTC1",
1674
+ "ENSG00000184640": "SEPTIN9",
1675
+ "ENSG00000184787": "UBE2G2",
1676
+ "ENSG00000184838": "PRR16",
1677
+ "ENSG00000184863": "RBM33",
1678
+ "ENSG00000184903": "IMMP2L",
1679
+ "ENSG00000184992": "BRI3BP",
1680
+ "ENSG00000185033": "SEMA4B",
1681
+ "ENSG00000185104": "FAF1",
1682
+ "ENSG00000185219": "ZNF445",
1683
+ "ENSG00000185238": "PRMT3",
1684
+ "ENSG00000185305": "ARL15",
1685
+ "ENSG00000185344": "ATP6V0A2",
1686
+ "ENSG00000185420": "SMYD3",
1687
+ "ENSG00000185551": "NR2F2",
1688
+ "ENSG00000185624": "P4HB",
1689
+ "ENSG00000185651": "UBE2L3",
1690
+ "ENSG00000185658": "BRWD1",
1691
+ "ENSG00000185686": "PRAME",
1692
+ "ENSG00000185760": "KCNQ5",
1693
+ "ENSG00000185811": "IKZF1",
1694
+ "ENSG00000185842": "DNAH14",
1695
+ "ENSG00000186001": "LRCH3",
1696
+ "ENSG00000186153": "WWOX",
1697
+ "ENSG00000186187": "ZNRF1",
1698
+ "ENSG00000186260": "MRTFB",
1699
+ "ENSG00000186314": "PRELID2",
1700
+ "ENSG00000186432": "KPNA4",
1701
+ "ENSG00000186468": "RPS23",
1702
+ "ENSG00000186480": "INSIG1",
1703
+ "ENSG00000186566": "GPATCH8",
1704
+ "ENSG00000186591": "UBE2H",
1705
+ "ENSG00000186716": "BCR",
1706
+ "ENSG00000186908": "ZDHHC17",
1707
+ "ENSG00000187079": "TEAD1",
1708
+ "ENSG00000187109": "NAP1L1",
1709
+ "ENSG00000187172": "BAGE2",
1710
+ "ENSG00000187239": "FNBP1",
1711
+ "ENSG00000187257": "RSBN1L",
1712
+ "ENSG00000187605": "TET3",
1713
+ "ENSG00000187741": "FANCA",
1714
+ "ENSG00000187772": "LIN28B",
1715
+ "ENSG00000187951": "LOC100288637",
1716
+ "ENSG00000188312": "CENPP",
1717
+ "ENSG00000188342": "GTF2F2",
1718
+ "ENSG00000188511": "MIR3667HG",
1719
+ "ENSG00000188529": "SRSF10",
1720
+ "ENSG00000188735": "TMEM120B",
1721
+ "ENSG00000188846": "RPL14",
1722
+ "ENSG00000188994": "ZNF292",
1723
+ "ENSG00000189056": "RELN",
1724
+ "ENSG00000189079": "ARID2",
1725
+ "ENSG00000189091": "SF3B3",
1726
+ "ENSG00000189229": "LOC105376944",
1727
+ "ENSG00000189283": "FHIT",
1728
+ "ENSG00000189308": "LIN54",
1729
+ "ENSG00000189337": "KAZN",
1730
+ "ENSG00000196182": "STK40",
1731
+ "ENSG00000196187": "TMEM63A",
1732
+ "ENSG00000196230": "TUBB",
1733
+ "ENSG00000196233": "LCOR",
1734
+ "ENSG00000196284": "SUPT3H",
1735
+ "ENSG00000196305": "IARS1",
1736
+ "ENSG00000196312": "MFSD14CP",
1737
+ "ENSG00000196313": "POM121",
1738
+ "ENSG00000196365": "LONP1",
1739
+ "ENSG00000196367": "TRRAP",
1740
+ "ENSG00000196396": "PTPN1",
1741
+ "ENSG00000196405": "EVL",
1742
+ "ENSG00000196418": "ZNF124",
1743
+ "ENSG00000196419": "XRCC6",
1744
+ "ENSG00000196428": "TSC22D2",
1745
+ "ENSG00000196498": "NCOR2",
1746
+ "ENSG00000196504": "PRPF40A",
1747
+ "ENSG00000196565": "HBG2",
1748
+ "ENSG00000196584": "XRCC2",
1749
+ "ENSG00000196588": "MRTFA",
1750
+ "ENSG00000196628": "TCF4",
1751
+ "ENSG00000196642": "RABL6",
1752
+ "ENSG00000196705": "ZNF431",
1753
+ "ENSG00000196712": "NF1",
1754
+ "ENSG00000196715": "VKORC1L1",
1755
+ "ENSG00000196730": "DAPK1",
1756
+ "ENSG00000196792": "STRN3",
1757
+ "ENSG00000196821": "ILRUN",
1758
+ "ENSG00000196914": "ARHGEF12",
1759
+ "ENSG00000196924": "FLNA",
1760
+ "ENSG00000197081": "IGF2R",
1761
+ "ENSG00000197102": "DYNC1H1",
1762
+ "ENSG00000197147": "LRRC8B",
1763
+ "ENSG00000197157": "SND1",
1764
+ "ENSG00000197183": "NOL4L",
1765
+ "ENSG00000197312": "DDI2",
1766
+ "ENSG00000197323": "TRIM33",
1767
+ "ENSG00000197410": "DCHS2",
1768
+ "ENSG00000197442": "MAP3K5",
1769
+ "ENSG00000197471": "SPN",
1770
+ "ENSG00000197548": "ATG7",
1771
+ "ENSG00000197555": "SIPA1L1",
1772
+ "ENSG00000197721": "CR1L",
1773
+ "ENSG00000197746": "PSAP",
1774
+ "ENSG00000197756": "RPL37A",
1775
+ "ENSG00000197892": "KIF13B",
1776
+ "ENSG00000197958": "RPL12",
1777
+ "ENSG00000197965": "MPZL1",
1778
+ "ENSG00000197969": "VPS13A",
1779
+ "ENSG00000198087": "CD2AP",
1780
+ "ENSG00000198160": "MIER1",
1781
+ "ENSG00000198162": "MAN1A2",
1782
+ "ENSG00000198218": "QRICH1",
1783
+ "ENSG00000198242": "RPL23A",
1784
+ "ENSG00000198265": "HELZ",
1785
+ "ENSG00000198286": "CARD11",
1786
+ "ENSG00000198363": "ASPH",
1787
+ "ENSG00000198369": "SPRED2",
1788
+ "ENSG00000198373": "WWP2",
1789
+ "ENSG00000198380": "GFPT1",
1790
+ "ENSG00000198382": "UVRAG",
1791
+ "ENSG00000198399": "ITSN2",
1792
+ "ENSG00000198408": "OGA",
1793
+ "ENSG00000198431": "TXNRD1",
1794
+ "ENSG00000198492": "YTHDF2",
1795
+ "ENSG00000198586": "TLK1",
1796
+ "ENSG00000198589": "LRBA",
1797
+ "ENSG00000198604": "BAZ1A",
1798
+ "ENSG00000198646": "NCOA6",
1799
+ "ENSG00000198663": "C6ORF89",
1800
+ "ENSG00000198677": "SKIC3",
1801
+ "ENSG00000198695": "MT-ND6",
1802
+ "ENSG00000198700": "IPO9",
1803
+ "ENSG00000198712": "MT-CO2",
1804
+ "ENSG00000198727": "MT-CYB",
1805
+ "ENSG00000198740": "ZNF652",
1806
+ "ENSG00000198742": "SMURF1",
1807
+ "ENSG00000198755": "RPL10A",
1808
+ "ENSG00000198763": "MT-ND2",
1809
+ "ENSG00000198771": "RCSD1",
1810
+ "ENSG00000198786": "MT-ND5",
1811
+ "ENSG00000198793": "MTOR",
1812
+ "ENSG00000198804": "MT-CO1",
1813
+ "ENSG00000198815": "FOXJ3",
1814
+ "ENSG00000198836": "OPA1",
1815
+ "ENSG00000198840": "MT-ND3",
1816
+ "ENSG00000198874": "TYW1",
1817
+ "ENSG00000198879": "SFMBT2",
1818
+ "ENSG00000198886": "MT-ND4",
1819
+ "ENSG00000198888": "MT-ND1",
1820
+ "ENSG00000198898": "CAPZA2",
1821
+ "ENSG00000198899": "MT-ATP6",
1822
+ "ENSG00000198900": "TOP1",
1823
+ "ENSG00000198911": "SREBF2",
1824
+ "ENSG00000198938": "MT-CO3",
1825
+ "ENSG00000198947": "DMD",
1826
+ "ENSG00000198964": "SGMS1",
1827
+ "ENSG00000203666": "DRC8",
1828
+ "ENSG00000203867": "RBM20",
1829
+ "ENSG00000204084": "INPP5B",
1830
+ "ENSG00000204120": "GIGYF2",
1831
+ "ENSG00000204130": "RUFY2",
1832
+ "ENSG00000204138": "PHACTR4",
1833
+ "ENSG00000204178": "MACO1",
1834
+ "ENSG00000204217": "BMPR2",
1835
+ "ENSG00000204394": "VARS1",
1836
+ "ENSG00000204406": "MBD5",
1837
+ "ENSG00000204442": "NALF1",
1838
+ "ENSG00000204568": "MRPS18B",
1839
+ "ENSG00000204628": "RACK1",
1840
+ "ENSG00000204713": "TRIM27",
1841
+ "ENSG00000204842": "ATXN2",
1842
+ "ENSG00000205268": "PDE7A",
1843
+ "ENSG00000205339": "IPO7",
1844
+ "ENSG00000205531": "NAP1L4",
1845
+ "ENSG00000205628": "LINC01446",
1846
+ "ENSG00000206560": "ANKRD28",
1847
+ "ENSG00000211459": "MT-RNR1",
1848
+ "ENSG00000212907": "MT-ND4L",
1849
+ "ENSG00000213047": "DENND1B",
1850
+ "ENSG00000213079": "SCAF8",
1851
+ "ENSG00000213551": "DNAJC9",
1852
+ "ENSG00000213719": "CLIC1",
1853
+ "ENSG00000213741": "RPS29",
1854
+ "ENSG00000213931": "HBE1",
1855
+ "ENSG00000213934": "HBG1",
1856
+ "ENSG00000214113": "LYRM4",
1857
+ "ENSG00000214827": "MTCP1",
1858
+ "ENSG00000214960": "CRPPA",
1859
+ "ENSG00000215417": "MIR17HG",
1860
+ "ENSG00000215908": "CROCCP2",
1861
+ "ENSG00000221914": "PPP2R2A",
1862
+ "ENSG00000221983": "UBA52",
1863
+ "ENSG00000222041": "CYTOR",
1864
+ "ENSG00000223482": "NUTM2A-AS1",
1865
+ "ENSG00000223745": "CCDC18-AS1",
1866
+ "ENSG00000223812": "PYDC2-AS1",
1867
+ "ENSG00000224063": "CALCRL-AS1",
1868
+ "ENSG00000224141": "MIR548XHG",
1869
+ "ENSG00000224184": "MIR3681HG",
1870
+ "ENSG00000224271": "EPIC1",
1871
+ "ENSG00000224699": "LAMTOR5-AS1",
1872
+ "ENSG00000225470": "JPX",
1873
+ "ENSG00000225484": "NUTM2B-AS1",
1874
+ "ENSG00000225546": "LINC02476",
1875
+ "ENSG00000226383": "LINC01876",
1876
+ "ENSG00000226419": "SLC16A1-AS1",
1877
+ "ENSG00000226688": "ENTPD1-AS1",
1878
+ "ENSG00000226752": "CUTALP",
1879
+ "ENSG00000226985": "LINC01203",
1880
+ "ENSG00000227070": "EPS15-AS1",
1881
+ "ENSG00000227398": "KIF9-AS1",
1882
+ "ENSG00000227706": "ERVH-3",
1883
+ "ENSG00000228253": "MT-ATP8",
1884
+ "ENSG00000228782": "MRPL45P2",
1885
+ "ENSG00000229140": "CCDC26",
1886
+ "ENSG00000229180": "RABGEF1P1",
1887
+ "ENSG00000229807": "XIST",
1888
+ "ENSG00000230124": "ACBD6",
1889
+ "ENSG00000230590": "FTX",
1890
+ "ENSG00000230876": "LINC00486",
1891
+ "ENSG00000231185": "LINC01844",
1892
+ "ENSG00000231304": "SGO1-AS1",
1893
+ "ENSG00000231312": "MAP4K3-DT",
1894
+ "ENSG00000231500": "RPS18",
1895
+ "ENSG00000231607": "DLEU2",
1896
+ "ENSG00000231689": "LINC01090",
1897
+ "ENSG00000231721": "LINC-PINT",
1898
+ "ENSG00000231925": "TAPBP",
1899
+ "ENSG00000232040": "SCAND3",
1900
+ "ENSG00000232053": "LOC105375523",
1901
+ "ENSG00000233098": "CCDC144NL-AS1",
1902
+ "ENSG00000233766": "CAVIN2-AS1",
1903
+ "ENSG00000234062": "TM9SF5P",
1904
+ "ENSG00000234129": "HCCS-DT",
1905
+ "ENSG00000234722": "LINC01287",
1906
+ "ENSG00000234948": "LINC01524",
1907
+ "ENSG00000235335": "B3GALT1-AS1",
1908
+ "ENSG00000237978": "KCNMB2-AS1",
1909
+ "ENSG00000241743": "XACT",
1910
+ "ENSG00000241956": "LOC102546299",
1911
+ "ENSG00000241973": "PI4KA",
1912
+ "ENSG00000242086": "SDHAP2",
1913
+ "ENSG00000243156": "MICAL3",
1914
+ "ENSG00000244754": "N4BP2L2",
1915
+ "ENSG00000244879": "GABPB1-AS1",
1916
+ "ENSG00000245532": "NEAT1",
1917
+ "ENSG00000246067": "RAB30-DT",
1918
+ "ENSG00000247809": "NR2F2-AS1",
1919
+ "ENSG00000247828": "TMEM161B-DT",
1920
+ "ENSG00000248049": "UBA6-DT",
1921
+ "ENSG00000248131": "LINC01194",
1922
+ "ENSG00000248685": "LINC02484",
1923
+ "ENSG00000248858": "FLJ46284",
1924
+ "ENSG00000249307": "LINC01088",
1925
+ "ENSG00000249592": "PCGF3-AS1",
1926
+ "ENSG00000249859": "PVT1",
1927
+ "ENSG00000250903": "GMDS-DT",
1928
+ "ENSG00000250954": "LOC101928622",
1929
+ "ENSG00000251003": "ZFPM2-AS1",
1930
+ "ENSG00000251129": "LINC02506",
1931
+ "ENSG00000251138": "LINC02882",
1932
+ "ENSG00000251209": "LINC00923",
1933
+ "ENSG00000251381": "LINC00958",
1934
+ "ENSG00000251513": "LIX1-AS1",
1935
+ "ENSG00000251562": "MALAT1",
1936
+ "ENSG00000251574": "LOC105379109",
1937
+ "ENSG00000253394": "LINC00534",
1938
+ "ENSG00000253729": "PRKDC",
1939
+ "ENSG00000253877": "LINC01608",
1940
+ "ENSG00000254087": "LYN",
1941
+ "ENSG00000255679": "JRKL-AS1",
1942
+ "ENSG00000257103": "LSM14A",
1943
+ "ENSG00000257261": "SLC38A4-AS1",
1944
+ "ENSG00000257923": "CUX1",
1945
+ "ENSG00000258038": "LINC02327",
1946
+ "ENSG00000258667": "HIF1A-AS3",
1947
+ "ENSG00000258932": "RPS27AP4",
1948
+ "ENSG00000259240": "MIR4713HG",
1949
+ "ENSG00000259471": "LINC01169",
1950
+ "ENSG00000259692": "LINC01418",
1951
+ "ENSG00000260032": "NORAD",
1952
+ "ENSG00000261008": "LINC01572",
1953
+ "ENSG00000261609": "GAN",
1954
+ "ENSG00000263001": "GTF2I",
1955
+ "ENSG00000263711": "LINC02864",
1956
+ "ENSG00000264538": "SUZ12P1",
1957
+ "ENSG00000265491": "RNF115",
1958
+ "ENSG00000265843": "LINC01029",
1959
+ "ENSG00000265972": "TXNIP",
1960
+ "ENSG00000266412": "NCOA4",
1961
+ "ENSG00000266976": "ERVE-5",
1962
+ "ENSG00000267265": "GP6-AS1",
1963
+ "ENSG00000269821": "KCNQ1OT1",
1964
+ "ENSG00000270647": "TAF15",
1965
+ "ENSG00000272325": "NUDT3",
1966
+ "ENSG00000272391": "POM121C",
1967
+ "ENSG00000272693": "NUPR2P1",
1968
+ "ENSG00000272886": "DCP1A",
1969
+ "ENSG00000275066": "SYNRG",
1970
+ "ENSG00000276476": "LINC00540",
1971
+ "ENSG00000277149": "TYW1B",
1972
+ "ENSG00000277654": "NOP35P1",
1973
+ "ENSG00000278259": "MYO19",
1974
+ "ENSG00000278311": "GGNBP2",
1975
+ "ENSG00000278540": "ACACA",
1976
+ "ENSG00000281131": "SCHLAP1",
1977
+ "ENSG00000283117": "MGC4859"
1978
+ }
PDGrapher/data/protein/protein_features.csv ADDED
The diff for this file is too large to render. See raw diff
 
PDGrapher/data/raw/cosmic/2022-10-COSMIC/README.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # COSMIC
2
+
3
+ ## Sources
4
+ Cosmic CLP: https://cancer.sanger.ac.uk/cell_lines/download (downloaded 15th September 2022)
5
+
6
+ Curated gene list: https://cancer.sanger.ac.uk/cell_lines/curation (downloaded on 18th March 2024)
7
+
8
+ ## Date retrieved
9
+
10
+ November 15, 2022
11
+ March 18, 2024
12
+
13
+ ## Contacts
14
+
15
+ Guadalupe Gonzalez
16
+ <ggonzalezp16@gmail.com>
17
+
PDGrapher/data/raw/drugbank/2022-11-DrugBank/README.md ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DrugBank
2
+
3
+ ## Sources
4
+
5
+ https://www.drugbank.ca
6
+
7
+ See also an older version of the database with Python scripts in 2020-08-DrugBank directory.
8
+
9
+ ## References
10
+
11
+ * Wishart DS, Feunang YD, Guo AC, Lo EJ, Marcu A, Grant JR, Sajed T, Johnson D, Li C, Sayeeda Z, Assempour N. DrugBank 5.0: a major update to the DrugBank database for 2018. Nucleic acids research. 2018 Jan 4;46(D1):D1074-82.
12
+
13
+ * Wishart DS, Wu A. Using DrugBank for in silico drug exploration and discovery. Current Protocols in Bioinformatics. 2016 Jun;54(1):14-4.
14
+
15
+ * Probst D, Reymond JL. Exploring drugbank in virtual reality chemical space. Journal of chemical information and modeling. 2018 Aug 16;58(9):1731-5.
16
+
17
+ ## Date retrieved
18
+
19
+ November 4, 2022
20
+
21
+ ## Contacts
22
+
23
+ Marinka Zitnik
24
+ <marinka@hms.harvard.edu>
PDGrapher/data/raw/lincs/2022-02-LINCS_Level3/README.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # LINCS
2
+
3
+ ## Sources
4
+
5
+ https://clue.io/releases/data-dashboard
6
+ cellinfo_beta.txt
7
+ compoundinfo_beta.txt
8
+ geneinfo_beta.txt
9
+ instinfo_beta.txt
10
+ level3_beta_ctl_n188708x12328.gctx
11
+ level3_beta_trt_sh_n453175x12328.gctx
12
+ level3_beta_trt_xpr_n420583x12328.gctx
13
+
14
+ ## Date retrieved
15
+
16
+ Devember 16, 2020
17
+
18
+ ## Contacts
19
+
20
+ Guadalupe Gonzalez
21
+ <ggonzalezp16@gmail.com>
PDGrapher/data/raw/ppi/2022-03-PPI/README.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PPI
2
+
3
+ ## Sources
4
+
5
+
6
+ https://downloads.thebiogrid.org/File/BioGRID/Release-Archive/BIOGRID-4.4.207/BIOGRID-MV-Physical-4.4.207.tab3.zip
7
+
8
+ https://science.sciencemag.org/highwire/filestream/628238/field_highwire_adjunct_files/1/Datasets_S1-S4.zip
9
+
10
+ http://www.interactome-atlas.org/data/HuRI.tsv
11
+
12
+ ## Auxiliary files
13
+ hgnc2map.txt: gene identity map
14
+ geneinfo_beta.txt: gene information of C-map data used for training PDGrapher
15
+
16
+ ## References
17
+
18
+ * Stark C, Breitkreutz BJ, Reguly T, Boucher L, Breitkreutz A, Tyers M. Biogrid: A General Repository for Interaction Datasets. Nucleic Acids Res. Jan 1, 2006; 34:D535-9.
19
+
20
+ * Menche, Jörg, et al. "Uncovering disease-disease relationships through the incomplete interactome." Science 347.6224 (2015).
21
+
22
+ * Luck, Katja, et al. "A reference map of the human binary protein interactome." Nature 580.7803 (2020): 402-408.
23
+
24
+ ## Date retrieved
25
+
26
+ March 14, 2022
27
+
28
+ ## Contacts
29
+
30
+ Guadalupe Gonzalez
31
+ <ggonzalezp16@gmail.com>
PDGrapher/data/raw/ppi/2022-03-PPI/geneinfo_beta.txt ADDED
The diff for this file is too large to render. See raw diff
 
PDGrapher/data/raw/ppi/2022-03-PPI/hgnc2map.txt ADDED
The diff for this file is too large to render. See raw diff
 
PDGrapher/data/scripts/GRN/GENIE3.py ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.tree import BaseDecisionTree
2
+ from sklearn.ensemble import RandomForestRegressor, ExtraTreesRegressor
3
+ from numpy import *
4
+ import time
5
+ from operator import itemgetter
6
+ from multiprocessing import Pool
7
+
8
+
9
+ def compute_feature_importances(estimator):
10
+ if isinstance(estimator, BaseDecisionTree):
11
+ return estimator.tree_.compute_feature_importances(normalize=False)
12
+ else:
13
+ importances = [e.tree_.compute_feature_importances(normalize=False)
14
+ for e in estimator.estimators_]
15
+ importances = array(importances)
16
+ return sum(importances,axis=0) / len(estimator)
17
+
18
+
19
+
20
+ def get_link_list(VIM,gene_names=None,regulators='all',maxcount='all',file_name=None):
21
+
22
+ """Gets the ranked list of (directed) regulatory links.
23
+
24
+ Parameters
25
+ ----------
26
+
27
+ VIM: numpy array
28
+ Array as returned by the function GENIE3(), in which the element (i,j) is the score of the edge directed from the i-th gene to the j-th gene.
29
+
30
+ gene_names: list of strings, optional
31
+ List of length p, where p is the number of rows/columns in VIM, containing the names of the genes. The i-th item of gene_names must correspond to the i-th row/column of VIM. When the gene names are not provided, the i-th gene is named Gi.
32
+ default: None
33
+
34
+ regulators: list of strings, optional
35
+ List containing the names of the candidate regulators. When a list of regulators is provided, the names of all the genes must be provided (in gene_names), and the returned list contains only edges directed from the candidate regulators. When regulators is set to 'all', any gene can be a candidate regulator.
36
+ default: 'all'
37
+
38
+ maxcount: 'all' or positive integer, optional
39
+ Writes only the first maxcount regulatory links of the ranked list. When maxcount is set to 'all', all the regulatory links are written.
40
+ default: 'all'
41
+
42
+ file_name: string, optional
43
+ Writes the ranked list of regulatory links to the file file_name.
44
+ default: None
45
+
46
+
47
+
48
+ Returns
49
+ -------
50
+
51
+ The list of regulatory links, ordered according to the edge score. Auto-regulations do not appear in the list. Regulatory links with a score equal to zero are randomly permuted. In the ranked list of edges, each line has format:
52
+
53
+ regulator target gene score of edge
54
+ """
55
+
56
+ # Check input arguments
57
+ if not isinstance(VIM,ndarray):
58
+ raise ValueError('VIM must be a square array')
59
+ elif VIM.shape[0] != VIM.shape[1]:
60
+ raise ValueError('VIM must be a square array')
61
+
62
+ ngenes = VIM.shape[0]
63
+
64
+ if gene_names is not None:
65
+ if not isinstance(gene_names,(list,tuple)):
66
+ raise ValueError('input argument gene_names must be a list of gene names')
67
+ elif len(gene_names) != ngenes:
68
+ raise ValueError('input argument gene_names must be a list of length p, where p is the number of columns/genes in the expression data')
69
+
70
+ if regulators != 'all':
71
+ if not isinstance(regulators,(list,tuple)):
72
+ raise ValueError('input argument regulators must be a list of gene names')
73
+
74
+ if gene_names is None:
75
+ raise ValueError('the gene names must be specified (in input argument gene_names)')
76
+ else:
77
+ sIntersection = set(gene_names).intersection(set(regulators))
78
+ if not sIntersection:
79
+ raise ValueError('The genes must contain at least one candidate regulator')
80
+
81
+ if maxcount != 'all' and not isinstance(maxcount,int):
82
+ raise ValueError('input argument maxcount must be "all" or a positive integer')
83
+
84
+ if file_name is not None and not isinstance(file_name,str):
85
+ raise ValueError('input argument file_name must be a string')
86
+
87
+
88
+
89
+ # Get the indices of the candidate regulators
90
+ if regulators == 'all':
91
+ input_idx = range(ngenes)
92
+ else:
93
+ input_idx = [i for i, gene in enumerate(gene_names) if gene in regulators]
94
+
95
+ # Get the non-ranked list of regulatory links
96
+ vInter = [(i,j,score) for (i,j),score in ndenumerate(VIM) if i in input_idx and i!=j]
97
+
98
+ # Rank the list according to the weights of the edges
99
+ vInter_sort = sorted(vInter,key=itemgetter(2),reverse=True)
100
+ nInter = len(vInter_sort)
101
+
102
+ # Random permutation of edges with score equal to 0
103
+ flag = 1
104
+ i = 0
105
+ while flag and i < nInter:
106
+ (TF_idx,target_idx,score) = vInter_sort[i]
107
+ if score == 0:
108
+ flag = 0
109
+ else:
110
+ i += 1
111
+
112
+ if not flag:
113
+ items_perm = vInter_sort[i:]
114
+ items_perm = random.permutation(items_perm)
115
+ vInter_sort[i:] = items_perm
116
+
117
+ # Write the ranked list of edges
118
+ nToWrite = nInter
119
+ if isinstance(maxcount,int) and maxcount >= 0 and maxcount < nInter:
120
+ nToWrite = maxcount
121
+
122
+ edge_list = []
123
+ if file_name:
124
+
125
+ outfile = open(file_name,'w')
126
+
127
+ if gene_names is not None:
128
+ for i in range(nToWrite):
129
+ (TF_idx,target_idx,score) = vInter_sort[i]
130
+ TF_idx = int(TF_idx)
131
+ target_idx = int(target_idx)
132
+ outfile.write('%s\t%s\t%.6f\n' % (gene_names[TF_idx],gene_names[target_idx],score))
133
+ edge_list.append((gene_names[TF_idx],gene_names[target_idx],score))
134
+ else:
135
+ for i in range(nToWrite):
136
+ (TF_idx,target_idx,score) = vInter_sort[i]
137
+ TF_idx = int(TF_idx)
138
+ target_idx = int(target_idx)
139
+ outfile.write('G%d\tG%d\t%.6f\n' % (TF_idx+1,target_idx+1,score))
140
+ edge_list.append((TF_idx+1,target_idx+1,score))
141
+
142
+ outfile.close()
143
+
144
+ else:
145
+
146
+ if gene_names is not None:
147
+ for i in range(nToWrite):
148
+ (TF_idx,target_idx,score) = vInter_sort[i]
149
+ TF_idx = int(TF_idx)
150
+ target_idx = int(target_idx)
151
+ #print('%s\t%s\t%.6f' % (gene_names[TF_idx],gene_names[target_idx],score))
152
+ edge_list.append((gene_names[TF_idx],gene_names[target_idx],score))
153
+ else:
154
+ for i in range(nToWrite):
155
+ (TF_idx,target_idx,score) = vInter_sort[i]
156
+ TF_idx = int(TF_idx)
157
+ target_idx = int(target_idx)
158
+ #print('G%d\tG%d\t%.6f' % (TF_idx+1,target_idx+1,score))
159
+ edge_list.append((TF_idx+1,target_idx+1,score))
160
+
161
+ return edge_list
162
+
163
+
164
+
165
+
166
+
167
+ def GENIE3(expr_data,gene_names=None,regulators='all',tree_method='RF',K='sqrt',ntrees=1000,nthreads=1):
168
+
169
+ '''Computation of tree-based scores for all putative regulatory links.
170
+
171
+ Parameters
172
+ ----------
173
+
174
+ expr_data: numpy array
175
+ Array containing gene expression values. Each row corresponds to a condition and each column corresponds to a gene.
176
+
177
+ gene_names: list of strings, optional
178
+ List of length p, where p is the number of columns in expr_data, containing the names of the genes. The i-th item of gene_names must correspond to the i-th column of expr_data.
179
+ default: None
180
+
181
+ regulators: list of strings, optional
182
+ List containing the names of the candidate regulators. When a list of regulators is provided, the names of all the genes must be provided (in gene_names). When regulators is set to 'all', any gene can be a candidate regulator.
183
+ default: 'all'
184
+
185
+ tree-method: 'RF' or 'ET', optional
186
+ Specifies which tree-based procedure is used: either Random Forest ('RF') or Extra-Trees ('ET')
187
+ default: 'RF'
188
+
189
+ K: 'sqrt', 'all' or a positive integer, optional
190
+ Specifies the number of selected attributes at each node of one tree: either the square root of the number of candidate regulators ('sqrt'), the total number of candidate regulators ('all'), or any positive integer.
191
+ default: 'sqrt'
192
+
193
+ ntrees: positive integer, optional
194
+ Specifies the number of trees grown in an ensemble.
195
+ default: 1000
196
+
197
+ nthreads: positive integer, optional
198
+ Number of threads used for parallel computing
199
+ default: 1
200
+
201
+
202
+ Returns
203
+ -------
204
+
205
+ An array in which the element (i,j) is the score of the edge directed from the i-th gene to the j-th gene. All diagonal elements are set to zero (auto-regulations are not considered). When a list of candidate regulators is provided, the scores of all the edges directed from a gene that is not a candidate regulator are set to zero.
206
+
207
+ '''
208
+
209
+ time_start = time.time()
210
+
211
+ # Check input arguments
212
+ if not isinstance(expr_data,ndarray):
213
+ raise ValueError('expr_data must be an array in which each row corresponds to a condition/sample and each column corresponds to a gene')
214
+
215
+ ngenes = expr_data.shape[1]
216
+
217
+ if gene_names is not None:
218
+ if not isinstance(gene_names,(list,tuple)):
219
+ raise ValueError('input argument gene_names must be a list of gene names')
220
+ elif len(gene_names) != ngenes:
221
+ raise ValueError('input argument gene_names must be a list of length p, where p is the number of columns/genes in the expr_data')
222
+
223
+ if regulators != 'all':
224
+ if not isinstance(regulators,(list,tuple)):
225
+ raise ValueError('input argument regulators must be a list of gene names')
226
+
227
+ if gene_names is None:
228
+ raise ValueError('the gene names must be specified (in input argument gene_names)')
229
+ else:
230
+ sIntersection = set(gene_names).intersection(set(regulators))
231
+ if not sIntersection:
232
+ raise ValueError('the genes must contain at least one candidate regulator')
233
+
234
+ if tree_method != 'RF' and tree_method != 'ET':
235
+ raise ValueError('input argument tree_method must be "RF" (Random Forests) or "ET" (Extra-Trees)')
236
+
237
+ if K != 'sqrt' and K != 'all' and not isinstance(K,int):
238
+ raise ValueError('input argument K must be "sqrt", "all" or a stricly positive integer')
239
+
240
+ if isinstance(K,int) and K <= 0:
241
+ raise ValueError('input argument K must be "sqrt", "all" or a stricly positive integer')
242
+
243
+ if not isinstance(ntrees,int):
244
+ raise ValueError('input argument ntrees must be a stricly positive integer')
245
+ elif ntrees <= 0:
246
+ raise ValueError('input argument ntrees must be a stricly positive integer')
247
+
248
+ if not isinstance(nthreads,int):
249
+ raise ValueError('input argument nthreads must be a stricly positive integer')
250
+ elif nthreads <= 0:
251
+ raise ValueError('input argument nthreads must be a stricly positive integer')
252
+
253
+
254
+ print('Tree method: ' + str(tree_method))
255
+ print('K: ' + str(K))
256
+ print('Number of trees: ' + str(ntrees))
257
+ print('\n')
258
+
259
+
260
+ # Get the indices of the candidate regulators
261
+ if regulators == 'all':
262
+ input_idx = list(range(ngenes))
263
+ else:
264
+ input_idx = [i for i, gene in enumerate(gene_names) if gene in regulators]
265
+
266
+
267
+ # Learn an ensemble of trees for each target gene, and compute scores for candidate regulators
268
+ VIM = zeros((ngenes,ngenes))
269
+
270
+ if nthreads > 1:
271
+ print('running jobs on %d threads' % nthreads)
272
+
273
+ input_data = list()
274
+ for i in range(ngenes):
275
+ input_data.append( [expr_data,i,input_idx,tree_method,K,ntrees] )
276
+
277
+ pool = Pool(nthreads)
278
+ alloutput = pool.map(wr_GENIE3_single, input_data)
279
+
280
+ for (i,vi) in alloutput:
281
+ VIM[i,:] = vi
282
+
283
+ else:
284
+ print('running single threaded jobs')
285
+ for i in range(ngenes):
286
+ print('Gene %d/%d...' % (i+1,ngenes))
287
+
288
+ vi = GENIE3_single(expr_data,i,input_idx,tree_method,K,ntrees)
289
+ VIM[i,:] = vi
290
+
291
+
292
+ VIM = transpose(VIM)
293
+
294
+ time_end = time.time()
295
+ print("Elapsed time: %.2f seconds" % (time_end - time_start))
296
+
297
+ return VIM
298
+
299
+
300
+
301
+ def wr_GENIE3_single(args):
302
+ return([args[1], GENIE3_single(args[0], args[1], args[2], args[3], args[4], args[5])])
303
+
304
+
305
+
306
+ def GENIE3_single(expr_data,output_idx,input_idx,tree_method,K,ntrees):
307
+
308
+ ngenes = expr_data.shape[1]
309
+
310
+ # Expression of target gene
311
+ output = expr_data[:,output_idx]
312
+
313
+ # Normalize output data
314
+ output = output / std(output)
315
+
316
+ # Remove target gene from candidate regulators
317
+ input_idx = input_idx[:]
318
+ if output_idx in input_idx:
319
+ input_idx.remove(output_idx)
320
+
321
+ expr_data_input = expr_data[:,input_idx]
322
+
323
+ # Parameter K of the tree-based method
324
+ if (K == 'all') or (isinstance(K,int) and K >= len(input_idx)):
325
+ max_features = "auto"
326
+ else:
327
+ max_features = K
328
+
329
+ if tree_method == 'RF':
330
+ treeEstimator = RandomForestRegressor(n_estimators=ntrees,max_features=max_features)
331
+ elif tree_method == 'ET':
332
+ treeEstimator = ExtraTreesRegressor(n_estimators=ntrees,max_features=max_features)
333
+
334
+ # Learn ensemble of trees
335
+ treeEstimator.fit(expr_data_input,output)
336
+
337
+ # Compute importance scores
338
+ feature_importances = compute_feature_importances(treeEstimator)
339
+ vi = zeros(ngenes)
340
+ vi[input_idx] = feature_importances
341
+
342
+ return vi
343
+
344
+
345
+
PDGrapher/data/scripts/GRN/GENIEppi-run.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from GENIE3 import *
2
+ import networkx as nx
3
+ import numpy as np
4
+ import os
5
+ import time
6
+ root = 'data/raw/'
7
+ import argparse
8
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
9
+ parser.add_argument('--cell_line', default=None, nargs='+')
10
+ parser.add_argument('--data_type', default='cmp', type=str) #cmp or gen for chemical or genetic
11
+ args = parser.parse_args()
12
+ data_type = args.data_type
13
+ celllines = args.cell_line
14
+
15
+ def run_GENIE():
16
+ for cn in celllines:
17
+ startTime=time.time()
18
+ d = root + 'xpr_matrices/{}_xpr_matrix_{}_nonpertsubset.txt'.format(cn, data_type)
19
+ data=loadtxt(d, skiprows=1)
20
+ f=open(d)
21
+ gene_names=f.readline()
22
+ f.close()
23
+ gene_names = gene_names.rstrip('\n').split('\t')
24
+ VIM = GENIE3(data, ntrees=100, nthreads=20)
25
+ outdir = root + 'processed/'
26
+ os.makedirs(outdir, exist_ok=True)
27
+ with open(outdir + "{}_{}_GENIE3arr.npy".format(cn, data_type), 'wb') as f:
28
+ np.save(f, VIM)
29
+ print("Cell Line: {} - ".format(cn)+str(time.time()-startTime))
30
+
31
+ def get_edgelist():
32
+ for cn in celllines:
33
+ outdir = root + 'processed/'
34
+ startTime=time.time()
35
+ d = root + 'xpr_matrices/{}_xpr_matrix_{}_nonpertsubset.txt'.format(cn, data_type)
36
+ arr = np.load(outdir + "{}_{}_GENIE3arr.npy".format(cn, data_type))
37
+ f=open(d)
38
+ gene_names=f.readline()
39
+ f.close()
40
+ gene_names = gene_names.rstrip('\n').split('\t')
41
+
42
+ reg_link_list=get_link_list(arr, gene_names=gene_names, file_name=outdir+"{}_{}_edgelist.txt".format(cn, data_type))
43
+ g = nx.DiGraph((x,y,{'weight': v}) for (x, y, v) in reg_link_list)
44
+ nx.write_weighted_edgelist(g, outdir+'{}_{}_nxEdgelist.txt'.format(cn, data_type), delimiter=' ')
45
+ #print(reg_link_list[0], type(reg_link_list[0]))
46
+ print("Cell Line: {} - ".format(cn)+str(time.time()-startTime))
47
+
48
+
49
+ if __name__ == "__main__":
50
+ #startTime=time.time()
51
+ run_GENIE()
52
+ get_edgelist()
53
+ #print(time.time()-startTime)
PDGrapher/data/scripts/GRN/README.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Scripts to build GRN for PDGrapher
2
+ ---
3
+
4
+ ### 1. Generate Expression Matrices
5
+ Use `xpr_matrix_generator_datatypesplit.py` to build the `xpr_matrices` files.
6
+
7
+ **Inputs:**
8
+ - `level3_beta_ctl_n188708x12328.gctx` (download from [C-map](https://clue.io/releases/data-dashboard))
9
+ - `ppi_all_genes_edgelist.txt` (see `data/scripts/ppi` for instructions on generating this file)
10
+
11
+ **Command Example:**
12
+ python xpr_matrix_generator_datatypesplit.py
13
+
14
+
15
+ ### 2. Generate GENIE3 edge list
16
+ Use `GENIEppi-run.py` to build the `{cell_line}_{pert_type}_edgelist.txt` files.
17
+
18
+ **Inputs:**
19
+ - `xpr_matrices` (from step 1)
20
+
21
+ **Command Example:**
22
+ python GENIEppi-run.py --data_type cmp --cell_line A549
23
+
24
+ ### 3. Filter edge lists
25
+ Use `filter_edge_list.py` to build the `{cell_line}_{pert_type}_edgelist_filtered.txt` files.
26
+
27
+ **Inputs:**
28
+ - `{cell_line}_{pert_type}_edgelist.txt` files (from step 2)
29
+
30
+ **Command Example:**
31
+ python filter_edge_list.py --data_type cmp --cell_line A549
PDGrapher/data/scripts/GRN/filter_edge_list.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import networkx as nx
2
+ import csrgraph as cg
3
+ from collections import Counter
4
+ import pandas as pd
5
+ import os
6
+ import os.path as osp
7
+ import numpy as np
8
+ import sys
9
+ import argparse
10
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
11
+ parser.add_argument('--cell_line', default=None, nargs='+')
12
+ parser.add_argument('--data_type', default='cross', type=str)
13
+ args = parser.parse_args()
14
+ data_type = args.data_type
15
+ celllines = args.cell_line
16
+
17
+ #chemical
18
+ if data_type == "chemical":
19
+ print("Chemical")
20
+ gene_info = pd.read_csv('data/raw/lincs/geneinfo_beta.txt', sep="\t", low_memory=False)
21
+ outdir = 'data/raw/grn/filter/'
22
+ for i in celllines:
23
+ log_handle = open(f'log_grn_all_genes_genetic_{i}.txt', 'w')
24
+ path_edge_list = 'data/raw/grn/processed/{}_cmp_edgelist.txt'.format(i)
25
+ print("Do: ", i)
26
+ grn_0 = nx.read_edgelist(path_edge_list, nodetype=str, data=(('weight', float),))
27
+ grn_1 = [(u, v, d['weight']) for u, v, d in grn_0.edges(data=True)]
28
+ grn_2 = sorted(grn_1, key=lambda x: x[2])
29
+ grn = nx.Graph()
30
+ grn.add_weighted_edges_from(grn_2)
31
+ wl = np.array([float(weight) for u, v, weight in grn_2])
32
+ k = np.quantile(wl, 0.99)
33
+ edges = np.array(grn_2)
34
+ print(f"Do cutoff {k}...")
35
+ edges_filter = edges[wl < k]
36
+ grn.remove_edges_from(edges_filter)
37
+ #Loads gene info LINCS
38
+ log_handle.write('Cutoff:{}, removed edges {}\n'.format(k, len(edges_filter)))
39
+ log_handle.write('Overlap of genes from LINCS to grn:{}/{}\n'.format(len(set(grn.nodes()).intersection(set(gene_info['gene_symbol']))), len(gene_info)))
40
+ print("Flitering...")
41
+ #Filter nodes from grn to keep only the ones in LINCS
42
+ grn = grn.subgraph(gene_info['gene_symbol'].tolist())
43
+ log_handle.write('Keeping only grn nodes that are in LINCS:{}\n'.format(grn.number_of_nodes()))
44
+ print("Find connected components...")
45
+ ccs = [len(c) for c in sorted(nx.connected_components(grn), key=len, reverse=True)]
46
+ log_handle.write('Number of connected componens:\t{}\n'.format(len(ccs)))
47
+ Gcc = sorted(nx.connected_components(grn), key=len, reverse=True)
48
+ grn = grn.subgraph(Gcc[0])
49
+ log_handle.write('After keeping only biggest CC:\n')
50
+ log_handle.write('stats: {} nodes, {} edges, {} density, {} diameter\n\n\n'.format(grn.number_of_nodes(), grn.number_of_edges(), nx.density(grn), nx.diameter(grn)))
51
+ print("Done and save...")
52
+ grn_f = osp.join(outdir, f'{i}_cmp_edgelist_filtered.txt')
53
+ nx.write_edgelist(grn, grn_f, data=False)
54
+
55
+ elif data_type == "genetic":
56
+ gene_info = pd.read_csv('data/raw/lincs/geneinfo_beta.txt', sep="\t", low_memory=False)
57
+ outdir = 'data/raw/grn/filter/'
58
+ for i in celllines:
59
+ log_handle = open(f'log_grn_all_genes_genetic_{i}.txt', 'w')
60
+ path_edge_list = 'data/raw/grn/processed/{}_gen_edgelist.txt'.format(i)
61
+ print("Do: ", i)
62
+ grn_0 = nx.read_edgelist(path_edge_list, nodetype=str, data=(('weight', float),))
63
+ grn_1 = [(u, v, d['weight']) for u, v, d in grn_0.edges(data=True)]
64
+ grn_2 = sorted(grn_1, key=lambda x: x[2])
65
+ grn = nx.Graph()
66
+ grn.add_weighted_edges_from(grn_2)
67
+ wl = np.array([float(weight) for u, v, weight in grn_2])
68
+ k = np.quantile(wl, 0.99)
69
+ edges = np.array(grn_2)
70
+ print(f"Do cutoff {k}...")
71
+ edges_filter = edges[wl < k]
72
+ grn.remove_edges_from(edges_filter)
73
+ #Loads gene info LINCS
74
+ log_handle.write('Cutoff:{}, removed edges {}\n'.format(k, len(edges_filter)))
75
+ log_handle.write('Overlap of genes from LINCS to grn:{}/{}\n'.format(len(set(grn.nodes()).intersection(set(gene_info['gene_symbol']))), len(gene_info)))
76
+ print("Flitering...")
77
+ #Filter nodes from grn to keep only the ones in LINCS
78
+ grn = grn.subgraph(gene_info['gene_symbol'].tolist())
79
+ log_handle.write('Keeping only grn nodes that are in LINCS:{}\n'.format(grn.number_of_nodes()))
80
+ print("Find connected components...")
81
+ ccs = [len(c) for c in sorted(nx.connected_components(grn), key=len, reverse=True)]
82
+ log_handle.write('Number of connected componens:\t{}\n'.format(len(ccs)))
83
+ Gcc = sorted(nx.connected_components(grn), key=len, reverse=True)
84
+ grn = grn.subgraph(Gcc[0])
85
+ log_handle.write('After keeping only biggest CC:\n')
86
+ log_handle.write('stats: {} nodes, {} edges, {} density, {} diameter\n\n\n'.format(grn.number_of_nodes(), grn.number_of_edges(), nx.density(grn), nx.diameter(grn)))
87
+ print("Done and save...")
88
+ grn_f = osp.join(outdir, f'{i}_gen_edgelist_filtered.txt')
89
+ nx.write_edgelist(grn, grn_f, data=False)
PDGrapher/data/scripts/GRN/xpr_matrix_generator_datatypesplit.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import networkx as nx
2
+ import pandas as pd
3
+ import numpy as np
4
+ import os
5
+ import os.path as osp
6
+ import h5py
7
+
8
+ #Loading Data
9
+ DATA_ROOT = "data/raw/lincs/"
10
+ #log_handle = open(osp.join(outdir, 'process_data_lognorm_log.txt'), 'w')
11
+ #log_handle = open(osp.join(outdir, 'test_log.txt'), 'w')
12
+
13
+ inst_info = pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
14
+ inst_info_xpr = inst_info[np.logical_and(inst_info['pert_type'] == 'trt_xpr', inst_info['failure_mode'].isna())].reset_index(inplace=False, drop=True)
15
+ inst_info_ctl = inst_info[np.logical_and(np.logical_or(inst_info['pert_type'] == 'ctl_vector',inst_info['pert_type'] == 'ctl_vehicle'), inst_info['failure_mode'].isna())].reset_index(inplace=False, drop=True)
16
+ gene_info = pd.read_csv(os.path.join(DATA_ROOT, 'geneinfo_beta.txt'), sep="\t", low_memory=False)
17
+ df_xpr=pd.DataFrame(inst_info_xpr[['sample_id','pert_id', 'pert_dose','pert_dose_unit','pert_time','cell_iname']])
18
+
19
+
20
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_ctl_n188708x12328.gctx'), 'r')
21
+ matrix_xpr = f['0']['DATA']['0']['matrix'][:].transpose()
22
+ gene_ids_xpr = f['0']['META']['ROW']['id'][:]
23
+ sample_ids_xpr = f['0']['META']['COL']['id'][:]
24
+ matrix_xpr = pd.DataFrame(matrix_xpr, columns = sample_ids_xpr.astype(str), index = gene_ids_xpr.astype(int))
25
+ del f
26
+
27
+ #Decoding sample_ids_xpr array
28
+ decode=np.vectorize(np.char.decode)
29
+ sample_ids_xpr=decode(sample_ids_xpr)
30
+
31
+ #Creating dict of cell_line:sample_ids
32
+ cell_line_sids={}
33
+ for cn in inst_info_ctl.cell_iname.unique():
34
+ cell_line_sids[cn]=list(inst_info_ctl.loc[inst_info_ctl['cell_iname']==cn]['sample_id'])
35
+
36
+ #Lists of sample_ids for ctl_vector and ctl_vehicle samples
37
+ xpr_samples_unique = list(inst_info_ctl.loc[inst_info_ctl['pert_type']=="ctl_vector"].sample_id.unique())
38
+ cmp_samples_unique = list(inst_info_ctl.loc[inst_info_ctl['pert_type']=="ctl_vehicle"].sample_id.unique())
39
+
40
+
41
+
42
+ #Renaming columns of matrix_xpr_trans to gene symbols
43
+ matrix_xpr_trans=matrix_xpr.T
44
+ new_cols = []
45
+ for i in matrix_xpr_trans.columns:
46
+ new_cols.append(gene_info.loc[gene_info['gene_id']==i]['gene_symbol'].item())
47
+ matrix_xpr_trans.columns = new_cols
48
+
49
+
50
+ #Subsetting matrix_xpr_trans column genes to include only those in the ppi, but not those that are perturbed.
51
+ path_edge_list = 'data/raw/ppi/ppi_all_genes_edgelist.txt'
52
+ ppi = nx.read_edgelist(path_edge_list)
53
+ ppi = ppi.subgraph(gene_info['gene_symbol'].tolist())
54
+
55
+
56
+ #pert_genes = dict()
57
+ #for cell_line in list(set(inst_info_xpr['cell_iname'])):
58
+ #pert_genes[cell_line] = set(inst_info_xpr[inst_info_xpr['cell_iname']==cell_line]['cmap_name'].tolist())
59
+
60
+ outdir = 'data/raw/grn/xpr_matrices/'
61
+ os.makedirs(outdir, exist_ok=True)
62
+
63
+ #chemical cell lines
64
+ for cn in cell_line_sids:
65
+ if cn in ['A549', 'MCF7', 'PC3', 'VCAP', 'MDAMB231', 'BT20', 'HT29', 'A375', 'HELA']:
66
+ print(cn)
67
+ cellline_xpr_matrix_chem = matrix_xpr_trans[np.logical_and(matrix_xpr_trans.index.isin(cell_line_sids[cn]),matrix_xpr_trans.index.isin(cmp_samples_unique))]
68
+ gene_intersection_list=list(set(ppi.nodes).intersection(set(list(gene_info.gene_symbol.unique()))))
69
+ cellline_xpr_matrix_chem=cellline_xpr_matrix_chem[gene_intersection_list]
70
+ cellline_xpr_matrix_chem.to_csv(osp.join(outdir,'{}_xpr_matrix_cmp_nonpertsubset.txt'.format(cn)), sep=' ', index=False)
71
+
72
+ #genetic cell lines
73
+ for cn in cell_line_sids:
74
+ if cn in ['BICR6', 'YAPC', 'AGS', 'U251MG', 'ES2', 'MCF7', 'PC3', 'A375', 'HT29', 'A549']:
75
+ print(cn)
76
+ cellline_xpr_matrix_gen = matrix_xpr_trans[np.logical_and(matrix_xpr_trans.index.isin(cell_line_sids[cn]),matrix_xpr_trans.index.isin(xpr_samples_unique))]
77
+ gene_intersection_list=list(set(ppi.nodes).intersection(set(list(gene_info.gene_symbol.unique()))))
78
+ cellline_xpr_matrix_gen=cellline_xpr_matrix_gen[gene_intersection_list]
79
+ cellline_xpr_matrix_gen.to_csv(osp.join(outdir,'{}_xpr_matrix_gen_nonpertsubset.txt'.format(cn)), sep=' ', index=False)
80
+
81
+
82
+
PDGrapher/data/scripts/cosmic/generate_cell_line_mutations_files.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Processes CosmicCLP_MutantExport.tsv (15th Sept 2022) to create a file with cell line: mutations
3
+ Expert curated list obtained from:https://cancer.sanger.ac.uk/cell_lines/curation# (18th March 2024)
4
+
5
+ '''
6
+
7
+ import pandas as pd
8
+ from collections import Counter
9
+ import os
10
+ import os.path as osp
11
+
12
+ #Creates out dir
13
+ outdir = '../../processed/cosmic'
14
+ os.makedirs(outdir, exist_ok=True)
15
+
16
+
17
+ cell_lines = ['A549', 'PC-3', 'MCF7', 'BT-20', 'MDA-MB-231', 'VCaP', 'A375', 'HT-29', 'ES-2', 'BICR6', 'YAPC', 'AGS', 'U251MG']
18
+
19
+
20
+
21
+ #Loads data
22
+ data = pd.read_csv('../../raw/cosmic/2022-10-COSMIC/data/CosmicCLP_MutantExport.tsv', sep='\t', encoding="ISO-8859-1")
23
+ #Filter to include only the 5 cell lines of interest
24
+ mask = [e in cell_lines for e in data['Sample name']]
25
+ data = data[mask]
26
+
27
+
28
+
29
+ #Explore data
30
+ log_handle = open('log_stats.txt','w')
31
+ columns = ['Mutation Description', 'Mutation somatic status', 'Mutation verification status']
32
+ for cell_line in cell_lines:
33
+ data_i = data[data['Sample name']==cell_line]
34
+ log_handle.write('\nCELL LINE:\t{}\n'.format(cell_line))
35
+ for column in columns:
36
+ log_handle.write(column+'\n')
37
+ log_handle.write(str(Counter(data_i[column])) +'\n\n')
38
+ log_handle.write('Total genes mutated:\t{}\n\n\n\n'.format(len(data_i['Gene name'])))
39
+
40
+
41
+
42
+
43
+
44
+
45
+ #As agreed with Marinka, take an overlap of the 'verified' mutations and expert curated genes, for each cell line
46
+ #Filter to keep only verified genes
47
+ data = data[data['Mutation verification status'] == 'Verified']
48
+
49
+
50
+ #Filter to keep only curated genes
51
+ curated_genes = pd.read_csv('../../raw/cosmic/2022-10-COSMIC/data/expert_curated_genes_cosmic_2024.csv', sep='\t')['Genes'].tolist()
52
+ mask = [gene in curated_genes for gene in data['Gene name']]
53
+ data_curated = data[mask]
54
+ data_curated['Sample name'] = [e.replace('-','').upper() for e in data_curated['Sample name']]
55
+
56
+
57
+ #Save file
58
+ data_curated.to_csv(osp.join(outdir, 'CosmicCLP_MutantExport_only_verified_and_curated.csv'))
59
+ log_handle.write(str(data_curated['Sample name'].value_counts()))
60
+ log_handle.close()
PDGrapher/data/scripts/drugbank/get_drug_targets.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Processess DrugBank full database to get txt file with drug names and targets
3
+ '''
4
+ from bs4 import BeautifulSoup
5
+ import pandas as pd
6
+ import os
7
+ import os.path as osp
8
+
9
+ outdir = '../../processed/drugbank/'
10
+ os.makedirs(outdir, exist_ok=True)
11
+
12
+ soup = BeautifulSoup(open("../../raw/drugbank/2022-11-DrugBank/data/all-full-database.xml"),"xml")
13
+
14
+ # sep = ","
15
+ # with open('../processed/targets.txt', 'w') as f:
16
+
17
+ df = []
18
+ for drug in soup.find_all("drug"):
19
+ drug_id = drug.find("drugbank-id").text
20
+ drug_name = drug.find("name").text
21
+ targets = drug.find_all("target")
22
+ synonyms = drug.find("synonyms")
23
+ if synonyms is None:
24
+ synonyms = '-'
25
+ else:
26
+ synonyms = synonyms.find_all("synonym")
27
+ synonyms = "||".join([e.text for e in synonyms])
28
+ if not targets:
29
+ continue
30
+ for i in targets:
31
+ identifiers = i.find_all("external-identifier")
32
+ identifiers = '||'.join(['|'.join([e.resource.text, e.identifier.text]) for e in identifiers])
33
+ if i.find("id") is not None:
34
+ idd = i.find("id").text
35
+ else:
36
+ idd = '-'
37
+ if i.find("name") is not None:
38
+ name = i.find("name").text
39
+ else:
40
+ name == "-"
41
+ if i.find("gene-name") is not None:
42
+ gene_name = i.find("gene-name").text
43
+ else:
44
+ gene_name = "-"
45
+ if i.find("organism") is not None:
46
+ organism = i.find("organism").text
47
+ else:
48
+ organism = "-"
49
+ if i.find_all('synonym') is not None:
50
+ synonyms = '||'.join(synonym.text for synonym in i.find_all('synonym'))
51
+ else:
52
+ synonyms = '-'
53
+
54
+
55
+ df.append([drug_id, drug_name, synonyms, idd, name, gene_name, synonyms, identifiers, organism])
56
+
57
+
58
+ df = pd.DataFrame(df, columns= ['DrugBank_ID', 'drug_name', 'drug_synonyms', 'target_id', 'target_name', 'gene_name', 'gene_synonyms', 'gene_identifiers', 'organism']).to_csv(osp.join(outdir, 'targets.txt'), sep = ',', index=False)
59
+
PDGrapher/data/scripts/lincs/process_data.py ADDED
@@ -0,0 +1,881 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Normalizes perturbed (treated) and control (diseased) data of genetic interventions
3
+ Saves data as npz
4
+
5
+ 1. Reads data (load_data)
6
+ 2. Filters to keep only the cell lines that we use in experiments (filter_cell_lines_custom)
7
+ 3. Filters to keep only the samples in metadata (filter_data_metadata)
8
+ 4. Filters out samples for which the drug targets are not in LINCS genes (filter_samples_with_unknown_perturbed_genes)
9
+ 5. Normalizes data between (0,1) and save (normalize_and_save)
10
+ '''
11
+ import pandas as pd
12
+ import h5py
13
+ import os
14
+ import matplotlib.pyplot as plt
15
+ import seaborn as sns
16
+ import os.path as osp
17
+ import numpy as np
18
+ from collections import Counter
19
+ import matplotlib.pyplot as plt
20
+ import math
21
+ from random import sample
22
+ from sklearn.preprocessing import MinMaxScaler
23
+
24
+
25
+ outdir = '../../processed/lincs'
26
+ os.makedirs(outdir, exist_ok=True)
27
+
28
+ #LOG
29
+
30
+
31
+ ################
32
+ # Data loading
33
+ ################
34
+ def stats_data(inst_info_xpr, matrix_xpr, matrix_ctl, gene_info):
35
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
36
+
37
+ ####Data exploration -- GE values of genes that are perturbed (!)
38
+ #Get GE value for each gene perturbed by CRISPR
39
+ values_pert = {}
40
+ values_control = {}
41
+ for i in range(len(inst_info_xpr)):
42
+ gene_symbol = inst_info_xpr.at[i, 'cmap_name']
43
+ if gene_symbol in dict_symbol_id: #if the cmap_name of gene is in the gene_info
44
+ sample_id = inst_info_xpr.at[i, 'sample_id']
45
+ gene_id = dict_symbol_id[gene_symbol]
46
+ if gene_id in values_pert:
47
+ values_pert[gene_id].append(matrix_xpr.at[gene_id, sample_id])
48
+ else:
49
+ values_pert[gene_id] = [matrix_xpr.at[gene_id, sample_id]]
50
+
51
+
52
+ for gene_symbol in list(set(inst_info_xpr['cmap_name'])):
53
+ if gene_symbol in dict_symbol_id: #if the cmap_name of gene is in the gene_info
54
+ gene_id = dict_symbol_id[gene_symbol]
55
+ values_control[gene_id] = [matrix_ctl.loc[gene_id]]
56
+
57
+ for key in values_pert:
58
+ values_pert[key] = np.mean(values_pert[key])
59
+
60
+ for key in values_control:
61
+ values_control[key] = np.mean(values_control[key])
62
+
63
+ fig, (ax1, ax2) = plt.subplots(2, figsize=(16,6))
64
+ ax1.hist(values_pert.values())
65
+ ax2.hist(values_control.values())
66
+ ax1.set_title('Values of perturbed genes (avg) - CRISPR')
67
+ ax2.set_title('Values of genes in control (avg)')
68
+ fig.savefig(osp.join(outdir,'exploration_ge_crispr.png'))
69
+
70
+
71
+ return
72
+
73
+
74
+
75
+ def loads_data(DATA_ROOT, log_handle):
76
+ #Loads metadata
77
+ inst_info = pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
78
+ inst_info_xpr = inst_info[np.logical_and(inst_info['pert_type'] == 'trt_xpr', inst_info['failure_mode'].isna())].reset_index(inplace=False, drop=True)
79
+ inst_info_ctl = inst_info[np.logical_and(inst_info['pert_type'] == 'ctl_vector', inst_info['failure_mode'].isna()) ].reset_index(inplace=False, drop=True)
80
+ gene_info = pd.read_csv(os.path.join(DATA_ROOT, 'geneinfo_beta.txt'), sep="\t", low_memory=False)
81
+
82
+
83
+ ####################
84
+ #Loads data matrices
85
+ ### CRISPR
86
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_trt_xpr_n420583x12328.gctx'), 'r')
87
+ matrix_xpr = f['0']['DATA']['0']['matrix'][:].transpose()
88
+ gene_ids_xpr = f['0']['META']['ROW']['id'][:]
89
+ sample_ids_xpr = f['0']['META']['COL']['id'][:]
90
+ matrix_xpr = pd.DataFrame(matrix_xpr, columns = sample_ids_xpr.astype(str), index = gene_ids_xpr.astype(int))
91
+ del f
92
+
93
+
94
+ #re-order gene_info based on the order in gene_ids_xpr (rows of data)
95
+ gene_info.index = gene_info['gene_id']
96
+ gene_info = gene_info.loc[gene_ids_xpr.astype(int)].reset_index(inplace=False, drop=True)
97
+ gene_info.to_csv(osp.join(outdir, 'gene_info.txt'), index=False)
98
+
99
+ #Stats
100
+ log_handle.write('CRISPR\n------\n')
101
+ log_handle.write('CRISPR entries in inst_info metadata:\t{}\n'.format(len(inst_info_xpr)))
102
+ log_handle.write('CRISPR entries in data matrix:\t{}\n'.format(len(sample_ids_xpr)))
103
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_xpr['sample_id']).intersection(set(sample_ids_xpr.astype(str))))))
104
+
105
+
106
+
107
+ ### Control data
108
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_ctl_n188708x12328.gctx'), 'r')
109
+ matrix_ctl = f['0']['DATA']['0']['matrix'][:].transpose()
110
+ gene_ids_ctl = f['0']['META']['ROW']['id'][:] #not in the same order as gene_ids_xpr
111
+ sample_ids_ctl = f['0']['META']['COL']['id'][:]
112
+ matrix_ctl = pd.DataFrame(matrix_ctl, columns = sample_ids_ctl.astype(str), index = gene_ids_ctl.astype(int))
113
+ del f
114
+
115
+
116
+ #Stats
117
+ log_handle.write('CONTROL\n------\n')
118
+ log_handle.write('Control entries in inst_info metadata:\t{}\n'.format(len(inst_info_ctl)))
119
+ log_handle.write('Control entries in data matrix:\t{}\n'.format(len(sample_ids_ctl)))
120
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_ctl['sample_id']).intersection(set(sample_ids_ctl.astype(str))))))
121
+ log_handle.write('\n------\n')
122
+
123
+
124
+ stats_data(inst_info_xpr, matrix_xpr, matrix_ctl, gene_info)
125
+
126
+ return inst_info_xpr, inst_info_ctl, gene_info, matrix_xpr, matrix_ctl
127
+
128
+
129
+
130
+
131
+ ################
132
+ # Processing
133
+ ################
134
+
135
+ ################
136
+ #1. Filter column metadata and data matrix to keep only those in metadata
137
+
138
+ def filter_data_metadata(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle):
139
+ log_handle.write('Filtering to keep only those in metadata\n------\n')
140
+ #CRISPR
141
+ list_ids = list(inst_info_xpr['sample_id']) #in metadata
142
+ matrix_xpr = matrix_xpr[list_ids] #Filtered data matrix
143
+ log_handle.write('CRISPR:\t{} datapoints\n'.format(matrix_xpr.shape[1]))
144
+ #CONTROL
145
+ list_ids = list(inst_info_ctl['sample_id']) #in metadata
146
+ #extra steps
147
+ #--
148
+ list_ids = list(set(list_ids).intersection(set(matrix_ctl.columns.astype(str)))) #in metadata and in data matrix (some of metadata are not in data matrix)
149
+ inst_info_ctl.index = inst_info_ctl['sample_id']; inst_info_ctl = inst_info_ctl.loc[list_ids].reset_index(inplace=False, drop=True) #remove entries from metadata that are not in data matrix
150
+ #--
151
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
152
+ log_handle.write('CONTROL:\t{} datapoints\n\n\n'.format(matrix_ctl.shape[1]))
153
+ return inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl
154
+
155
+
156
+
157
+ ################
158
+ #2. Filter to keep only cell lines with more perturbations
159
+
160
+ def stats_control(inst_info_ctl, log_handle):
161
+ #Stats unique cell lines
162
+ log_handle.write('Unique cell lines:\t{}:\n'.format(len(set(inst_info_ctl['cell_iname']))))
163
+ for c in list(set(inst_info_ctl['cell_iname'])):
164
+ log_handle.write('\t{}\n'.format(c))
165
+
166
+ log_handle.write('\n\n')
167
+
168
+ #Stats on dosages
169
+ df_ctl = pd.DataFrame(inst_info_ctl[['cmap_name', 'cell_iname', 'pert_idose']].groupby(['cmap_name', 'cell_iname']).apply(lambda x: x['pert_idose'].unique()))
170
+ df_ctl = pd.DataFrame([(i, len(df_ctl.loc[i][0])) for i in df_ctl.index], columns =['cmap_name-cell_line', 'n_doses'])
171
+ log_handle.write('Stats on dosages and timepoints\n')
172
+ log_handle.write('\n------\nHOW MANY DOSES ARE THERE FOR CMAP_NAME-CELL LINE PAIRS?\n------\n')
173
+ for index,value in pd.Series.iteritems(pd.DataFrame(df_ctl['n_doses'])['n_doses'].describe()):
174
+ log_handle.write('{}:\t{}\n'.format(index, value))
175
+
176
+ log_handle.write('\n')
177
+ log_handle.write('Number of pairs with more than 1 dose:\t{}/{}\n'.format(sum(df_ctl['n_doses']>1), len(df_ctl)))
178
+ log_handle.write('Number of pairs with more than 2 doses:\t{}/{}\n\n'.format(sum(df_ctl['n_doses']>2), len(df_ctl)))
179
+
180
+ #Stats on timepoints
181
+ df_ctl = pd.DataFrame(inst_info_ctl[['cmap_name', 'cell_iname', 'pert_time']].groupby(['cmap_name', 'cell_iname']).apply(lambda x: x['pert_time'].unique()))
182
+ df_ctl = pd.DataFrame([(i, len(df_ctl.loc[i][0])) for i in df_ctl.index], columns =['cmap_name-cell_line', 'n_times'])
183
+
184
+ log_handle.write('\n------\nHOW MANY TIMEPOINTS ARE THERE FOR CMAP_NAME-CELL LINE PAIRS?\n------\n')
185
+ for index,value in pd.Series.iteritems(pd.DataFrame(df_ctl['n_times'])['n_times'].describe()):
186
+ log_handle.write('{}:\t{}\n'.format(index, value))
187
+
188
+ log_handle.write('\n')
189
+ log_handle.write('Number of pairs with more than 1 timepoint:\t{}/{}\n'.format(sum(df_ctl['n_times']>1), len(df_ctl['n_times'])))
190
+ log_handle.write('Number of pairs with more than 2 timepoints:\t{}/{}\n\n'.format(sum(df_ctl['n_times']>2), len(df_ctl['n_times'])))
191
+
192
+
193
+ log_handle.write('\nUSING THEM ALL FOR NOW\n')
194
+
195
+ #Types of vectors
196
+ log_handle.write('Number of vectors:\t{}:\n'.format(len(set(inst_info_ctl['cmap_name']))))
197
+ df=pd.DataFrame.from_dict(Counter(inst_info_ctl['cmap_name']), orient='index')
198
+ df = df.sort_values(by=0)
199
+ for i, v in enumerate(zip(df.index, df[0])):
200
+ log_handle.write('{}:\t{}\n'.format(v[0], v[1]))
201
+
202
+ #Number of controls per cell line
203
+ replicates = inst_info_ctl.groupby(['cell_iname']).size()
204
+ log_handle.write('\n\n------\nNUMBER OF REPLICATES PER CELL LINE (different doses, times, vectors)\n-----------\n')
205
+ df=pd.DataFrame.from_dict(Counter(inst_info_ctl['cell_iname']), orient='index')
206
+ df = df.sort_values(by=0)
207
+ for i, v in enumerate(zip(df.index, df[0])):
208
+ log_handle.write('{}:\t{}\n'.format(v[0], v[1]))
209
+
210
+ return
211
+
212
+
213
+ def filter_cell_lines(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle):
214
+ log_handle.write('Filtering to keep only cell lines with highest mumber of perturbed genes\n------\n')
215
+
216
+ #####CRISPR
217
+ #Obtain cell lines with the most perturbations (> 90th-percentile)
218
+ df_xpr = pd.DataFrame(inst_info_xpr[['cmap_name', 'cell_iname']].groupby('cell_iname', as_index=True).apply(lambda x: x['cmap_name'].unique()))
219
+ df_xpr = pd.DataFrame([(i, len(df_xpr.loc[i][0])) for i in df_xpr.index], columns =['cell_line', 'n_cmap_names'])
220
+ df_xpr = df_xpr.sort_values(by='n_cmap_names')
221
+ keep_cell_lines = df_xpr[df_xpr['n_cmap_names']>np.percentile(df_xpr['n_cmap_names'], 60)]['cell_line'].tolist()
222
+
223
+ #Find indices of samples that are on the desired cell lines
224
+ keep_index = []
225
+ for i in range(len(inst_info_xpr)):
226
+ if inst_info_xpr.at[i, 'cell_iname'] in keep_cell_lines:
227
+ keep_index.append(i)
228
+
229
+
230
+ inst_info_xpr = inst_info_xpr.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
231
+ list_ids = list(inst_info_xpr['sample_id']) #obtain sample ID from metadata
232
+ matrix_xpr = matrix_xpr[list_ids] #Filtered data matrix
233
+ log_handle.write('CRISPR:\t{} datapoints\n'.format(matrix_xpr.shape[1]))
234
+
235
+
236
+
237
+ #####CONTROL
238
+ keep_index = []
239
+ for i in range(len(inst_info_ctl)):
240
+ if inst_info_ctl.at[i, 'cell_iname'] in keep_cell_lines:
241
+ keep_index.append(i)
242
+
243
+
244
+ inst_info_ctl = inst_info_ctl.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
245
+ list_ids = list(inst_info_ctl['sample_id']) #obtain sample ID from metadata
246
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
247
+ log_handle.write('CONTROL:\t{} datapoints\n'.format(matrix_ctl.shape[1]))
248
+
249
+ # Stats
250
+ # stats_control(inst_info_ctl, log_handle)
251
+
252
+ return inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, keep_cell_lines
253
+
254
+
255
+ def filter_cell_lines_custom(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle):
256
+ log_handle.write('Filtering to keep only cell lines: A549, PC3, MCF7\n------\n')
257
+ #####CRISPR
258
+ #Obtain cell lines with the most perturbations (> 4K genes perturbed)
259
+ keep_cell_lines = ['A549', 'PC3', 'MCF7', 'A375', 'HT29', 'ES2', 'BICR6', 'YAPC', 'AGS', 'U251MG']
260
+ #Find indices of samples that are on the desired cell lines
261
+ keep_index = []
262
+ for i in range(len(inst_info_xpr)):
263
+ if inst_info_xpr.at[i, 'cell_iname'] in keep_cell_lines:
264
+ keep_index.append(i)
265
+ inst_info_xpr = inst_info_xpr.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
266
+ list_ids = list(inst_info_xpr['sample_id']) #obtain sample ID from metadata
267
+ matrix_xpr = matrix_xpr[list_ids] #Filtered data matrix
268
+ log_handle.write('CRISPR:\t{} datapoints\n'.format(matrix_xpr.shape[1]))
269
+ #####CONTROL
270
+ keep_index = []
271
+ for i in range(len(inst_info_ctl)):
272
+ if inst_info_ctl.at[i, 'cell_iname'] in keep_cell_lines:
273
+ keep_index.append(i)
274
+ inst_info_ctl = inst_info_ctl.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
275
+ list_ids = list(inst_info_ctl['sample_id']) #obtain sample ID from metadata
276
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
277
+ log_handle.write('CONTROL:\t{} datapoints\n'.format(matrix_ctl.shape[1]))
278
+ # Stats
279
+ #stats_control(inst_info_ctl, log_handle)
280
+ return inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, keep_cell_lines
281
+
282
+ ################
283
+ #3. Concatenate perturbation and control data, normalize (binarize), and save
284
+ def filter_samples_with_unknown_perturbed_genes(inst_info_xpr, matrix_xpr, gene_info, log_handle):
285
+ ########################################################################################
286
+ #First filter perturbation samples to remove those with genes not mapping to genes_info
287
+ #Will need to remove this once I get the mapping file from CLUE
288
+ known_genes = list(set(gene_info['gene_symbol']))
289
+ keep_index = []
290
+ for i in range(len(inst_info_xpr)):
291
+ if inst_info_xpr.at[i, 'cmap_name'] in known_genes:
292
+ keep_index.append(i)
293
+
294
+
295
+ inst_info_xpr = inst_info_xpr.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
296
+ list_ids = list(inst_info_xpr['sample_id']) #obtain sample ID from metadata
297
+ matrix_xpr = matrix_xpr[list_ids] #Filtered data matrix
298
+ log_handle.write('Filtering samples with perturbed genes not mapped to gene_info -- TEMPORARY STEP THAT SHOULD BE REMOVED AFTER MAPPING GENES\n')
299
+ log_handle.write('CRISPR:\t{} datapoints\n'.format(matrix_xpr.shape[1]))
300
+ return inst_info_xpr, matrix_xpr
301
+
302
+
303
+ def binarize_genewise_ranking_all(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir):
304
+ log_handle.write('\n\n------\nBINARIZING GENEWISE RANKING ALL SAMPLES\n------\n')
305
+ outdir = osp.join(outdir, 'binarize_genewise_ranking_all')
306
+ os.makedirs(outdir, exist_ok= True)
307
+ ########################################################################################
308
+ #All data
309
+ metadata = pd.concat([inst_info_xpr, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
310
+ matrix = pd.concat([matrix_xpr, matrix_ctl], 1)
311
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
312
+
313
+
314
+
315
+ #Normalization
316
+ #0. create dictionary of gene_id: sample_id
317
+ #gene symbol -> gene id
318
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
319
+ #gene symbol -> sample id
320
+ dict_gene_id_sample_id= dict()
321
+ for i in range(len(inst_info_xpr)):
322
+ gene_symbol = inst_info_xpr.at[i, 'cmap_name']
323
+ gene_id = dict_symbol_id[gene_symbol]
324
+ if gene_id in dict_gene_id_sample_id:
325
+ dict_gene_id_sample_id[gene_id].append(inst_info_xpr.at[i, 'sample_id'])
326
+ else:
327
+ dict_gene_id_sample_id[gene_id] = [inst_info_xpr.at[i, 'sample_id']]
328
+
329
+
330
+ #1. Iterate through each gene, mask out the samples in which it was perturbed, and normalize --> take top 2% of samples as = 1
331
+ #for the perturbed genes = 0
332
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
333
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
334
+ i = 1
335
+ higher_than_thr = []
336
+ higher_than_thr_ids = []
337
+ for gene_id in list(matrix.index):
338
+ print('{}/{}'.format(i, len(matrix)))
339
+ #mask of elements to ignore (perturbed samples --> =0)
340
+ if gene_id in dict_gene_id_sample_id:
341
+ mask_pert = dict_gene_id_sample_id[gene_id]
342
+ mask_norm = list(set(list(matrix.columns)) - set(mask_pert))
343
+ else:
344
+ mask_pert = None
345
+ mask_norm = list(matrix.columns)
346
+ #normalize
347
+ threshold = np.percentile(matrix.loc[gene_id][mask_norm].values, 98)
348
+ matrix_binarized.loc[gene_id][mask_norm] = (matrix.loc[gene_id][mask_norm] >= threshold).astype(int).values
349
+ i+=1
350
+ #some stats
351
+ if mask_pert is not None:
352
+ higher_than_thr += (matrix.loc[gene_id][mask_pert] >= threshold).values.astype(int).tolist()
353
+ higher_than_thr_ids += matrix.loc[gene_id][mask_pert].index[np.where(matrix.loc[gene_id][mask_pert] >= threshold)].tolist()
354
+
355
+ ###Filter columns (samples) in which the perturbed gene has an expression value that is >= the threshold used to binarize
356
+ log_handle.write('Filtering:\t{} columns/samples because the perturbed gene has an expression value >= the threshold used to binarize -- TEMPORARY STEP THAT SHOULD BE REMOVED LATER ON\n'.format(len(higher_than_thr_ids)))
357
+ for c in higher_than_thr_ids:
358
+ del matrix_binarized[c]
359
+
360
+
361
+ #plot higher than thr
362
+ fig, ax1 = plt.subplots(1, figsize=(16,6))
363
+ ax1.hist(higher_than_thr)
364
+ ax1.set_title('Perturbed genes values >= threshold')
365
+ fig.savefig(osp.join(outdir,'exploration_ge_crispr_higher_than_thr.png'))
366
+ log_handle.write('After binarizing, stats, perturbed gene values would be higher than threshold in :\t{} samples\n'.format(np.sum(higher_than_thr)))
367
+
368
+
369
+ #2. Save data and metadata for each condition and cell line
370
+ #CRISPR + cell lines
371
+ #Control + cell lines
372
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
373
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
374
+ metadata.index = metadata['sample_id']
375
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
376
+ for cell_line in keep_cell_lines:
377
+ for pert_type in ['trt_xpr', 'ctl_vector']:
378
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
379
+ data_i = matrix_binarized[metadata_i.index]
380
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
381
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
382
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
383
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
384
+ log_handle.write('\n\n------\nSTATS\n------\n')
385
+
386
+ return
387
+
388
+
389
+
390
+ def binarize_genewise_comparing_to_control_all_controls_joint(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
391
+
392
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
393
+ if use_log:
394
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_all_controls_joint_lognorm')
395
+ else:
396
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_all_controls_joint')
397
+ os.makedirs(outdir, exist_ok= True)
398
+
399
+ ########################################################################################
400
+ #All data
401
+ metadata = pd.concat([inst_info_xpr, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
402
+ matrix = pd.concat([matrix_xpr, matrix_ctl], 1)
403
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
404
+
405
+
406
+
407
+ #Normalization
408
+ #0. create dictionary of gene_id: sample_id
409
+ #gene symbol -> gene id
410
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
411
+ #gene id -> sample id
412
+ dict_gene_id_sample_id= dict()
413
+ for i in range(len(inst_info_xpr)):
414
+ gene_symbol = inst_info_xpr.at[i, 'cmap_name']
415
+ gene_id = dict_symbol_id[gene_symbol]
416
+ if gene_id in dict_gene_id_sample_id:
417
+ dict_gene_id_sample_id[gene_id].append(inst_info_xpr.at[i, 'sample_id'])
418
+ else:
419
+ dict_gene_id_sample_id[gene_id] = [inst_info_xpr.at[i, 'sample_id']]
420
+
421
+
422
+ #1. Iterate through each gene, mask out the samples in which it was perturbed, and normalize --> set to 1 those genes that have value of average + 2std higher than control
423
+ #for the perturbed genes = 0
424
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
425
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
426
+ i = 1
427
+ higher_than_thr = []
428
+ higher_than_thr_ids = []
429
+
430
+
431
+ mask_norm = list(matrix_ctl.columns) #mask_norm is controls only
432
+
433
+ # averages = np.mean(matrix[mask_norm], 1)
434
+ # stds = np.std(matrix[mask_norm], 1)
435
+ # thresholds = averages + (2*stds)
436
+ if use_log:
437
+ matrix = np.log2(matrix + 1)
438
+
439
+ averages = np.mean(matrix[mask_norm], 1)
440
+ stds = np.std(matrix[mask_norm], 1)
441
+ thresholds = averages + (2*stds)
442
+
443
+ #hist of values
444
+ mv = matrix.values.flatten()
445
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
446
+ mv = mv[sampling]
447
+
448
+ fig, ax = plt.subplots(figsize=(16,6))
449
+ ax.hist(mv)
450
+ ax.set_title('Histogram of values')
451
+ fig.savefig(osp.join(outdir,'histogram.png'))
452
+ plt.close()
453
+
454
+
455
+ for gene_id in list(matrix.index):
456
+ print('{}/{}'.format(i, len(matrix)))
457
+ #mask of elements to use for normalization: the ones in control samples only
458
+ #mask of elements to binarize to 0 (samples in which gene_id is perturbed)
459
+ if gene_id in dict_gene_id_sample_id:
460
+ mask_pert = dict_gene_id_sample_id[gene_id]
461
+ else:
462
+ mask_pert = None
463
+ #normalize
464
+ threshold = thresholds.loc[gene_id]
465
+ matrix_binarized.loc[gene_id] = (matrix.loc[gene_id] >= threshold).astype(int).values
466
+ matrix_binarized.loc[gene_id][mask_pert] = 0
467
+ i+=1
468
+ #some stats
469
+ if mask_pert is not None:
470
+ gte = matrix.loc[gene_id][mask_pert] >= threshold
471
+ higher_than_thr += gte.values.astype(int).tolist()
472
+ higher_than_thr_ids += matrix.loc[gene_id][mask_pert].index[np.where(gte)].tolist()
473
+
474
+
475
+
476
+
477
+ ###Filter columns (samples) in which the perturbed gene has an expression value that is >= the threshold used to binarize
478
+ # log_handle.write('Filtering:\t{} columns/samples because the perturbed gene has an expression value >= the threshold used to binarize -- TEMPORARY STEP THAT SHOULD BE REMOVED LATER ON\n'.format(len(higher_than_thr_ids)))
479
+
480
+ # print('Filtering columns from data...')
481
+ # keep_columns = list(set(matrix_binarized.columns) - set(higher_than_thr_ids))
482
+ # matrix_binarized = matrix_binarized[keep_columns]
483
+
484
+
485
+
486
+ #plot higher than thr
487
+ fig, ax1 = plt.subplots(1, figsize=(16,6))
488
+ ax1.hist(higher_than_thr)
489
+ ax1.set_title('Perturbed genes values >= threshold')
490
+ fig.savefig(osp.join(outdir,'exploration_ge_crispr_higher_than_thr.png'))
491
+ log_handle.write('After binarizing, stats, perturbed gene values would be higher than threshold in :\t{} samples\n'.format(np.sum(higher_than_thr)))
492
+
493
+
494
+ #2. Save data and metadata for each condition and cell line
495
+ #CRISPR + cell lines
496
+ #Control + cell lines
497
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
498
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
499
+ metadata.index = metadata['sample_id']
500
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
501
+ for cell_line in keep_cell_lines:
502
+ for pert_type in ['trt_xpr', 'ctl_vector']:
503
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
504
+ data_i = matrix_binarized[metadata_i.index]
505
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
506
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
507
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
508
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
509
+ log_handle.write('\n\n------\nSTATS\n------\n')
510
+
511
+ return
512
+
513
+
514
+ def binarize_genewise_comparing_to_control(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
515
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
516
+ if use_log:
517
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm')
518
+ else:
519
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control')
520
+ os.makedirs(outdir, exist_ok= True)
521
+
522
+ ########################################################################################
523
+ #All data
524
+ metadata = pd.concat([inst_info_xpr, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
525
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
526
+ matrix = pd.concat([matrix_xpr, matrix_ctl], 1)
527
+
528
+
529
+ #0. create dictionary of gene_id: sample_id
530
+ #gene symbol -> gene id
531
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
532
+ #gene id -> sample id
533
+ dict_gene_id_sample_id= dict()
534
+ for i in range(len(inst_info_xpr)):
535
+ gene_symbol = inst_info_xpr.at[i, 'cmap_name']
536
+ gene_id = dict_symbol_id[gene_symbol]
537
+ if gene_id in dict_gene_id_sample_id:
538
+ dict_gene_id_sample_id[gene_id].append(inst_info_xpr.at[i, 'sample_id'])
539
+ else:
540
+ dict_gene_id_sample_id[gene_id] = [inst_info_xpr.at[i, 'sample_id']]
541
+
542
+
543
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
544
+
545
+ i = 1
546
+ higher_than_thr = []
547
+ higher_than_thr_ids = []
548
+ control_corrected = []
549
+ pert_corrected = []
550
+
551
+ #lognorm
552
+ if use_log:
553
+ matrix = np.log2(matrix + 1)
554
+
555
+ #hist of values
556
+ mv = matrix.values.flatten()
557
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
558
+ mv = mv[sampling]
559
+
560
+ fig, ax = plt.subplots(figsize=(16,6))
561
+ ax.hist(mv)
562
+ ax.set_title('Histogram of values')
563
+ fig.savefig(osp.join(outdir,'histogram.png'))
564
+ plt.close()
565
+
566
+ for cell_line in list(set(metadata['cell_iname'])):
567
+ matrix_i = matrix[metadata[metadata['cell_iname']==cell_line]['sample_id']]
568
+ #Normalization
569
+ #1. Iterate through each gene, mask out the samples in which it was perturbed, and normalize --> set to 1 those genes that have value of average + 2std higher than control
570
+ #for the perturbed genes = 0
571
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
572
+ mask_norm = list(set(matrix_ctl.columns).intersection(set(matrix_i.columns))) #mask_norm is controls only (for specific cell line 'cell_line')
573
+ control_corrected += mask_norm
574
+ averages = np.mean(matrix[mask_norm], 1)
575
+ stds = np.std(matrix[mask_norm], 1)
576
+ thresholds = averages + (2*stds)
577
+ for gene_id in list(matrix_i.index):
578
+ #mask of elements to use for normalization: the ones in control samples only
579
+ #mask of elements to binarize to 0 (samples in which gene_id is perturbed)
580
+ if gene_id in dict_gene_id_sample_id:
581
+ mask_pert = list(set(dict_gene_id_sample_id[gene_id]).intersection(set(matrix_i.columns))) #mask_pert for specific cell line 'cell_line'
582
+ pert_corrected += mask_pert
583
+ else:
584
+ mask_pert = []
585
+ #normalize
586
+ threshold = thresholds.loc[gene_id]
587
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
588
+ matrix_binarized.loc[gene_id][mask_pert] = 0
589
+ #some stats
590
+ if mask_pert != []:
591
+ gte = matrix_i.loc[gene_id][mask_pert] >= threshold
592
+ higher_than_thr += gte.values.astype(int).tolist()
593
+ higher_than_thr_ids += matrix_i.loc[gene_id][mask_pert].index[np.where(gte)].tolist()
594
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
595
+ i+=1
596
+
597
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), len(inst_info_ctl)))
598
+ print('Perturbed covered:{}/{}\n'.format(len(pert_corrected), len(inst_info_xpr)))
599
+
600
+ ###Filter columns (samples) in which the perturbed gene has an expression value that is >= the threshold used to binarize
601
+ # log_handle.write('Filtering:\t{} columns/samples because the perturbed gene has an expression value >= the threshold used to binarize -- TEMPORARY STEP THAT SHOULD BE REMOVED LATER ON\n'.format(len(higher_than_thr_ids)))
602
+
603
+ # print('Filtering columns from data...')
604
+ # keep_columns = list(set(matrix_binarized.columns) - set(higher_than_thr_ids))
605
+ # matrix_binarized = matrix_binarized[keep_columns]
606
+
607
+
608
+
609
+ #plot higher than thr
610
+ fig, ax1 = plt.subplots(1, figsize=(16,6))
611
+ ax1.hist(higher_than_thr)
612
+ ax1.set_title('Perturbed genes values >= threshold')
613
+ fig.savefig(osp.join(outdir,'exploration_ge_crispr_higher_than_thr.png'))
614
+ log_handle.write('After binarizing, stats, perturbed gene values would be higher than threshold in :\t{} samples\n'.format(np.sum(higher_than_thr)))
615
+
616
+
617
+ #2. Save data and metadata for each condition and cell line
618
+ #CRISPR + cell lines
619
+ #Control + cell lines
620
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
621
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
622
+ metadata.index = metadata['sample_id']
623
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
624
+ for cell_line in keep_cell_lines:
625
+ for pert_type in ['trt_xpr', 'ctl_vector']:
626
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
627
+ data_i = matrix_binarized[metadata_i.index]
628
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
629
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
630
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
631
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
632
+ log_handle.write('\n\n------\nSTATS\n------\n')
633
+
634
+ return
635
+
636
+
637
+
638
+
639
+
640
+ def binarize_genewise_comparing_to_control_augmented(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
641
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
642
+ if use_log:
643
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm/augmented')
644
+ else:
645
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control/augmented')
646
+ os.makedirs(outdir, exist_ok= True)
647
+
648
+ ########################################################################################
649
+ #All data
650
+ metadata = pd.concat([inst_info_xpr, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
651
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
652
+ matrix = pd.concat([matrix_xpr, matrix_ctl], 1)
653
+
654
+
655
+ #0. create dictionary of gene_id: sample_id
656
+ #gene symbol -> gene id
657
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
658
+ #gene id -> sample id
659
+ dict_gene_id_sample_id= dict()
660
+ for i in range(len(inst_info_xpr)):
661
+ gene_symbol = inst_info_xpr.at[i, 'cmap_name']
662
+ gene_id = dict_symbol_id[gene_symbol]
663
+ if gene_id in dict_gene_id_sample_id:
664
+ dict_gene_id_sample_id[gene_id].append(inst_info_xpr.at[i, 'sample_id'])
665
+ else:
666
+ dict_gene_id_sample_id[gene_id] = [inst_info_xpr.at[i, 'sample_id']]
667
+
668
+ #lognorm
669
+ if use_log:
670
+ matrix = np.log2(matrix + 1)
671
+
672
+ matrix_augmented = matrix.copy()
673
+ ###Data augmentation using Gaussian noise
674
+ AUG_PROPORTION = 5
675
+ columns = matrix.columns
676
+ for i in range(AUG_PROPORTION):
677
+ columns_i = [e+'___{}'.format(i) for e in columns]
678
+ noise = np.random.normal(0,1,matrix.shape)
679
+ to_add = pd.DataFrame(matrix.values + noise, columns = columns_i, index = matrix.index)
680
+ matrix_augmented = pd.concat([matrix_augmented, to_add], 1)
681
+
682
+
683
+ matrix = matrix_augmented
684
+
685
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
686
+
687
+ i = 1
688
+ higher_than_thr = []
689
+ higher_than_thr_ids = []
690
+ control_corrected = []
691
+ pert_corrected = []
692
+
693
+
694
+
695
+ #hist of values
696
+ # mv = matrix.values.flatten()
697
+ # sampling = sample(range(len(mv)), int(0.005*len(mv)))
698
+ # mv = mv[sampling]
699
+
700
+ # fig, ax = plt.subplots(figsize=(16,6))
701
+ # ax.hist(mv)
702
+ # ax.set_title('Histogram of values')
703
+ # fig.savefig(osp.join(outdir,'histogram.png'))
704
+ # plt.close()
705
+
706
+ for cell_line in list(set(metadata['cell_iname'])):
707
+ columns = metadata[metadata['cell_iname']==cell_line]['sample_id'].tolist()
708
+ columns_augmented = [e+'___{}'.format(i) for i in range(AUG_PROPORTION) for e in columns] + columns
709
+ columns = columns_augmented
710
+ matrix_i = matrix[columns]
711
+ #Normalization
712
+ #1. Iterate through each gene, mask out the samples in which it was perturbed, and normalize --> set to 1 those genes that have value of average + 2std higher than control
713
+ #for the perturbed genes = 0
714
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
715
+ columns_control = list(matrix_ctl.columns)
716
+ columns_control = [e+'___{}'.format(i) for i in range(AUG_PROPORTION) for e in columns_control] + columns_control
717
+ columns_i = list(matrix_i.columns)
718
+ mask_norm = list(set(columns_control).intersection(set(columns_i))) #mask_norm is controls only (for specific cell line 'cell_line')
719
+ control_corrected += mask_norm
720
+ averages = np.mean(matrix[mask_norm], 1)
721
+ stds = np.std(matrix[mask_norm], 1)
722
+ thresholds = averages + (2*stds)
723
+
724
+ for gene_id in list(matrix_i.index):
725
+ #mask of elements to use for normalization: the ones in control samples only
726
+ #mask of elements to binarize to 0 (samples in which gene_id is perturbed)
727
+ if gene_id in dict_gene_id_sample_id:
728
+ samples_perturbed = dict_gene_id_sample_id[gene_id]
729
+ samples_perturbed = [e+'___{}'.format(i) for i in range(AUG_PROPORTION) for e in samples_perturbed] + samples_perturbed
730
+ mask_pert = list(set(samples_perturbed).intersection(set(matrix_i.columns))) #mask_pert for specific cell line 'cell_line'
731
+ pert_corrected += mask_pert
732
+ else:
733
+ mask_pert = []
734
+ #normalize
735
+ threshold = thresholds.loc[gene_id]
736
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
737
+ matrix_binarized.loc[gene_id][mask_pert] = 0
738
+ #some stats
739
+ if mask_pert != []:
740
+ gte = matrix_i.loc[gene_id][mask_pert] >= threshold
741
+ higher_than_thr += gte.values.astype(int).tolist()
742
+ higher_than_thr_ids += matrix_i.loc[gene_id][mask_pert].index[np.where(gte)].tolist()
743
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
744
+ i+=1
745
+
746
+ # print('Controls covered:{}/{}\n'.format(len(control_corrected), len(inst_info_ctl)))
747
+ # print('Perturbed covered:{}/{}\n'.format(len(pert_corrected), len(inst_info_xpr)))
748
+
749
+ ###Filter columns (samples) in which the perturbed gene has an expression value that is >= the threshold used to binarize
750
+ # log_handle.write('Filtering:\t{} columns/samples because the perturbed gene has an expression value >= the threshold used to binarize -- TEMPORARY STEP THAT SHOULD BE REMOVED LATER ON\n'.format(len(higher_than_thr_ids)))
751
+
752
+ # print('Filtering columns from data...')
753
+ # keep_columns = list(set(matrix_binarized.columns) - set(higher_than_thr_ids))
754
+ # matrix_binarized = matrix_binarized[keep_columns]
755
+
756
+
757
+
758
+ #plot higher than thr
759
+ fig, ax1 = plt.subplots(1, figsize=(16,6))
760
+ ax1.hist(higher_than_thr)
761
+ ax1.set_title('Perturbed genes values >= threshold')
762
+ fig.savefig(osp.join(outdir,'exploration_ge_crispr_higher_than_thr.png'))
763
+ log_handle.write('After binarizing, stats, perturbed gene values would be higher than threshold in :\t{} samples\n'.format(np.sum(higher_than_thr)))
764
+
765
+
766
+ #2. Save data and metadata for each condition and cell line
767
+ #CRISPR + cell lines
768
+ #Control + cell lines
769
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
770
+ log_handle.write('CELL\tPERT\t\tSIZE\tAUGMENTED SIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
771
+ metadata.index = metadata['sample_id']
772
+ # metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
773
+ for cell_line in keep_cell_lines:
774
+ for pert_type in ['trt_xpr', 'ctl_vector']:
775
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
776
+ columns = list(metadata_i.index)
777
+ to_add = []
778
+ for i in range(AUG_PROPORTION):
779
+ to_add += [e+'___{}'.format(i) for e in columns]
780
+ columns = columns + to_add
781
+ data_i = matrix_binarized[columns]
782
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
783
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
784
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
785
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), data_i.shape[1], len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
786
+ log_handle.write('\n\n------\nSTATS\n------\n')
787
+
788
+ return
789
+
790
+
791
+
792
+
793
+ def normalize_and_save(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
794
+ log_handle.write('\n\n------\nNORMALIZE DATA AND SAVE\n------\n')
795
+ if use_log:
796
+ outdir = osp.join(outdir, 'real_lognorm')
797
+ else:
798
+ outdir = osp.join(outdir, 'real')
799
+ os.makedirs(outdir, exist_ok= True)
800
+
801
+
802
+ #All data
803
+ metadata = pd.concat([inst_info_xpr, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
804
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
805
+ matrix = pd.concat([matrix_xpr, matrix_ctl], 1)
806
+ del(matrix_xpr)
807
+
808
+ #hist of values before lognorm
809
+ mv = matrix.values.flatten()
810
+ sampling = sample(range(len(mv)), int(0.001*len(mv)))
811
+ mv = mv[sampling]
812
+
813
+ fig, ax = plt.subplots(figsize=(16,6))
814
+ ax.hist(mv)
815
+ ax.set_title('Histogram of values')
816
+ fig.savefig(osp.join(outdir,'histogram_raw.png'))
817
+ plt.close()
818
+
819
+ #NORMALIZATION
820
+ #lognorm + minmax
821
+ if use_log:
822
+ matrix = np.log2(matrix + 1)
823
+
824
+ scaler = MinMaxScaler((0,1))
825
+ matrix = matrix.transpose()
826
+ matrix = pd.DataFrame(scaler.fit_transform(matrix), columns = matrix.columns, index = matrix.index)
827
+ matrix = matrix.transpose()
828
+
829
+
830
+
831
+ #hist of values after lognorm
832
+ mv = matrix.values.flatten()
833
+ sampling = sample(range(len(mv)), int(0.001*len(mv)))
834
+ mv = mv[sampling]
835
+
836
+ fig, ax = plt.subplots(figsize=(16,6))
837
+ ax.hist(mv)
838
+ ax.set_title('Histogram of values')
839
+ fig.savefig(osp.join(outdir,'histogram_lognorm.png'))
840
+ plt.close()
841
+
842
+ #2. Save data and metadata for each condition and cell line
843
+ #Compound + cell lines
844
+ #Control + cell lines
845
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
846
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
847
+ metadata.index = metadata['sample_id']
848
+ metadata = metadata.loc[matrix.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
849
+ for cell_line in keep_cell_lines:
850
+ for pert_type in ['trt_xpr', 'ctl_vector']:
851
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
852
+ data_i = matrix[metadata_i.index]
853
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
854
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
855
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
856
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['pert_id'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
857
+ log_handle.write('\n\n------\nSTATS\n------\n')
858
+
859
+ return
860
+
861
+
862
+
863
+
864
+ def main():
865
+
866
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
867
+ log_handle = open(osp.join(outdir, 'process_data_lognorm.txt'), 'w')
868
+ inst_info_xpr, inst_info_ctl, gene_info, matrix_xpr, matrix_ctl = loads_data(DATA_ROOT, log_handle)
869
+ inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl = filter_data_metadata(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle)
870
+ inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, keep_cell_lines = filter_cell_lines_custom(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle)
871
+ # inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, keep_cell_lines = filter_cell_lines(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, log_handle)
872
+ inst_info_xpr, matrix_xpr = filter_samples_with_unknown_perturbed_genes(inst_info_xpr, matrix_xpr, gene_info, log_handle)
873
+ use_log=True
874
+ normalize_and_save(inst_info_xpr, matrix_xpr, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log)
875
+ log_handle.close()
876
+
877
+
878
+ if __name__ == "__main__":
879
+ main()
880
+
881
+
PDGrapher/data/scripts/lincs/process_data_chemical_1.py ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Find drug targets in DrugBank, maps drugs to drugs in LINCS
3
+ '''
4
+
5
+
6
+ import pandas as pd
7
+ from rdkit import Chem
8
+ import numpy as np
9
+ import matplotlib.pyplot as plt
10
+ import json
11
+
12
+ import os
13
+ import csv
14
+ import gzip
15
+ import collections
16
+ import re
17
+ import io
18
+ import json
19
+ import os.path as osp
20
+ import xml.etree.ElementTree as ET
21
+
22
+ import requests
23
+ from bs4 import BeautifulSoup
24
+ import pickle
25
+
26
+ outdir = '../../processed/lincs/chemical'
27
+ os.makedirs(outdir, exist_ok=True)
28
+ outdir_df = '../../processed/lincs/chemical/dataframes/'
29
+ os.makedirs(outdir_df, exist_ok=True)
30
+
31
+
32
+ def load_data(DATA_ROOT,log_handle):
33
+
34
+
35
+ ###Load LINCS Data
36
+ df_lincs=pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
37
+ df_cpmeta=pd.read_csv(os.path.join(DATA_ROOT, 'compoundinfo_beta.txt'), sep="\t", low_memory=False)
38
+
39
+ df_trtcp=df_lincs.loc[np.logical_and(df_lincs['pert_type'] == 'trt_cp', df_lincs['failure_mode'].isna())]
40
+ unique_cp=df_trtcp.pert_id.unique()
41
+
42
+ log_handle.write('LINCS Compound Data\n------\n')
43
+ log_handle.write('Compound treatments in inst_info:\t{}\n'.format(df_trtcp.shape[0]))
44
+ log_handle.write('Unique pert_ids:\t{}\n'.format(df_cpmeta.pert_id.unique().shape[0]))
45
+ log_handle.write('Unique inchi_keys:\t{}\n'.format(df_cpmeta.inchi_key.unique().shape[0]))
46
+
47
+ ###Load DrugBank Data
48
+ DATAROOT= '../../raw/drugbank/2022-11-DrugBank/data/'
49
+ xml_path = os.path.join(DATAROOT, 'all-full-database.xml')
50
+ with open(xml_path) as xml_file:
51
+ tree = ET.parse(xml_file)
52
+ root = tree.getroot()
53
+
54
+
55
+ ns = '{http://www.drugbank.ca}'
56
+ inchikey_template = "{ns}calculated-properties/{ns}property[{ns}kind='InChIKey']/{ns}value"
57
+ inchi_template = "{ns}calculated-properties/{ns}property[{ns}kind='InChI']/{ns}value"
58
+ SMILES_template = "{ns}calculated-properties/{ns}property[{ns}kind='SMILES']/{ns}value"
59
+
60
+
61
+ rows = list()
62
+
63
+
64
+
65
+ for i, drug in enumerate(root):
66
+ row = collections.OrderedDict()
67
+ assert drug.tag == ns + 'drug'
68
+ row['type'] = drug.get('type')
69
+ row['drugbank_id'] = drug.findtext(ns + "drugbank-id[@primary='true']")
70
+ row['name'] = drug.findtext(ns + "name")
71
+ row['description'] = drug.findtext(ns + "description")
72
+ row['groups'] = [group.text for group in
73
+ drug.findall("{ns}groups/{ns}group".format(ns = ns))]
74
+ row['atc_codes'] = [code.get('code') for code in
75
+ drug.findall("{ns}atc-codes/{ns}atc-code".format(ns = ns))]
76
+
77
+ row['categories'] = [x.findtext(ns + 'category') for x in
78
+ drug.findall("{ns}categories/{ns}category".format(ns = ns))]
79
+
80
+ row['inchi'] = drug.findtext(inchi_template.format(ns = ns))
81
+ row['inchi_key'] = drug.findtext(inchikey_template.format(ns = ns))
82
+ row['SMILES']=drug.findtext(SMILES_template.format(ns=ns))
83
+
84
+ # Add drug aliases
85
+ aliases = {
86
+ elem.text for elem in
87
+ drug.findall("{ns}international-brands/{ns}international-brand".format(ns = ns)) +
88
+ drug.findall("{ns}synonyms/{ns}synonym[@language='English']".format(ns = ns)) +
89
+ drug.findall("{ns}international-brands/{ns}international-brand".format(ns = ns)) +
90
+ drug.findall("{ns}products/{ns}product/{ns}name".format(ns = ns))
91
+
92
+ }
93
+ aliases.add(row['name'])
94
+ row['aliases'] = sorted(aliases)
95
+
96
+ rows.append(row)
97
+
98
+ columns = ['drugbank_id', 'name', 'type', 'groups', 'atc_codes', 'categories', 'inchi_key', 'inchi','SMILES', 'description']
99
+ drugbank_df = pd.DataFrame.from_dict(rows)[columns]
100
+ drugbank_slim_df = drugbank_df[
101
+ drugbank_df.inchi.map(lambda x: x is not None) &
102
+ drugbank_df.SMILES.map(lambda x: x is not None)
103
+ ]
104
+ return drugbank_slim_df, unique_cp, df_cpmeta
105
+
106
+
107
+
108
+
109
+
110
+
111
+ ### Matching pert_ids to DrugBankIDs
112
+
113
+ def pert_id2inchikey(pertid, df):
114
+ """Returns InChIKey of the corresponding pert_id"""
115
+
116
+
117
+ pertid_index=df.index[df['pert_id']==pertid][0]
118
+ return (pertid_index, df.at[pertid_index,'inchi_key'])
119
+
120
+
121
+ def df_pert_id2inchikey(pert_idarr, df_cpmeta):
122
+ """ Returns a DataFrame with corresponding InChIKeys of each pert_id in pert_idarr"""
123
+
124
+ d = {'pert_id': [], 'compoundinfo_index': [], 'inchi_key': []}
125
+ for i in range(len(pert_idarr)):
126
+ d['pert_id'].append(pert_idarr[i])
127
+ index, inchikey = pert_id2inchikey(pert_idarr[i], df_cpmeta)
128
+ d['compoundinfo_index'].append(index)
129
+ d['inchi_key'].append(inchikey)
130
+ inchikey_df=pd.DataFrame(data=d)
131
+ return inchikey_df
132
+
133
+
134
+ def df_DrugBankCol_inchi(df,drugbank_slim_df):
135
+ """Adds a column to df with InChIKeys mapped to DrugBank IDs from drugbank_canSmiles_df"""
136
+ in_drugbank = set(list(drugbank_slim_df['inchi_key']))
137
+ assert 'inchi_key' in df.columns.values
138
+ for i in range(df.shape[0]):
139
+ inchikey = df['inchi_key'][i]
140
+ if type(inchikey) ==float:
141
+ df.at[i,"DrugBank_ID"] = "None"
142
+ else:
143
+ if inchikey not in in_drugbank:
144
+ df.at[i,"DrugBank_ID"] = "Not in DrugBank"
145
+ else:
146
+ ik_index=drugbank_slim_df.index[drugbank_slim_df['inchi_key']==inchikey][0]
147
+ x= (ik_index, drugbank_slim_df.at[ik_index,'drugbank_id'])
148
+ df.at[i,"DrugBank_ID"] = x[1]
149
+ return df
150
+
151
+
152
+
153
+ def createMappedDF(df):
154
+ """Returns a copy of the df that were mapped to DrugBankIDs"""
155
+ df_new = df.copy(deep=True)
156
+ df_new=df_new.loc[(df_new['DrugBank_ID']!='Not in DrugBank')&(df_new['DrugBank_ID']!= "None")]
157
+ df_new.reset_index(drop=True, inplace=True)
158
+ return df_new
159
+
160
+
161
+
162
+
163
+
164
+ ### Load DrugBank targets
165
+ def load_targets_drugbank(path):
166
+ return pd.read_csv(path)
167
+
168
+
169
+ def summarize_drugbank_targets(mapped_DrugBankDF, df_targets):
170
+ mapped_DrugBankDF_new = mapped_DrugBankDF.copy(deep=True)
171
+ mapped_DrugBankDF_new['targets'] = ''
172
+ for i in range(len(mapped_DrugBankDF)):
173
+ dbid = mapped_DrugBankDF['DrugBank_ID'].tolist()[i]
174
+ targets = df_targets[df_targets['DrugBank_ID']==dbid]['idd'].tolist()
175
+ mapped_DrugBankDF_new.at[i, 'targets'] = targets
176
+ return mapped_DrugBankDF_new
177
+
178
+
179
+
180
+
181
+ def countTargets(df):
182
+ #Counts number of DrugBank Targets and adds column called "num_targets"
183
+ df['num_targets']=0
184
+ for i in range(df.shape[0]):
185
+ if df.notna().at[i,'targets']:
186
+ str_list=df.at[i,'targets']
187
+ df.at[i,'num_targets']=len(df.at[i,'targets'])
188
+ return df
189
+
190
+
191
+
192
+ def target_stats(df_targets, log_handle):
193
+ #Calculates statistics on number of DrugBank targets and plots distribution
194
+ log_handle.write('DrugBank Target Stats\n------\n')
195
+ for index,value in pd.Series.iteritems(pd.DataFrame(df_targets['num_targets']).describe()):
196
+ log_handle.write('{}:\t{}\n'.format(index, value))
197
+ x = list(df_targets['num_targets'])
198
+ fig, ax1 = plt.subplots()
199
+ ax1.hist(np.clip(x,0,30), bins=60)
200
+ ax1.set_xlabel("# of Targets")
201
+ ax1.set_ylabel("# of Compounds")
202
+ ax1.set_title('Number of DrugBank Targets')
203
+ fig.savefig(osp.join(outdir,'num_target_distribution.png'))
204
+
205
+
206
+
207
+ def main():
208
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
209
+ log_handle = open(osp.join(outdir, 'log_process_data_chemical_1.txt'), 'w')
210
+ drugbank_slim_df, unique_cp, df_cpmeta = load_data(DATA_ROOT, log_handle)
211
+
212
+ #Creating DataFrame mapping pert_id to InChIKeys from compoundinfo
213
+ pert_id_inchikeyDF=df_pert_id2inchikey(unique_cp, df_cpmeta)
214
+
215
+
216
+ #Adding the column with corresponding DrugBank IDs
217
+ pert_id_DrugBankDF=df_DrugBankCol_inchi(pert_id_inchikeyDF,drugbank_slim_df)
218
+ mapped_DrugBankDF=createMappedDF(pert_id_DrugBankDF)
219
+
220
+ log_handle.write('Fraction of compounds found in DrugBank:\t{}/{}\n'.format(mapped_DrugBankDF.shape[0],pert_id_DrugBankDF.shape[0]))
221
+
222
+
223
+ #Loads targets from DrugBank
224
+
225
+ df_targets = load_targets_drugbank('../../processed/drugbank/targets.txt')
226
+ df_targets.columns = ['DrugBank_ID', 'DrugBank_name', 'synonyms', 'idd', 'name', 'gene_name', 'gene_synonyms', 'identifiers', 'organism']
227
+
228
+ #Summarizes DrugBank targets in mapped_DrugBankDF
229
+
230
+ mapped_DrugBankDF = summarize_drugbank_targets(mapped_DrugBankDF, df_targets)
231
+ mapped_DrugBankDF=countTargets(mapped_DrugBankDF)
232
+
233
+
234
+ target_stats(mapped_DrugBankDF, log_handle)
235
+ no_targets=mapped_DrugBankDF.loc[mapped_DrugBankDF['num_targets']==0].shape[0]
236
+ log_handle.write('Fraction of compounds without DrugBank targets:\t{}/{}\n'.format(no_targets,mapped_DrugBankDF.shape[0]))
237
+
238
+
239
+ with open(osp.join(outdir_df,"df_targets.pickle"), 'wb') as f:
240
+ pickle.dump(mapped_DrugBankDF, f)
241
+ mapped_DrugBankDF.to_csv(osp.join(outdir_df,"df_targets.csv"))
242
+
243
+
244
+
245
+ if __name__ == "__main__":
246
+ main()
247
+
248
+
249
+
PDGrapher/data/scripts/lincs/process_data_chemical_2.py ADDED
@@ -0,0 +1,697 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Normalizes perturbed (treated) and control (diseased) data of chemical interventions
3
+ Saves data as npz
4
+
5
+ 1. Reads data (load_data)
6
+ 2. Filters to keep only the cell lines that we use in experiments (filter_cell_lines_custom)
7
+ 3. Filters to keep only the samples in metadata (filter_data_metadata)
8
+ 4. Maps drug gene targets to LINCS genes (map_gene_targets_to_lincs)
9
+ 5. Filters out samples for which the drug targets are not in LINCS genes (filter_samples_with_unknown_perturbed_genes)
10
+ 6. Normalizes data between (0,1) and save (normalize_and_save)
11
+ '''
12
+ import pandas as pd
13
+ import h5py
14
+ import os
15
+ import matplotlib.pyplot as plt
16
+ import seaborn as sns
17
+ import os.path as osp
18
+ import numpy as np
19
+ from collections import Counter
20
+ import matplotlib.pyplot as plt
21
+ from sklearn.preprocessing import MinMaxScaler
22
+ import math
23
+ from random import sample
24
+
25
+
26
+ import networkx as nx
27
+ import csrgraph as cg
28
+ import os
29
+ import itertools
30
+ import json
31
+ import operator
32
+ import swifter
33
+ from tqdm import tqdm
34
+ import time
35
+ import pickle
36
+
37
+
38
+ #LOG
39
+
40
+
41
+ ################
42
+ # Data loading
43
+ ################
44
+
45
+ def get_gene_names(x, dict_id_names):
46
+ # Returns a list of gene names for each protein ID (node ID of protein).
47
+ # If there is more than one gene name for a given ID, a list of all of them are given.
48
+ gene_names = []
49
+ for gene_id in x:
50
+ gname = dict_id_names[gene_id]
51
+ if gname ==[]:
52
+ continue
53
+ else:
54
+ gene_names.append(dict_id_names[gene_id])
55
+ return gene_names
56
+
57
+
58
+
59
+ def targetList(pid,dict_pid_target_names):
60
+ if pid not in dict_pid_target_names:
61
+ return []
62
+ else:
63
+ return dict_pid_target_names[pid]
64
+
65
+
66
+
67
+
68
+ def loads_data(DATA_ROOT, log_handle):
69
+
70
+ #Loads metadata
71
+ inst_info = pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
72
+ inst_info_cp = inst_info[np.logical_and(inst_info['pert_type'] == 'trt_cp', inst_info['failure_mode'].isna())].reset_index(inplace=False, drop=True)
73
+ inst_info_ctl = inst_info[np.logical_and(inst_info['pert_type'] == 'ctl_vehicle', inst_info['failure_mode'].isna()) ].reset_index(inplace=False, drop=True)
74
+ gene_info = pd.read_csv(os.path.join(DATA_ROOT, 'geneinfo_beta.txt'), sep="\t", low_memory=False)
75
+
76
+ with open('../../processed/lincs/chemical/dataframes/df_targets.pickle', 'rb') as f:
77
+ df_targets = pickle.load(f)
78
+
79
+
80
+
81
+ drugbank_targets=pd.read_csv("../../processed/drugbank/targets.txt")
82
+
83
+ dict_id_names = dict()
84
+ for i in range(len(drugbank_targets)):
85
+ name = drugbank_targets.at[i, 'gene_name']
86
+ if name != '-':
87
+ dict_id_names[drugbank_targets.at[i,'target_id']] = [drugbank_targets.at[i,'gene_name']]
88
+ else:
89
+ dict_id_names[drugbank_targets.at[i,'target_id']] = []
90
+ synonyms = drugbank_targets.at[i, 'gene_synonyms']
91
+ if synonyms != '-' and str(synonyms) != 'nan':
92
+ dict_id_names[drugbank_targets.at[i,'target_id']] += synonyms.split('||')
93
+
94
+
95
+ df_targets['target_names']=df_targets['targets'].apply(lambda x: get_gene_names(x, dict_id_names))
96
+ dict_pid_target_names = dict(zip(df_targets['pert_id'], df_targets['target_names']))
97
+ inst_info_cp['drugbank_target_names']=inst_info_cp['pert_id'].apply(lambda x: targetList(x,dict_pid_target_names))
98
+
99
+
100
+ ####################
101
+ #Loads data matrices
102
+ ### Compound
103
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_trt_cp_n1805898x12328.gctx'), 'r')
104
+ matrix_cp = f['0']['DATA']['0']['matrix'][:].transpose()
105
+ gene_ids_cp = f['0']['META']['ROW']['id'][:]
106
+ sample_ids_cp = f['0']['META']['COL']['id'][:]
107
+ matrix_cp = pd.DataFrame(matrix_cp, columns = sample_ids_cp.astype(str), index = gene_ids_cp.astype(int))
108
+ del f
109
+
110
+
111
+ #re-order gene_info based on the order in gene_ids_cp (rows of data)
112
+ gene_info.index = gene_info['gene_id']
113
+ gene_info = gene_info.loc[gene_ids_cp.astype(int)].reset_index(inplace=False, drop=True)
114
+ gene_info.to_csv(osp.join(outdir, 'gene_info.txt'), index=False)
115
+
116
+ #Stats
117
+ log_handle.write('Compounds\n------\n')
118
+ log_handle.write('Compound entries in inst_info metadata:\t{}\n'.format(len(inst_info_cp)))
119
+ log_handle.write('Compound entries in data matrix:\t{}\n'.format(len(sample_ids_cp)))
120
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_cp['sample_id']).intersection(set(sample_ids_cp.astype(str))))))
121
+
122
+
123
+
124
+ ### Control data
125
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_ctl_n188708x12328.gctx'), 'r')
126
+ matrix_ctl = f['0']['DATA']['0']['matrix'][:].transpose()
127
+ gene_ids_ctl = f['0']['META']['ROW']['id'][:] #not in the same order as gene_ids_cp
128
+ sample_ids_ctl = f['0']['META']['COL']['id'][:]
129
+ matrix_ctl = pd.DataFrame(matrix_ctl, columns = sample_ids_ctl.astype(str), index = gene_ids_ctl.astype(int))
130
+ del f
131
+
132
+
133
+ #Stats
134
+ log_handle.write('CONTROL\n------\n')
135
+ log_handle.write('Control entries in inst_info metadata:\t{}\n'.format(len(inst_info_ctl)))
136
+ log_handle.write('Control entries in data matrix:\t{}\n'.format(len(sample_ids_ctl)))
137
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_ctl['sample_id']).intersection(set(sample_ids_ctl.astype(str))))))
138
+ log_handle.write('\n------\n')
139
+
140
+
141
+ # stats_data(inst_info_cp, matrix_cp, matrix_ctl, gene_info, df_targets)
142
+
143
+ return sample_ids_cp, inst_info_cp, inst_info_ctl, gene_info, matrix_cp, matrix_ctl, df_targets
144
+
145
+
146
+
147
+
148
+
149
+ def stats_data(inst_info_cp, matrix_cp, matrix_ctl, gene_info, df_targets):
150
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
151
+ dict_pert_id = dict(zip(df_targets['pert_id'], df_targets['target_names']))
152
+
153
+ ####Data exploration -- GE values of genes that are perturbed (!)
154
+ #Get GE value for each gene perturbed by Compound
155
+ values_pert = {}
156
+ values_control = {}
157
+ for i in range(len(inst_info_cp)):
158
+ pert_id = inst_info_cp.at[i, 'pert_id']
159
+ if pert_id in dict_pert_id:
160
+ gene_symbols=dict_pert_id[pert_id]
161
+ if type(gene_symbols)==list:
162
+ for j in range(len(gene_symbols)):
163
+
164
+ if gene_symbols[j] in dict_symbol_id: #if the cmap_name of gene is in the gene_info
165
+ sample_id = inst_info_cp.at[i, 'sample_id']
166
+ gene_id = dict_symbol_id[gene_symbols[j]]
167
+ if gene_id in values_pert:
168
+ values_pert[gene_id].append(matrix_cp.at[gene_id, sample_id])
169
+ else:
170
+ values_pert[gene_id] = [matrix_cp.at[gene_id, sample_id]]
171
+
172
+
173
+
174
+ for pert_id in list(set(inst_info_cp['pert_id'])):
175
+ if pert_id in dict_pert_id:
176
+ gene_symbols=dict_pert_id[pert_id]
177
+ if type(gene_symbols)==list:
178
+ for z in range(len(gene_symbols)):
179
+
180
+
181
+
182
+ if gene_symbols[z] in dict_symbol_id: #if the cmap_name of gene is in the gene_info
183
+ gene_id = dict_symbol_id[gene_symbols[z]]
184
+ values_control[gene_id] = [matrix_ctl.loc[gene_id]]
185
+
186
+ for key in values_pert:
187
+ values_pert[key] = np.mean(values_pert[key])
188
+
189
+ for key in values_control:
190
+ values_control[key] = np.mean(values_control[key])
191
+
192
+ fig, (ax1, ax2) = plt.subplots(2, figsize=(16,6))
193
+ ax1.hist(values_pert.values())
194
+ ax2.hist(values_control.values())
195
+ ax1.set_title('Values of perturbed genes (avg) - Compounds')
196
+ ax2.set_title('Values of genes in control (avg)')
197
+ fig.savefig(osp.join(outdir,'exploration_ge_compounds.png'))
198
+
199
+
200
+ return
201
+
202
+
203
+
204
+
205
+ ################
206
+ # Processing
207
+ ################
208
+
209
+
210
+ ################
211
+ #1. Filter to keep only cell lines with more perturbations
212
+
213
+ def stats_control(inst_info_ctl, log_handle):
214
+ log_handle.write('STATS CONTROL DATA\n***********************************\n')
215
+ #Stats unique cell lines
216
+ log_handle.write('Unique cell lines:\t{}:\n'.format(len(set(inst_info_ctl['cell_iname']))))
217
+ for c in list(set(inst_info_ctl['cell_iname'])):
218
+ log_handle.write('\t{}\n'.format(c))
219
+
220
+ log_handle.write('\n\n')
221
+
222
+ #Stats on dosages
223
+ df_ctl = pd.DataFrame(inst_info_ctl[['cmap_name', 'cell_iname', 'pert_idose']].groupby(['cmap_name', 'cell_iname']).apply(lambda x: x['pert_idose'].unique()))
224
+ df_ctl = pd.DataFrame([(i, len(df_ctl.loc[i][0])) for i in df_ctl.index], columns =['cmap_name-cell_line', 'n_doses'])
225
+ log_handle.write('Stats on dosages and timepoints\n')
226
+ log_handle.write('\n------\nHOW MANY DOSES ARE THERE FOR CMAP_NAME-CELL LINE PAIRS?\n------\n')
227
+ for index,value in pd.Series.iteritems(pd.DataFrame(df_ctl['n_doses'])['n_doses'].describe()):
228
+ log_handle.write('{}:\t{}\n'.format(index, value))
229
+
230
+ log_handle.write('\n')
231
+ log_handle.write('Number of pairs with more than 1 dose:\t{}/{}\n'.format(sum(df_ctl['n_doses']>1), len(df_ctl)))
232
+ log_handle.write('Number of pairs with more than 2 doses:\t{}/{}\n\n'.format(sum(df_ctl['n_doses']>2), len(df_ctl)))
233
+
234
+ #Stats on timepoints
235
+ df_ctl = pd.DataFrame(inst_info_ctl[['cmap_name', 'cell_iname', 'pert_time']].groupby(['cmap_name', 'cell_iname']).apply(lambda x: x['pert_time'].unique()))
236
+ df_ctl = pd.DataFrame([(i, len(df_ctl.loc[i][0])) for i in df_ctl.index], columns =['cmap_name-cell_line', 'n_times'])
237
+
238
+ log_handle.write('\n------\nHOW MANY TIMEPOINTS ARE THERE FOR CMAP_NAME-CELL LINE PAIRS?\n------\n')
239
+ for index,value in pd.Series.iteritems(pd.DataFrame(df_ctl['n_times'])['n_times'].describe()):
240
+ log_handle.write('{}:\t{}\n'.format(index, value))
241
+
242
+ log_handle.write('\n')
243
+ log_handle.write('Number of pairs with more than 1 timepoint:\t{}/{}\n'.format(sum(df_ctl['n_times']>1), len(df_ctl['n_times'])))
244
+ log_handle.write('Number of pairs with more than 2 timepoints:\t{}/{}\n\n'.format(sum(df_ctl['n_times']>2), len(df_ctl['n_times'])))
245
+
246
+
247
+ log_handle.write('\nUSING THEM ALL FOR NOW\n')
248
+
249
+ #Types of vectors
250
+ log_handle.write('Number of vectors:\t{}:\n'.format(len(set(inst_info_ctl['cmap_name']))))
251
+ df=pd.DataFrame.from_dict(Counter(inst_info_ctl['cmap_name']), orient='index')
252
+ df = df.sort_values(by=0)
253
+ for i, v in enumerate(zip(df.index, df[0])):
254
+ log_handle.write('{}:\t{}\n'.format(v[0], v[1]))
255
+
256
+ #Number of controls per cell line
257
+ replicates = inst_info_ctl.groupby(['cell_iname']).size()
258
+ log_handle.write('\n\n------\nNUMBER OF REPLICATES PER CELL LINE (different doses, times, vectors)\n-----------\n')
259
+ df=pd.DataFrame.from_dict(Counter(inst_info_ctl['cell_iname']), orient='index')
260
+ df = df.sort_values(by=0)
261
+ for i, v in enumerate(zip(df.index, df[0])):
262
+ log_handle.write('{}:\t{}\n'.format(v[0], v[1]))
263
+
264
+ log_handle.write('\n***********************************\n')
265
+
266
+ return
267
+
268
+
269
+ def filter_cell_lines(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle):
270
+ log_handle.write('Filtering to keep only cell lines with highest mumber of perturbed genes\n------\n')
271
+
272
+ #####Compound
273
+ #Obtain cell lines with the most perturbations (> 4K genes perturbed)
274
+ df_cp = pd.DataFrame(inst_info_cp[['cmap_name', 'cell_iname']].groupby('cell_iname', as_index=True).apply(lambda x: x['cmap_name'].unique()))
275
+ df_cp = pd.DataFrame([(i, len(df_cp.loc[i][0])) for i in df_cp.index], columns =['cell_line', 'n_cmap_names'])
276
+ df_cp = df_cp.sort_values(by='n_cmap_names')
277
+
278
+ keep_cell_lines = df_cp[df_cp['n_cmap_names']>np.percentile(df_cp['n_cmap_names'], 90)]['cell_line'].tolist()
279
+
280
+ #Find indices of samples that are on the desired cell lines
281
+ keep_index = []
282
+ for i in range(len(inst_info_cp)):
283
+ if inst_info_cp.at[i, 'cell_iname'] in keep_cell_lines:
284
+ keep_index.append(i)
285
+
286
+
287
+ inst_info_cp = inst_info_cp.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
288
+ list_ids = list(inst_info_cp['sample_id']) #obtain sample ID from metadata
289
+ matrix_cp = matrix_cp[list_ids] #Filtered data matrix
290
+ log_handle.write('Compounds:\t{} datapoints\n'.format(matrix_cp.shape[1]))
291
+
292
+
293
+
294
+ #####CONTROL
295
+ keep_index = []
296
+ for i in range(len(inst_info_ctl)):
297
+ if inst_info_ctl.at[i, 'cell_iname'] in keep_cell_lines:
298
+ keep_index.append(i)
299
+
300
+
301
+ inst_info_ctl = inst_info_ctl.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
302
+ list_ids = list(inst_info_ctl['sample_id']) #obtain sample ID from metadata
303
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
304
+ log_handle.write('CONTROL:\t{} datapoints\n'.format(matrix_ctl.shape[1]))
305
+
306
+ # Stats
307
+ #stats_control(inst_info_ctl, log_handle)
308
+
309
+ return inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, keep_cell_lines
310
+
311
+
312
+
313
+
314
+ def filter_cell_lines_custom(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle):
315
+ log_handle.write('Filtering to keep custom list of cell lines\n------\n')
316
+
317
+ #####Compound
318
+ keep_cell_lines = ['A549', 'PC3', 'MCF7', 'VCAP', 'MDAMB231', 'BT20', 'HA1E', 'HT29', 'A375', 'HELA', 'YAPC']
319
+
320
+ #Find indices of samples that are on the desired cell lines
321
+ keep_index = []
322
+ for i in range(len(inst_info_cp)):
323
+ if inst_info_cp.at[i, 'cell_iname'] in keep_cell_lines:
324
+ keep_index.append(i)
325
+
326
+
327
+ inst_info_cp = inst_info_cp.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
328
+ list_ids = list(inst_info_cp['sample_id']) #obtain sample ID from metadata
329
+ matrix_cp = matrix_cp[list_ids] #Filtered data matrix
330
+ log_handle.write('Compounds:\t{} datapoints\n'.format(matrix_cp.shape[1]))
331
+
332
+
333
+
334
+ #####CONTROL
335
+ keep_index = []
336
+ for i in range(len(inst_info_ctl)):
337
+ if inst_info_ctl.at[i, 'cell_iname'] in keep_cell_lines:
338
+ keep_index.append(i)
339
+
340
+
341
+ inst_info_ctl = inst_info_ctl.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
342
+ list_ids = list(inst_info_ctl['sample_id']) #obtain sample ID from metadata
343
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
344
+ log_handle.write('CONTROL:\t{} datapoints\n'.format(matrix_ctl.shape[1]))
345
+
346
+ # Stats
347
+ #stats_control(inst_info_ctl, log_handle)
348
+
349
+ return inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, keep_cell_lines
350
+
351
+
352
+ def maxSample(w,x,y,z, max_list):
353
+ if (w,x,y,z) in max_list:
354
+ return 1
355
+ else:
356
+ return 0
357
+
358
+
359
+ def filter_dosage_timepoints(sample_ids_cp, inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle):
360
+ log_handle.write('Filtering to keep only samples with the highest dosage and longest timepoint per drug-cell line combination\n------\n')
361
+ #####Compounds
362
+
363
+ df_cp=pd.DataFrame(inst_info_cp[['sample_id','pert_id', 'pert_dose','pert_dose_unit','pert_time','cell_iname']])
364
+ df_cp_max=df_cp.sort_values(by=['pert_dose','pert_time']).drop_duplicates(["pert_id","cell_iname"],keep="last")
365
+ max_list=list(zip(df_cp_max['pert_dose'], df_cp_max['pert_time'],df_cp_max['pert_id'],df_cp_max['cell_iname']))
366
+
367
+ #Decoding sample_ids_cp array
368
+ decode=np.vectorize(np.char.decode)
369
+ sample_ids_cp_dec=decode(sample_ids_cp)
370
+ tqdm.pandas()
371
+ df_cp['max'] = df_cp.swifter.apply(lambda row : maxSample(row['pert_dose'],row['pert_time'], row['pert_id'],row['cell_iname'], max_list), axis = 1)
372
+ df_cp_filtered=df_cp.loc[df_cp['max']== 1]
373
+ df_cp_filtered.to_csv("../../processed/chemical/dataframes/df_cp_filtered.csv")
374
+
375
+ sid_index=np.intersect1d(sample_ids_cp_dec,df_cp_filtered.sample_id.to_numpy(), return_indices=True)[1]
376
+ f1 = operator.itemgetter(*sid_index)
377
+ sample_ids=f1(sample_ids_cp_dec)
378
+ keep_index=inst_info_cp[inst_info_cp['sample_id'].isin(sample_ids)].index.tolist()
379
+
380
+ inst_info_cp = inst_info_cp.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
381
+ list_ids = list(inst_info_cp['sample_id']) #obtain sample ID from metadata
382
+ matrix_cp = matrix_cp[list_ids] #Filtered data matrix
383
+ log_handle.write('Compounds:\t{} datapoints\n'.format(matrix_cp.shape[1]))
384
+ return inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl
385
+
386
+
387
+
388
+
389
+ ################
390
+ #2. Filter column metadata and data matrix to keep only those in metadata
391
+
392
+ def filter_data_metadata(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle):
393
+ log_handle.write('Filtering to keep only those in metadata\n------\n')
394
+ #Compund
395
+ list_ids = list(inst_info_cp['sample_id']) #in metadata
396
+ matrix_cp = matrix_cp[list_ids] #Filtered data matrix
397
+ log_handle.write('Compounds:\t{} datapoints\n'.format(matrix_cp.shape[1]))
398
+ #CONTROL
399
+ list_ids = list(inst_info_ctl['sample_id']) #in metadata
400
+ #extra steps
401
+ #--
402
+ list_ids = list(set(list_ids).intersection(set(matrix_ctl.columns.astype(str)))) #in metadata and in data matrix (some of metadata are not in data matrix)
403
+ inst_info_ctl.index = inst_info_ctl['sample_id']; inst_info_ctl = inst_info_ctl.loc[list_ids].reset_index(inplace=False, drop=True) #remove entries from metadata that are not in data matrix
404
+ #--
405
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
406
+ log_handle.write('CONTROL:\t{} datapoints\n\n\n'.format(matrix_ctl.shape[1]))
407
+ return inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl
408
+
409
+
410
+
411
+
412
+ ################
413
+ #3. Map drug target names to symbols from LINCS
414
+ def map_gene_targets_to_lincs(inst_info_cp, gene_info):
415
+ genes_in_lincs = set(gene_info.gene_symbol)
416
+ inst_info_cp['target_names'] = ''
417
+ for i in range(len(inst_info_cp)):
418
+ drugbank_target_names = inst_info_cp.at[i, 'drugbank_target_names']
419
+ if drugbank_target_names ==[]:
420
+ continue
421
+ else:
422
+ target_names = []
423
+ for target_list in drugbank_target_names:
424
+ target_name = list(set(target_list).intersection(genes_in_lincs))
425
+ if len(target_name) == 1:
426
+ target_names.append(target_name[0])
427
+ inst_info_cp.at[i, 'target_names'] = target_names
428
+
429
+ return inst_info_cp
430
+
431
+
432
+ ################
433
+ #3. Filter samples with unknown perturbed genes (keeping those with at least 1 known perturbed gene)
434
+ def filter_samples_with_unknown_perturbed_genes(inst_info_cp, matrix_cp, gene_info, log_handle):
435
+ ########################################################################################
436
+ #First filter perturbation samples to remove those with genes not mapping to genes_info
437
+ keep_index = []
438
+ for i in range(len(inst_info_cp)):
439
+ if len(inst_info_cp.at[i, 'target_names']) > 0:
440
+ keep_index.append(i)
441
+
442
+ inst_info_cp = inst_info_cp.loc[keep_index].reset_index(inplace=False, drop=True) #filter from metadata
443
+ list_ids = list(inst_info_cp['sample_id']) #obtain sample ID from metadata
444
+ matrix_cp = matrix_cp[list_ids] #Filtered data matrix
445
+ log_handle.write('Filtering samples without protein targets in drugbank and lincs\n')
446
+ log_handle.write('Compounds:\t{} datapoints\n'.format(matrix_cp.shape[1]))
447
+ return inst_info_cp, matrix_cp
448
+
449
+
450
+
451
+
452
+
453
+ ################
454
+ #4. Cretes a dictionary of gene_symbol:sample_ids
455
+ def genesymb2sampleiddict(inst_info_cp):
456
+ #Returns a dictionary of gene_symbol: [sampleids]
457
+ genesymb_list=list(inst_info_cp.target_names)
458
+ genesymb_list=list(itertools.chain(*genesymb_list))
459
+ genesymb_list_unique=list(set(genesymb_list))
460
+
461
+ l=[ [] for _ in range(len(genesymb_list_unique)) ]
462
+ d=dict(zip(genesymb_list_unique,l))
463
+
464
+ for sample in range(len(inst_info_cp)):
465
+ sid=inst_info_cp.at[sample,'sample_id']
466
+ for target in inst_info_cp.at[sample,'target_names']:
467
+ if target in d:
468
+ d[target].append(sid)
469
+ return d
470
+
471
+
472
+
473
+ def binarize_genewise_comparing_to_control(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
474
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
475
+ if use_log:
476
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm')
477
+ else:
478
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control')
479
+ os.makedirs(outdir, exist_ok= True)
480
+
481
+
482
+ #All data
483
+ metadata = pd.concat([inst_info_cp, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
484
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
485
+ matrix = pd.concat([matrix_cp, matrix_ctl], 1)
486
+ del(matrix_cp)
487
+
488
+ #Normalization
489
+ #0. create dictionary of gene_id: sample_id
490
+ #gene symbol -> gene id
491
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
492
+ #gene symbol -> sample id
493
+ #Passing in dictionary from genesymb2sampleiddict
494
+ d=genesymb2sampleiddict(inst_info_cp)
495
+ #Switching keys to be gene_ids instead of gene_symbols
496
+ dict_gene_id_sample_id= dict((dict_symbol_id[key],value) for (key,value) in d.items())
497
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
498
+ del(d)
499
+ del(dict_symbol_id)
500
+ del(gene_info)
501
+ i = 1
502
+ higher_than_thr = []
503
+ higher_than_thr_ids = []
504
+ control_corrected = []
505
+ pert_corrected = []
506
+
507
+ #lognorm
508
+ if use_log:
509
+ matrix = np.log2(matrix + 1)
510
+
511
+
512
+ #hist of values
513
+ # mv_shape=matrix.values.shape
514
+ # num_elements = mv_shape[0]*mv_shape[1]
515
+ # chosenCols=np.random.randint(0, mv_shape[1], size=int(0.001*num_elements))
516
+ # chosenRows=np.random.randint(0, mv_shape[0], size=int(0.001*num_elements))
517
+ # filter_ind=np.array(np.array(list(zip(chosenRows,chosenCols))))
518
+ # mv=list(matrix.values[filter_ind[:,0],filter_ind[:,1]])
519
+ # fig, ax = plt.subplots(figsize=(16,6))
520
+ # ax.hist(mv)
521
+ # ax.set_title('Histogram of values')
522
+ # fig.savefig(osp.join(outdir,'histogram.png'))
523
+ # plt.close()
524
+
525
+ for cell_line in list(set(metadata['cell_iname'])):
526
+ matrix_i = matrix[metadata[metadata['cell_iname']==cell_line]['sample_id']]
527
+ #Normalization
528
+ #1. Iterate through each gene, mask out the samples in which it was perturbed, and normalize --> set to 1 those genes that have value of average + 2std higher than control
529
+ #for the perturbed genes = 0
530
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
531
+ mask_norm = list(set(matrix_ctl.columns).intersection(set(matrix_i.columns))) #mask_norm is controls only (for specific cell line 'cell_line')
532
+ control_corrected += mask_norm
533
+ averages = np.mean(matrix[mask_norm], 1)
534
+ stds = np.std(matrix[mask_norm], 1)
535
+ thresholds = averages + (2*stds)
536
+ for gene_id in list(matrix_i.index):
537
+ #mask of elements to use for normalization: the ones in control samples only
538
+ #mask of elements to binarize to 0 (samples in which gene_id is perturbed)
539
+ if gene_id in dict_gene_id_sample_id:
540
+ mask_pert = list(set(dict_gene_id_sample_id[gene_id]).intersection(set(matrix_i.columns))) #mask_pert for specific cell line 'cell_line'
541
+ pert_corrected += mask_pert
542
+ else:
543
+ mask_pert = []
544
+ #normalize
545
+ threshold = thresholds.loc[gene_id]
546
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
547
+ # matrix_binarized.loc[gene_id][mask_pert] = 0 #not setting to zero here -- it's chemical perturbations not KO
548
+ #some stats
549
+ if mask_pert != []:
550
+ gte = matrix_i.loc[gene_id][mask_pert] >= threshold
551
+ higher_than_thr += gte.values.astype(int).tolist()
552
+ higher_than_thr_ids += matrix_i.loc[gene_id][mask_pert].index[np.where(gte)].tolist()
553
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
554
+ i+=1
555
+
556
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), len(inst_info_ctl)))
557
+ print('Perturbed covered:{}/{}\n'.format(len(set(pert_corrected)), len(inst_info_cp)))
558
+
559
+
560
+
561
+ #plot higher than thr
562
+ fig, ax1 = plt.subplots(1, figsize=(16,6))
563
+ ax1.hist(higher_than_thr)
564
+ ax1.set_title('Perturbed genes values >= threshold')
565
+ fig.savefig(osp.join(outdir,'exploration_ge_compounds_higher_than_thr.png'))
566
+ log_handle.write('After binarizing, stats, perturbed gene values would be higher than threshold in :\t{} samples\n'.format(np.sum(higher_than_thr)))
567
+
568
+
569
+ #2. Save data and metadata for each condition and cell line
570
+ #Compound + cell lines
571
+ #Control + cell lines
572
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
573
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
574
+ metadata.index = metadata['sample_id']
575
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
576
+ for cell_line in keep_cell_lines:
577
+ for pert_type in ['trt_cp', 'ctl_vehicle']:
578
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
579
+ data_i = matrix_binarized[metadata_i.index]
580
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
581
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
582
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
583
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['pert_id'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
584
+ log_handle.write('\n\n------\nSTATS\n------\n')
585
+
586
+ return
587
+
588
+
589
+
590
+
591
+
592
+
593
+ def normalize_and_save(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log):
594
+ log_handle.write('\n\n------\nNORMALIZE DATA AND SAVE\n------\n')
595
+ if use_log:
596
+ outdir = osp.join(outdir, 'real_lognorm')
597
+ else:
598
+ outdir = osp.join(outdir, 'real')
599
+ os.makedirs(outdir, exist_ok= True)
600
+
601
+
602
+ #All data
603
+ metadata = pd.concat([inst_info_cp, inst_info_ctl], axis=0).reset_index(inplace=False, drop=True)
604
+ metadata.to_csv(osp.join(outdir, 'all_metadata.txt'))
605
+ matrix = pd.concat([matrix_cp, matrix_ctl], 1)
606
+ del(matrix_cp)
607
+
608
+ #hist of values before lognorm
609
+ mv = matrix.values.flatten()
610
+ sampling = sample(range(len(mv)), int(0.001*len(mv)))
611
+ mv = mv[sampling]
612
+
613
+ fig, ax = plt.subplots(figsize=(16,6))
614
+ ax.hist(mv)
615
+ ax.set_title('Histogram of values')
616
+ fig.savefig(osp.join(outdir,'histogram_raw.png'))
617
+ plt.close()
618
+
619
+ #NORMALIZATION
620
+ #lognorm + minmax
621
+ if use_log:
622
+ matrix = np.log2(matrix + 1)
623
+
624
+ scaler = MinMaxScaler((0,1))
625
+ matrix = matrix.transpose()
626
+ matrix = pd.DataFrame(scaler.fit_transform(matrix), columns = matrix.columns, index = matrix.index)
627
+ matrix = matrix.transpose()
628
+
629
+
630
+
631
+ #hist of values after lognorm
632
+ mv = matrix.values.flatten()
633
+ sampling = sample(range(len(mv)), int(0.001*len(mv)))
634
+ mv = mv[sampling]
635
+
636
+ fig, ax = plt.subplots(figsize=(16,6))
637
+ ax.hist(mv)
638
+ ax.set_title('Histogram of values')
639
+ fig.savefig(osp.join(outdir,'histogram_lognorm.png'))
640
+ plt.close()
641
+
642
+ #2. Save data and metadata for each condition and cell line
643
+ #Compound + cell lines
644
+ #Control + cell lines
645
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
646
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
647
+ metadata.index = metadata['sample_id']
648
+ metadata = metadata.loc[matrix.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
649
+ for cell_line in keep_cell_lines:
650
+ for pert_type in ['trt_cp', 'ctl_vehicle']:
651
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
652
+ data_i = matrix[metadata_i.index]
653
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
654
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
655
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
656
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['pert_id'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
657
+ log_handle.write('\n\n------\nSTATS\n------\n')
658
+
659
+ return
660
+
661
+
662
+
663
+ outdir = '../../processed/lincs/chemical/nofilter_dose_timepoint'
664
+ os.makedirs(outdir, exist_ok=True)
665
+
666
+
667
+ def main():
668
+
669
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
670
+ log_handle = open(osp.join(outdir, 'log_process_data_real_lognorm.txt'), 'w')
671
+
672
+ sample_ids_cp, inst_info_cp, inst_info_ctl, gene_info, matrix_cp, matrix_ctl, df_targets = loads_data(DATA_ROOT, log_handle)
673
+ print('loaded data - lognorm', inst_info_cp.shape)
674
+
675
+ # inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, keep_cell_lines = filter_cell_lines(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle)
676
+ inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, keep_cell_lines = filter_cell_lines_custom(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle)
677
+ print('filtered cell lines - lognorm', inst_info_cp.shape)
678
+
679
+
680
+ inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl = filter_data_metadata(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, log_handle)
681
+ print('filtered data - lognorm', inst_info_cp.shape)
682
+
683
+ inst_info_cp = map_gene_targets_to_lincs(inst_info_cp, gene_info)
684
+ inst_info_cp, matrix_cp = filter_samples_with_unknown_perturbed_genes(inst_info_cp, matrix_cp, gene_info, log_handle)
685
+ print('filtered unknown perturbed genes - lognorm', inst_info_cp.shape)
686
+
687
+ use_log=True
688
+ normalize_and_save(inst_info_cp, matrix_cp, inst_info_ctl, matrix_ctl, gene_info, keep_cell_lines, log_handle, outdir, use_log)
689
+ print('real values - lognorm')
690
+ log_handle.close()
691
+
692
+
693
+ if __name__ == "__main__":
694
+ startTime=time.time()
695
+ main()
696
+ print(time.time()-startTime)
697
+
PDGrapher/data/scripts/lincs/process_data_healthy.py ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Process LINCS data of healhty cell lines
3
+ MCF10A, NL20, RWPE1
4
+ Will do some processing first and then rely on the functions in process_data.py
5
+ '''
6
+
7
+ import pandas as pd
8
+ import h5py
9
+ import os
10
+ import matplotlib.pyplot as plt
11
+ import seaborn as sns
12
+ import os.path as osp
13
+ import numpy as np
14
+ from collections import Counter
15
+ import matplotlib.pyplot as plt
16
+ import math
17
+ from random import sample
18
+ from sklearn.preprocessing import MinMaxScaler
19
+
20
+ outdir = '../../processed/lincs'
21
+ os.makedirs(outdir, exist_ok=True)
22
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
23
+
24
+
25
+ ################
26
+ # Data loading
27
+ ################
28
+
29
+ #function updated from the one in process_data to load the cell lines of interest
30
+ def loads_data(DATA_ROOT, log_handle):
31
+ healhty_cell_lines = ['MCF10A', 'NL20', 'RWPE1']
32
+
33
+ #Loads metadata
34
+ inst_info = pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
35
+
36
+ inst_info_ctl_mcf10a = inst_info[np.logical_and(inst_info['cell_iname'] == 'MCF10A',np.logical_and(inst_info['pert_type'] == 'ctl_untrt', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
37
+ inst_info_ctl_nl20 = inst_info[np.logical_and(inst_info['cell_iname'] == 'NL20',np.logical_and(inst_info['pert_type'] == 'ctl_vehicle', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
38
+ inst_info_ctl_rwpe1 = inst_info[np.logical_and(inst_info['cell_iname'] == 'RWPE1',np.logical_and(inst_info['pert_type'] == 'ctl_vector', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
39
+
40
+
41
+ inst_info_ctl = pd.concat([inst_info_ctl_mcf10a, inst_info_ctl_nl20, inst_info_ctl_rwpe1])
42
+
43
+ gene_info = pd.read_csv(os.path.join(DATA_ROOT, 'geneinfo_beta.txt'), sep="\t", low_memory=False)
44
+
45
+
46
+ ####################
47
+ #Loads data matrices
48
+
49
+
50
+ ### Control data -- filter to keep only those in my metadata
51
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_ctl_n188708x12328.gctx'), 'r')
52
+ matrix_ctl = f['0']['DATA']['0']['matrix'][:].transpose()
53
+ gene_ids_ctl = f['0']['META']['ROW']['id'][:] #not in the same order as gene_ids_xpr
54
+ sample_ids_ctl = f['0']['META']['COL']['id'][:]
55
+ matrix_ctl = pd.DataFrame(matrix_ctl, columns = sample_ids_ctl.astype(str), index = gene_ids_ctl.astype(int))
56
+
57
+ del f
58
+
59
+
60
+ #Stats
61
+ log_handle.write('CONTROL\n------\n')
62
+ log_handle.write('Control entries in inst_info metadata:\t{}\n'.format(len(inst_info_ctl)))
63
+ log_handle.write('Control entries in data matrix:\t{}\n'.format(len(sample_ids_ctl)))
64
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_ctl['sample_id']).intersection(set(sample_ids_ctl.astype(str))))))
65
+ log_handle.write('\n------\n')
66
+
67
+ return inst_info_ctl, gene_info, matrix_ctl
68
+
69
+
70
+
71
+
72
+ ################
73
+ # Processing
74
+ ################
75
+
76
+ ################
77
+ #1. Filter column metadata and data matrix to keep only those in metadata
78
+
79
+ def filter_data_metadata(inst_info_ctl, matrix_ctl, log_handle):
80
+ log_handle.write('Filtering to keep only those in metadata\n------\n')
81
+ #CONTROL
82
+ list_ids = list(inst_info_ctl['sample_id']) #in metadata
83
+ #extra steps
84
+ #--
85
+ list_ids = list(set(list_ids).intersection(set(matrix_ctl.columns.astype(str)))) #in metadata and in data matrix (some of metadata are not in data matrix)
86
+ inst_info_ctl.index = inst_info_ctl['sample_id']; inst_info_ctl = inst_info_ctl.loc[list_ids].reset_index(inplace=False, drop=True) #remove entries from metadata that are not in data matrix
87
+ #--
88
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
89
+ log_handle.write('CONTROL:\t{} datapoints\n\n\n'.format(matrix_ctl.shape[1]))
90
+ return inst_info_ctl, matrix_ctl
91
+
92
+
93
+ ################
94
+ #3. Normalize (binarize), and save
95
+
96
+
97
+ def binarize_genewise_comparing_to_control(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
98
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
99
+ if use_log:
100
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm')
101
+ else:
102
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control')
103
+ os.makedirs(outdir, exist_ok= True)
104
+
105
+
106
+
107
+
108
+ ########################################################################################
109
+ #All data
110
+ metadata = inst_info_ctl
111
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
112
+ matrix = matrix_ctl
113
+
114
+
115
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
116
+
117
+ i = 1
118
+
119
+ control_corrected = []
120
+
121
+
122
+ #lognorm
123
+ if use_log:
124
+ matrix = np.log2(matrix + 1)
125
+
126
+ #hist of values
127
+ mv = matrix.values.flatten()
128
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
129
+ mv = mv[sampling]
130
+
131
+ fig, ax = plt.subplots(figsize=(16,6))
132
+ ax.hist(mv)
133
+ ax.set_title('Histogram of values')
134
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
135
+ plt.close()
136
+
137
+ for cell_line in list(set(metadata['cell_iname'])):
138
+ matrix_i = matrix[metadata[metadata['cell_iname']==cell_line]['sample_id']]
139
+ #Normalization
140
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
141
+ mask_norm = list(set(matrix_ctl.columns).intersection(set(matrix_i.columns))) #mask_norm is controls only (for specific cell line 'cell_line')
142
+ control_corrected += mask_norm
143
+ averages = np.mean(matrix[mask_norm], 1)
144
+ stds = np.std(matrix[mask_norm], 1)
145
+ thresholds = averages + (2*stds)
146
+ for gene_id in list(matrix_i.index):
147
+ #normalize
148
+ threshold = thresholds.loc[gene_id]
149
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
150
+
151
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
152
+ i+=1
153
+
154
+
155
+
156
+
157
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), len(inst_info_ctl)))
158
+
159
+ #2. Save data and metadata for each condition and cell line
160
+ #CRISPR + cell lines
161
+ #Control + cell lines
162
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
163
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
164
+ metadata.index = metadata['sample_id']
165
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
166
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_untrt', 'ctl_vehicle', 'ctl_vector'] ):
167
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
168
+ data_i = matrix_binarized[metadata_i.index]
169
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
170
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
171
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
172
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
173
+ log_handle.write('\n\n------\nSTATS\n------\n')
174
+
175
+ return
176
+
177
+
178
+
179
+ def binarize_genewise_comparing_to_control_augmented(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
180
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
181
+ if use_log:
182
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm/augmented')
183
+ else:
184
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control/augmented')
185
+ os.makedirs(outdir, exist_ok= True)
186
+
187
+
188
+
189
+
190
+ ########################################################################################
191
+ #All data
192
+ metadata = inst_info_ctl
193
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
194
+ matrix = matrix_ctl
195
+
196
+
197
+ #lognorm
198
+ if use_log:
199
+ matrix = np.log2(matrix + 1)
200
+
201
+
202
+ matrix_augmented = matrix.copy()
203
+ ###Data augmentation using Gaussian noise
204
+ AUG_PROPORTION = 10
205
+ columns = matrix.columns
206
+ for i in range(AUG_PROPORTION):
207
+ columns_i = [e+'___{}'.format(i) for e in columns]
208
+ noise = np.random.normal(0,1,matrix.shape)
209
+ to_add = pd.DataFrame(matrix.values + noise, columns = columns_i, index = matrix.index)
210
+ matrix_augmented = pd.concat([matrix_augmented, to_add], 1)
211
+
212
+
213
+ matrix = matrix_augmented
214
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
215
+
216
+ i = 1
217
+
218
+ control_corrected = []
219
+
220
+
221
+
222
+
223
+ #hist of values
224
+ mv = matrix.values.flatten()
225
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
226
+ mv = mv[sampling]
227
+
228
+ fig, ax = plt.subplots(figsize=(16,6))
229
+ ax.hist(mv)
230
+ ax.set_title('Histogram of values')
231
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
232
+ plt.close()
233
+
234
+ for cell_line in list(set(metadata['cell_iname'])):
235
+ columns = metadata[metadata['cell_iname']==cell_line]['sample_id'].tolist()
236
+ columns_augmented = [e+'___{}'.format(i) for i in range(AUG_PROPORTION) for e in columns] + columns
237
+ columns = columns_augmented
238
+ matrix_i = matrix[columns]
239
+ #Normalization
240
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
241
+ #Binarization
242
+ mask_norm = list(set(matrix_i.columns)) #mask_norm is controls only (for specific cell line 'cell_line')
243
+ control_corrected += mask_norm
244
+ averages = np.mean(matrix[mask_norm], 1)
245
+ stds = np.std(matrix[mask_norm], 1)
246
+ thresholds = averages + (2*stds)
247
+ for gene_id in list(matrix_i.index):
248
+ #normalize
249
+ threshold = thresholds.loc[gene_id]
250
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
251
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
252
+ i+=1
253
+
254
+
255
+
256
+
257
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), matrix.shape[1]))
258
+
259
+ #2. Save data and metadata for each condition and cell line
260
+ #Control + cell lines
261
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
262
+ log_handle.write('CELL\tPERT\t\tSIZE\tAUGMENTED SIZE\t\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
263
+ metadata.index = metadata['sample_id']
264
+ # metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
265
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_untrt', 'ctl_vehicle', 'ctl_vector'] ):
266
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
267
+ columns = list(metadata_i.index)
268
+ to_add = []
269
+ for i in range(AUG_PROPORTION):
270
+ to_add += [e+'___{}'.format(i) for e in columns]
271
+ columns = columns + to_add
272
+ data_i = matrix_binarized[columns]
273
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
274
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
275
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
276
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), data_i.shape[1], len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
277
+ log_handle.write('\n\n------\nSTATS\n------\n')
278
+
279
+ return
280
+
281
+
282
+ def normalize_and_save(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
283
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
284
+ if use_log:
285
+ outdir = osp.join(outdir, 'real_lognorm')
286
+ else:
287
+ outdir = osp.join(outdir, 'real')
288
+ os.makedirs(outdir, exist_ok= True)
289
+
290
+
291
+ ########################################################################################
292
+ #All data
293
+ metadata = inst_info_ctl
294
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
295
+ matrix = matrix_ctl
296
+
297
+
298
+ #lognorm
299
+ if use_log:
300
+ matrix = np.log2(matrix + 1)
301
+ scaler = MinMaxScaler((0,1))
302
+ matrix = matrix.transpose()
303
+ matrix = pd.DataFrame(scaler.fit_transform(matrix), columns = matrix.columns, index = matrix.index)
304
+ matrix = matrix.transpose()
305
+
306
+ #hist of values
307
+ mv = matrix.values.flatten()
308
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
309
+ mv = mv[sampling]
310
+
311
+ fig, ax = plt.subplots(figsize=(16,6))
312
+ ax.hist(mv)
313
+ ax.set_title('Histogram of values')
314
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
315
+ plt.close()
316
+
317
+
318
+
319
+ #2. Save data and metadata for each condition and cell line
320
+ #CRISPR + cell lines
321
+ #Control + cell lines
322
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
323
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
324
+ metadata.index = metadata['sample_id']
325
+ metadata = metadata.loc[matrix.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
326
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_untrt', 'ctl_vehicle', 'ctl_vector'] ):
327
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
328
+ data_i = matrix[metadata_i.index]
329
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
330
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
331
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
332
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
333
+ log_handle.write('\n\n------\nSTATS\n------\n')
334
+
335
+ return
336
+
337
+
338
+
339
+
340
+
341
+ def main():
342
+ from process_data import stats_control
343
+
344
+
345
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
346
+ log_handle = open(osp.join(outdir, 'process_data_healthy_lognorm.txt'), 'w')
347
+ inst_info_ctl, gene_info, matrix_ctl = loads_data(DATA_ROOT, log_handle)
348
+ inst_info_ctl, matrix_ctl = filter_data_metadata(inst_info_ctl, matrix_ctl, log_handle)
349
+ #stats_control(inst_info_ctl, log_handle)
350
+ use_log=True
351
+ normalize_and_save(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log)
352
+ log_handle.close()
353
+
354
+
355
+ if __name__ == "__main__":
356
+ main()
357
+
358
+
359
+
360
+
361
+
362
+
PDGrapher/data/scripts/lincs/process_data_healthy_chemical.py ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Process LINCS data of healhty cell lines
3
+
4
+ -- MCF10A, NL20, RWPE1
5
+
6
+ Will do some processing first and then rely on the functions in process_data.py
7
+ ######ONLY DIFFERENCE WITH CRISPR FILE IS THAT I USE CTL_VEHICLE FOR MCF10A INSTEAD OF CTL_UNTRT
8
+ '''
9
+
10
+ import pandas as pd
11
+ import h5py
12
+ import os
13
+ import matplotlib.pyplot as plt
14
+ import seaborn as sns
15
+ import os.path as osp
16
+ import numpy as np
17
+ from collections import Counter
18
+ import matplotlib.pyplot as plt
19
+ import math
20
+ from random import sample
21
+ from sklearn.preprocessing import MinMaxScaler
22
+
23
+ outdir = '../../processed/lincs/chemical'
24
+ os.makedirs(outdir, exist_ok=True)
25
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
26
+
27
+
28
+ ################
29
+ # Data loading
30
+ ################
31
+
32
+ #function updated from the one in process_data to load the cell lines of interest
33
+ def loads_data(DATA_ROOT, log_handle):
34
+
35
+ #Loads metadata
36
+ inst_info = pd.read_csv(os.path.join(DATA_ROOT, 'instinfo_beta.txt'), sep="\t", low_memory=False)
37
+
38
+
39
+ inst_info_ctl_mcf10a = inst_info[np.logical_and(inst_info['cell_iname'] == 'MCF10A',np.logical_and(inst_info['pert_type'] == 'ctl_vehicle', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
40
+ inst_info_ctl_nl20 = inst_info[np.logical_and(inst_info['cell_iname'] == 'NL20',np.logical_and(inst_info['pert_type'] == 'ctl_vehicle', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
41
+ inst_info_ctl_rwpe1 = inst_info[np.logical_and(inst_info['cell_iname'] == 'RWPE1',np.logical_and(inst_info['pert_type'] == 'ctl_vector', inst_info['failure_mode'].isna())) ].reset_index(inplace=False, drop=True)
42
+
43
+
44
+ inst_info_ctl = pd.concat([inst_info_ctl_mcf10a, inst_info_ctl_nl20, inst_info_ctl_rwpe1])
45
+
46
+ gene_info = pd.read_csv(os.path.join(DATA_ROOT, 'geneinfo_beta.txt'), sep="\t", low_memory=False)
47
+
48
+
49
+ ####################
50
+ #Loads data matrices
51
+
52
+
53
+ ### Control data -- filter to keep only those in my metadata
54
+ f = h5py.File(os.path.join(DATA_ROOT, 'level3_beta_ctl_n188708x12328.gctx'), 'r')
55
+ matrix_ctl = f['0']['DATA']['0']['matrix'][:].transpose()
56
+ gene_ids_ctl = f['0']['META']['ROW']['id'][:] #not in the same order as gene_ids_xpr
57
+ sample_ids_ctl = f['0']['META']['COL']['id'][:]
58
+ matrix_ctl = pd.DataFrame(matrix_ctl, columns = sample_ids_ctl.astype(str), index = gene_ids_ctl.astype(int))
59
+
60
+ del f
61
+
62
+
63
+ #Stats
64
+ log_handle.write('CONTROL\n------\n')
65
+ log_handle.write('Control entries in inst_info metadata:\t{}\n'.format(len(inst_info_ctl)))
66
+ log_handle.write('Control entries in data matrix:\t{}\n'.format(len(sample_ids_ctl)))
67
+ log_handle.write('Overlap between inst_info metadata and sample ids in data matrix:\t{}\n'.format(len(set(inst_info_ctl['sample_id']).intersection(set(sample_ids_ctl.astype(str))))))
68
+ log_handle.write('\n------\n')
69
+
70
+ return inst_info_ctl, gene_info, matrix_ctl
71
+
72
+
73
+
74
+
75
+ ################
76
+ # Processing
77
+ ################
78
+
79
+ ################
80
+ #1. Filter column metadata and data matrix to keep only those in metadata
81
+
82
+ def filter_data_metadata(inst_info_ctl, matrix_ctl, log_handle):
83
+ log_handle.write('Filtering to keep only those in metadata\n------\n')
84
+ #CONTROL
85
+ list_ids = list(inst_info_ctl['sample_id']) #in metadata
86
+ #extra steps
87
+ #--
88
+ list_ids = list(set(list_ids).intersection(set(matrix_ctl.columns.astype(str)))) #in metadata and in data matrix (some of metadata are not in data matrix)
89
+ inst_info_ctl.index = inst_info_ctl['sample_id']; inst_info_ctl = inst_info_ctl.loc[list_ids].reset_index(inplace=False, drop=True) #remove entries from metadata that are not in data matrix
90
+ #--
91
+ matrix_ctl = matrix_ctl[list_ids] #Filtered data matrix
92
+ log_handle.write('CONTROL:\t{} datapoints\n\n\n'.format(matrix_ctl.shape[1]))
93
+ return inst_info_ctl, matrix_ctl
94
+
95
+
96
+ ################
97
+ #3. Normalize (binarize), and save
98
+
99
+
100
+ def binarize_genewise_comparing_to_control(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
101
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
102
+ if use_log:
103
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm')
104
+ else:
105
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control')
106
+ os.makedirs(outdir, exist_ok= True)
107
+
108
+
109
+
110
+
111
+ ########################################################################################
112
+ #All data
113
+ metadata = inst_info_ctl
114
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
115
+ matrix = matrix_ctl
116
+
117
+
118
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
119
+
120
+ i = 1
121
+
122
+ control_corrected = []
123
+
124
+
125
+ #lognorm
126
+ if use_log:
127
+ matrix = np.log2(matrix + 1)
128
+
129
+ #hist of values
130
+ mv = matrix.values.flatten()
131
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
132
+ mv = mv[sampling]
133
+
134
+ fig, ax = plt.subplots(figsize=(16,6))
135
+ ax.hist(mv)
136
+ ax.set_title('Histogram of values')
137
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
138
+ plt.close()
139
+
140
+ for cell_line in list(set(metadata['cell_iname'])):
141
+ matrix_i = matrix[metadata[metadata['cell_iname']==cell_line]['sample_id']]
142
+ #Normalization
143
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
144
+ mask_norm = list(set(matrix_ctl.columns).intersection(set(matrix_i.columns))) #mask_norm is controls only (for specific cell line 'cell_line')
145
+ control_corrected += mask_norm
146
+ averages = np.mean(matrix[mask_norm], 1)
147
+ stds = np.std(matrix[mask_norm], 1)
148
+ thresholds = averages + (2*stds)
149
+ for gene_id in list(matrix_i.index):
150
+ #normalize
151
+ threshold = thresholds.loc[gene_id]
152
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
153
+
154
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
155
+ i+=1
156
+
157
+
158
+
159
+
160
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), len(inst_info_ctl)))
161
+
162
+ #2. Save data and metadata for each condition and cell line
163
+ #CRISPR + cell lines
164
+ #Control + cell lines
165
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
166
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
167
+ metadata.index = metadata['sample_id']
168
+ metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
169
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_vehicle', 'ctl_vehicle', 'ctl_vector'] ):
170
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
171
+ data_i = matrix_binarized[metadata_i.index]
172
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
173
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
174
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
175
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
176
+ log_handle.write('\n\n------\nSTATS\n------\n')
177
+
178
+ return
179
+
180
+
181
+
182
+ def binarize_genewise_comparing_to_control_augmented(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
183
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
184
+ if use_log:
185
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control_lognorm/augmented')
186
+ else:
187
+ outdir = osp.join(outdir, 'binarize_genewise_comparing_to_control/augmented')
188
+ os.makedirs(outdir, exist_ok= True)
189
+
190
+
191
+
192
+
193
+ ########################################################################################
194
+ #All data
195
+ metadata = inst_info_ctl
196
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
197
+ matrix = matrix_ctl
198
+
199
+
200
+ #lognorm
201
+ if use_log:
202
+ matrix = np.log2(matrix + 1)
203
+
204
+
205
+ matrix_augmented = matrix.copy()
206
+ ###Data augmentation using Gaussian noise
207
+ AUG_PROPORTION = 10
208
+ columns = matrix.columns
209
+ for i in range(AUG_PROPORTION):
210
+ columns_i = [e+'___{}'.format(i) for e in columns]
211
+ noise = np.random.normal(0,1,matrix.shape)
212
+ to_add = pd.DataFrame(matrix.values + noise, columns = columns_i, index = matrix.index)
213
+ matrix_augmented = pd.concat([matrix_augmented, to_add], 1)
214
+
215
+
216
+ matrix = matrix_augmented
217
+ matrix_binarized = pd.DataFrame(np.zeros_like(matrix), index = matrix.index, columns = matrix.columns)
218
+
219
+ i = 1
220
+
221
+ control_corrected = []
222
+
223
+
224
+
225
+
226
+ #hist of values
227
+ mv = matrix.values.flatten()
228
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
229
+ mv = mv[sampling]
230
+
231
+ fig, ax = plt.subplots(figsize=(16,6))
232
+ ax.hist(mv)
233
+ ax.set_title('Histogram of values')
234
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
235
+ plt.close()
236
+
237
+ for cell_line in list(set(metadata['cell_iname'])):
238
+ columns = metadata[metadata['cell_iname']==cell_line]['sample_id'].tolist()
239
+ columns_augmented = [e+'___{}'.format(i) for i in range(AUG_PROPORTION) for e in columns] + columns
240
+ columns = columns_augmented
241
+ matrix_i = matrix[columns]
242
+ #Normalization
243
+ #Create matrix of NGenes x NExperiments (add column name as sample_id)
244
+ #Binarization
245
+ mask_norm = list(set(matrix_i.columns)) #mask_norm is controls only (for specific cell line 'cell_line')
246
+ control_corrected += mask_norm
247
+ averages = np.mean(matrix[mask_norm], 1)
248
+ stds = np.std(matrix[mask_norm], 1)
249
+ thresholds = averages + (2*stds)
250
+ for gene_id in list(matrix_i.index):
251
+ #normalize
252
+ threshold = thresholds.loc[gene_id]
253
+ matrix_binarized.loc[gene_id][matrix_i.columns] = (matrix_i.loc[gene_id] >= threshold).astype(int).values
254
+ print('{}/{}'.format(i, len(list(set(metadata['cell_iname'])))))
255
+ i+=1
256
+
257
+
258
+
259
+
260
+ print('Controls covered:{}/{}\n'.format(len(control_corrected), matrix.shape[1]))
261
+
262
+ #2. Save data and metadata for each condition and cell line
263
+ #Control + cell lines
264
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
265
+ log_handle.write('CELL\tPERT\t\tSIZE\tAUGMENTED SIZE\t\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
266
+ metadata.index = metadata['sample_id']
267
+ # metadata = metadata.loc[matrix_binarized.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
268
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_untrt', 'ctl_vehicle', 'ctl_vector'] ):
269
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
270
+ columns = list(metadata_i.index)
271
+ to_add = []
272
+ for i in range(AUG_PROPORTION):
273
+ to_add += [e+'___{}'.format(i) for e in columns]
274
+ columns = columns + to_add
275
+ data_i = matrix_binarized[columns]
276
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
277
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
278
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
279
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), data_i.shape[1], len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
280
+ log_handle.write('\n\n------\nSTATS\n------\n')
281
+
282
+ return
283
+
284
+
285
+
286
+
287
+
288
+ def normalize_and_save(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log):
289
+ log_handle.write('\n\n------\nBINARIZING GENEWISE COMPARING TO CONTROL\n------\n')
290
+ if use_log:
291
+ outdir = osp.join(outdir, 'real_lognorm')
292
+ else:
293
+ outdir = osp.join(outdir, 'real')
294
+ os.makedirs(outdir, exist_ok= True)
295
+
296
+
297
+
298
+
299
+ ########################################################################################
300
+ #All data
301
+ metadata = inst_info_ctl
302
+ metadata.to_csv(osp.join(outdir, 'all_metadata_healthy.txt'))
303
+ matrix = matrix_ctl
304
+
305
+
306
+ #lognorm
307
+ if use_log:
308
+ matrix = np.log2(matrix + 1)
309
+ scaler = MinMaxScaler((0,1))
310
+ matrix = matrix.transpose()
311
+ matrix = pd.DataFrame(scaler.fit_transform(matrix), columns = matrix.columns, index = matrix.index)
312
+ matrix = matrix.transpose()
313
+
314
+ #hist of values
315
+ mv = matrix.values.flatten()
316
+ sampling = sample(range(len(mv)), int(0.1*len(mv)))
317
+ mv = mv[sampling]
318
+
319
+ fig, ax = plt.subplots(figsize=(16,6))
320
+ ax.hist(mv)
321
+ ax.set_title('Histogram of values')
322
+ fig.savefig(osp.join(outdir,'histogram_healthy.png'))
323
+ plt.close()
324
+
325
+
326
+
327
+ #2. Save data and metadata for each condition and cell line
328
+ #CRISPR + cell lines
329
+ #Control + cell lines
330
+ log_handle.write('----------------\n----------------\nDATA MATRICES\n')
331
+ log_handle.write('CELL\tPERT\t\tSIZE\tUNIQUE GENES/VECTORS\tUNIQUE CELL LINES\tAVG NUMBER OF 1\'s\n')
332
+ metadata.index = metadata['sample_id']
333
+ metadata = metadata.loc[matrix.columns] #sort metadata given by column order in data matrix (and filter samples that have been filtered out from matrix during binarization)
334
+ for cell_line, pert_type in zip(['MCF10A', 'NL20', 'RWPE1'],['ctl_vehicle', 'ctl_vehicle', 'ctl_vector'] ):
335
+ metadata_i = metadata[np.logical_and(metadata['cell_iname'] == cell_line, metadata['pert_type'] == pert_type)]
336
+ data_i = matrix[metadata_i.index]
337
+ metadata_i.to_csv(osp.join(outdir, 'cell_line_{}_pert_{}_metadata.txt'.format(cell_line, pert_type)), index=False)
338
+ filename = 'cell_line_{}_pert_{}'.format(cell_line, pert_type)
339
+ np.savez_compressed(osp.join(outdir, filename), data=data_i.values, row_ids = data_i.index, col_ids=data_i.columns)
340
+ log_handle.write('{}\t{}\t\t{}\t{}\t{}\t{}\n'.format(cell_line, pert_type, len(metadata_i), len(set(metadata_i['cmap_name'])), len(set(metadata_i['cell_iname'])), np.mean(np.sum(data_i, 0))))
341
+ log_handle.write('\n\n------\nSTATS\n------\n')
342
+
343
+ return
344
+
345
+ def main():
346
+ from process_data import stats_control
347
+
348
+ DATA_ROOT = "../../raw/lincs/2022-02-LINCS_Level3/data/"
349
+ log_handle = open(osp.join(outdir, 'log_process_data_healthy_lognorm.txt'), 'w')
350
+ inst_info_ctl, gene_info, matrix_ctl = loads_data(DATA_ROOT, log_handle)
351
+ inst_info_ctl, matrix_ctl = filter_data_metadata(inst_info_ctl, matrix_ctl, log_handle)
352
+ #stats_control(inst_info_ctl, log_handle)
353
+ use_log=True
354
+ normalize_and_save(inst_info_ctl, matrix_ctl, gene_info, log_handle, outdir, use_log)
355
+ log_handle.close()
356
+
357
+ if __name__ == "__main__":
358
+ main()
359
+
360
+
361
+
362
+
363
+
364
+
PDGrapher/data/scripts/ppi/README.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ ## Builld PPI for PDGrapher
2
+ 1. Using hgnc2map.txt (in data/raw/ppi/2022-03-PPI) with the raw PPI files (links are listed in the same folder), run union_ppi.py to generate ppi_edgelist.txt
3
+ 2. Using geneinfo_beta.txt and ppi_edgelist.txt, run export_ppi_all_genes.py to build ppi_all_genes_edgelist.txt
PDGrapher/data/scripts/ppi/export_ppi_all_genes.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Export PPI with all genes in LINCS (those that overlap)
3
+ '''
4
+
5
+ #Generate a subset of the PPI
6
+ #First checks the overlap between genes in PPI (BRIOGRID) and genes in LINCS
7
+ #Removes all genes from PPI that are *not* in LINCS (no GE data available for them)
8
+
9
+
10
+ import networkx as nx
11
+ import csrgraph as cg
12
+ from collections import Counter
13
+ import pandas as pd
14
+ import os
15
+ import os.path as osp
16
+
17
+ path_edge_list = '../../raw/ppi/2022-03-PPI/processed/ppi_edgelist.txt'
18
+ log_handle = open('log_ppi_all_genes.txt', 'w')
19
+
20
+
21
+ #Loads dataset PPI (BIOGRID)
22
+ ppi = nx.read_edgelist(path_edge_list)
23
+ #Loads gene info LINCS
24
+ gene_info = pd.read_csv('../../raw/lincs/2022-02-LINCS_Level3/data/geneinfo_beta.txt', sep="\t", low_memory=False)
25
+
26
+
27
+
28
+ log_handle.write('Overlap of genes from LINCS to PPI:{}/{}\n'.format(len(set(ppi.nodes()).intersection(set(gene_info['gene_symbol']))), len(gene_info)))
29
+
30
+ #Filter nodes from PPI to keep only the ones in LINCS
31
+ ppi = ppi.subgraph(gene_info['gene_symbol'].tolist())
32
+ log_handle.write('Keeping only PPI nodes that are in LINCS:{}\n'.format(ppi.number_of_nodes()))
33
+
34
+ ccs = [len(c) for c in sorted(nx.connected_components(ppi), key=len, reverse=True)]
35
+ log_handle.write('Number of connected componens:\t{}\n'.format(len(ccs)))
36
+ Gcc = sorted(nx.connected_components(ppi), key=len, reverse=True)
37
+ ppi = ppi.subgraph(Gcc[0])
38
+ log_handle.write('After keeping only biggest CC:\n')
39
+ log_handle.write('stats: {} nodes, {} edges, {} density, {} diameter\n\n\n'.format(ppi.number_of_nodes(), ppi.number_of_edges(), nx.density(ppi), nx.diameter(ppi)))
40
+
41
+ #Saves ppi
42
+ outdir = '../../processed/ppi'
43
+ os.makedirs(outdir, exist_ok=True)
44
+ ppi_f = osp.join(outdir, 'ppi_all_genes_edgelist.txt')
45
+
46
+ nx.write_edgelist(ppi, ppi_f, data=False)
47
+
48
+
49
+
50
+
51
+ log_handle.close()
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
PDGrapher/data/scripts/ppi/union_ppi.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Union BioGRID + Menche et al. 2015 + HuRI
2
+ import numpy as np
3
+ import networkx as nx
4
+ import pandas as pd
5
+ maxscore = 19
6
+ ref_score_list = {'Affinity Capture-MS':17,
7
+ 'Affinity Capture-Western':14,
8
+ 'Two-hybrid':1,
9
+ 'Reconstituted Complex':2,
10
+ 'Proximity Label-MS':7,
11
+ 'Co-fractionation':5,
12
+ 'Biochemical Activity':11,
13
+ 'Affinity Capture-RNA':13,
14
+ 'Co-localization':4,
15
+ 'Co-purification':6,
16
+ 'PCA':9,
17
+ 'Co-crystal Structure':18,
18
+ 'FRET':10,
19
+ 'Protein-peptide':16,
20
+ 'Affinity Capture-Luminescence':12,
21
+ 'Far Western':8,
22
+ 'Protein-RNA':3}
23
+
24
+ def read_biogrid(f, mapping):
25
+ edges = []
26
+ data = pd.read_csv(f, sep="\t")
27
+ source_ = data['Entrez Gene Interactor A'].values
28
+ target_ = data['Entrez Gene Interactor B'].values
29
+ ref = data['Experimental System'].values
30
+ score_ = np.array([ref_score_list[i] for i in ref])
31
+ for i in range(len(source_)):
32
+ source = str(source_[i])
33
+ target = str(target_[i])
34
+ score = score_[i]
35
+ if source in mapping and target in mapping:
36
+ source = mapping[source]
37
+ target = mapping[target]
38
+ temp = tuple(sorted((source, target)))
39
+ #if score == "-":
40
+ # score = maxscore
41
+ temp = temp + (score,)
42
+ edges.append(temp)
43
+ G = nx.Graph()
44
+ G.add_weighted_edges_from(edges)
45
+ print("BioGRID")
46
+ #print(nx.info(G))
47
+ for n in G.nodes:
48
+ if "," in n: print(n)
49
+ return G
50
+
51
+
52
+ def read_menche(f, mapping):
53
+ edges = []
54
+ with open(f) as fin:
55
+ for line in fin:
56
+ if line.startswith("#"): continue
57
+ source = line.split()[0]
58
+ target = line.split()[1]
59
+ if source in mapping and target in mapping:
60
+ source = mapping[source]
61
+ target = mapping[target]
62
+ temp = tuple(sorted((source, target)))
63
+ temp = temp + (maxscore,)
64
+ edges.append(temp)
65
+ G = nx.Graph()
66
+ G.add_weighted_edges_from(edges)
67
+ print("Menche et al. 2015")
68
+ #print(nx.info(G))
69
+ for n in G.nodes:
70
+ if "," in n: print(n)
71
+ return G
72
+
73
+
74
+ def read_huri(f, mapping):
75
+ edges = pd.read_csv(f, sep="\t", header=None)
76
+ edges['weight'] = maxscore
77
+ edges.columns = ["source", "target", "weight"]
78
+ G = nx.from_pandas_edgelist(edges, source='source', target='target', edge_attr='weight')
79
+ G = nx.relabel_nodes(G, mapping)
80
+ for n in G.nodes:
81
+ if "," in n: print(n)
82
+ nodes_to_remove = []
83
+ for n in G.nodes:
84
+ if n.startswith("ENS"): nodes_to_remove.append(n)
85
+ G.remove_nodes_from(nodes_to_remove)
86
+
87
+ print("HuRI")
88
+ #print(nx.info(G))
89
+ return G
90
+
91
+
92
+ def read_mapping(f):
93
+ entrez2hgnc = dict()
94
+ ensembl2hgnc = dict()
95
+ with open(f) as fin:
96
+ for line in fin:
97
+ hgnc_id = line.split("\t")[1].strip()
98
+ entrez_id = line.split("\t")[2].strip()
99
+ ensembl_id = line.split("\t")[3].strip()
100
+ if hgnc_id != "" and entrez_id != "":
101
+ if entrez_id in entrez2hgnc:
102
+ print(entrez_id, hgnc_id, entrez2hgnc[entrez_id])
103
+ if hgnc_id != entrez2hgnc[entrez_id]: hgnc_id = ",".join([entrez2hgnc[entrez_id], hgnc_id])
104
+ entrez2hgnc[entrez_id] = hgnc_id
105
+ if hgnc_id != "" and ensembl_id != "":
106
+ if ensembl_id in ensembl2hgnc:
107
+ print(ensembl_id, hgnc_id, ensembl2hgnc[ensembl_id])
108
+ if hgnc_id != ensembl2hgnc[ensembl_id]: hgnc_id = ",".join([ensembl2hgnc[ensembl_id], hgnc_id])
109
+ ensembl2hgnc[ensembl_id] = hgnc_id
110
+ print("Num mapping entrez2hgnc", len(entrez2hgnc))
111
+ print("Num mapping ensembl2hgnc", len(ensembl2hgnc))
112
+ return entrez2hgnc, ensembl2hgnc
113
+
114
+
115
+ def union_G(biogrid_G, menche_G, huri_G, ppi_f):
116
+ ppi = nx.Graph()
117
+ ppi.add_edges_from(biogrid_G.edges(data=True))
118
+ ppi.add_edges_from(menche_G.edges(data=True))
119
+ ppi.add_edges_from(huri_G.edges(data=True))
120
+ print("Overlap with PPI + BioGRID:", len(set(list(ppi.nodes)).intersection(set(list(biogrid_G.nodes)))))
121
+ print("Overlap with PPI + Menche:", len(set(list(ppi.nodes)).intersection(set(list(menche_G.nodes)))))
122
+ print("Overlap with PPI + HuRI:", len(set(list(ppi.nodes)).intersection(set(list(huri_G.nodes)))))
123
+ print("Overlap with BioGRID + Menche:", len(set(list(biogrid_G.nodes)).intersection(set(list(menche_G.nodes)))))
124
+ print("Overlap with BioGRID + HuRI:", len(set(list(biogrid_G.nodes)).intersection(set(list(huri_G.nodes)))))
125
+ print("Overlap with HuRI + Menche:", len(set(list(huri_G.nodes)).intersection(set(list(menche_G.nodes)))))
126
+ print("Overlap with BioGRID + HuRI + Menche:", len(set(list(biogrid_G.nodes)).intersection(set(list(huri_G.nodes)), set(list(menche_G.nodes)))))
127
+ print("Full PPI")
128
+ #print(nx.info(ppi))
129
+ nx.write_edgelist(ppi, ppi_f, data=True)
130
+ return ppi
131
+
132
+
133
+ def main():
134
+ entrez2hgnc, ensembl2hgnc = read_mapping("../../data/ppi/2022-03-PPI/hgnc2map.txt")
135
+ biogrid_G = read_biogrid("../../data/ppi/2022-03-PPI/BIOGRID-MV-Physical-4.4.207.tab3.txt", entrez2hgnc)
136
+ menche_G = read_menche("../../data/ppi/2022-03-PPI/DataS1_interactome.tsv", entrez2hgnc)
137
+ huri_G = read_huri("../../data/ppi/2022-03-PPI/HuRI.tsv", ensembl2hgnc)
138
+ ppi = union_G(biogrid_G, menche_G, huri_G, "../../data/ppi/2022-03-PPI/ppi_edgelist.txt")
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()
143
+
PDGrapher/data/scripts/random-baseline-cancer-targets/get_drugs_and_targets_cancer_cell_lines.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Builds data table with relevant cancer cell lines and corresponding drugs and targets
3
+ Log how many map to targets in DrugBank
4
+ '''
5
+
6
+ import pandas as pd
7
+ import os
8
+ import os.path as osp
9
+
10
+
11
+ #Outdir
12
+ outdir ='../../processed/nci'
13
+ os.makedirs(outdir, exist_ok=True)
14
+
15
+
16
+ #Cell lines and cancer
17
+ cancer_cell_mapping = {'breast': ['MCF7', 'BT20', 'MDAMB231'],
18
+ 'lung': ['A549'],
19
+ 'prostate': ['PC3', 'VCAP'],
20
+ 'gastric': ['AGS'],
21
+ 'skin': ['A375'],
22
+ 'cervical': ['HELA'],
23
+ 'colorectal': ['HT29'],
24
+ 'head': ['BICR6'],
25
+ 'ovarian': ['ES2'],
26
+ 'brain': ['U251MG'],
27
+ 'pancreatic': ['YAPC']}
28
+
29
+
30
+ #Loads data
31
+ cancer_drugs = pd.read_csv('../../raw/nci/2022-11-NCI/data/cancer_drugs_2024.csv')
32
+ cancer_drugs['drug'] =[e.lower() for e in cancer_drugs['drug']]
33
+ drug_targets = pd.read_csv('../../processed/drugbank/targets.txt', sep=',', low_memory=False)
34
+
35
+ drug_targets.columns = ['drug_id', 'drug_name', 'drug_synonyms', 'target_id', 'target_name', 'gene_name', 'gene_synonyms', 'identifiers', 'organism']
36
+ drug_targets['drug_name'] = [e.lower() for e in drug_targets['drug_name']]
37
+ drug_targets['drug_synonyms'] = [str(e).lower() for e in drug_targets['drug_synonyms']]
38
+
39
+ #Create dictionary of synonym-->drug
40
+ dict_syn_drug = dict()
41
+ for i in range(len(drug_targets)):
42
+ name = drug_targets.at[i, 'drug_name']
43
+ synonyms = drug_targets.at[i, 'drug_synonyms'].split('||') + [name]
44
+ for s in synonyms:
45
+ dict_syn_drug[s] = name
46
+
47
+
48
+ #Create dictionary of drug-->targets
49
+ dict_drug_targets = dict()
50
+ for i in range(len(drug_targets)):
51
+ name = drug_targets.at[i, 'drug_name']
52
+ targets = drug_targets[drug_targets['drug_name']==name]['gene_name'].tolist()
53
+ dict_drug_targets[name] = targets
54
+
55
+
56
+
57
+ #For each cancer, compile targets of approved drugs
58
+ #Manual mappings
59
+ manual_mappings = {'lapatinib ditosylate': 'lapatinib',
60
+ 'osimertinib mesylate': 'osimertinib',
61
+ 'abiraterone': 'abiraterone',
62
+ 'radium 223 dichloride': 'radium ra 223 dichloride',
63
+ 'rucaparib camsylate': 'rucaparib',
64
+ 'talazoparib tosylate': 'talazoparib',
65
+ 'tepotinib hydrochloride': 'tepotinib',
66
+ 'mobocertinib succinate': 'mobocertinib',
67
+ 'dabrafenib mesylate': 'dabrafenib',
68
+ 'afatinib dimaleate': 'afatinib dimaleate',
69
+ 'trametinib dimethyl sulfoxide': 'trametinib',
70
+ 'tamoxifen citrate': 'tamoxifen',
71
+ 'abiraterone acetate': 'abiraterone',
72
+ 'erlotinib hydrochloride': 'erlotinib',
73
+ 'neratinib maleate': 'neratinib',
74
+ 'lutetium lu 177 vipivotide tetraxetan': 'lutetium lu-177 vipivotide tetraxetan',
75
+ 'capmatinib hydrochloride': 'capmatinib',
76
+ 'afatinib dimaleate' : 'afatinib',
77
+ 'capmatinib hydrochloride': 'capmatinib',
78
+ 'toripalimab-tpzi': 'toripalimab',
79
+ 'amivantamab-vmjw': 'amivantamab',
80
+ 'cemiplimab-rwlc': 'cemiplimab',
81
+ 'fam-trastuzumab deruxtecan-nxki': 'Trastuzumab deruxtecan',
82
+ 'tarlatamab-dlle': 'tarlatamab',
83
+ 'tremelimumab-actl': 'tremelimumab',
84
+ 'sacituzumab govitecan-hziy':'Sacituzumab govitecan',
85
+ 'ado-trastuzumab emtansine': 'Trastuzumab emtansine',
86
+ 'margetuximab-cmkb':'Margetuximab',
87
+ 'sacituzumab govitecan-hziy':'Sacituzumab govitecan',
88
+ 'cobimetinib fumarate': 'cobimetinib',
89
+ 'retifanlimab-dlwr': 'retifanlimab',
90
+ 'tisotumab vedotin-tftv': 'tisotumab vedotin'
91
+ }
92
+
93
+ in_drugbank = set(dict_syn_drug.keys())
94
+ table_cancer_drugs_and_targets = []
95
+
96
+
97
+ log = open('log.txt', 'w')
98
+ for cancer in list(set(cancer_drugs['cancer_type'])):
99
+ not_mapped = []
100
+ drugs = cancer_drugs[cancer_drugs['cancer_type'] == cancer]['drug'].tolist()
101
+ drugs = [e.replace('\xa0', ' ').split(' (')[0] for e in drugs]
102
+ drugs = [manual_mappings[e] if e in manual_mappings else e for e in drugs]
103
+ for e in drugs:
104
+ if e =='pertuzumab, trastuzumab, and hyaluronidase-zzxf':
105
+ drugs.remove('pertuzumab, trastuzumab, and hyaluronidase-zzxf')
106
+ drugs.append('pertuzumab')
107
+ drugs.append('trastuzumab')
108
+ drugs.append('hyaluronidase')
109
+ cells = cancer_cell_mapping[cancer]
110
+ for cell in cells:
111
+ for d in drugs:
112
+ if d in dict_syn_drug:
113
+ name = dict_syn_drug[d]
114
+ else:
115
+ not_mapped.append(d)
116
+ targets = dict_drug_targets[name]
117
+ targets = ','.join(targets).replace('-,','')
118
+ table_cancer_drugs_and_targets.append([cell, name, targets])
119
+ log.write('CANCER:\t{},\tCELL LINE:\t{}\n'.format(cancer, cancer_cell_mapping[cancer]))
120
+ log.write('Number of approved drugs from NCI:\t{}\n'.format(len(set(drugs))))
121
+ log.write('Mapped drugs from NCI to DrugBank:\t{}/{}\n'.format(len(set(drugs).intersection(in_drugbank)) , len(set(drugs))))
122
+ log.write('Drugs not mapped:\n')
123
+ for d in not_mapped:
124
+ log.write('{}\n'.format(d))
125
+ log.write('\n----------\n')
126
+
127
+ log.close()
128
+
129
+ df = pd.DataFrame(table_cancer_drugs_and_targets, columns=['cell_line', 'drug', 'targets'])
130
+ df.to_csv(osp.join(outdir, 'drugs_and_targets.csv'), sep='\t', index = False)
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_scgen_chemical.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ import torch
4
+ import os.path as osp
5
+ import h5py
6
+ import pandas as pd
7
+ import numpy as np
8
+ import anndata
9
+
10
+ base_path = '../../processed/torch_data/chemical/real_lognorm'
11
+
12
+ cell_lines = ["A549","A375","BT20","HA1E","HELA","HT29","MCF7","MDAMB231","PC3","VCAP"]
13
+
14
+ for cell_line in cell_lines:
15
+ print("Processing cell line: ", cell_line)
16
+ #Loads datasets
17
+ data_backward = torch.load(osp.join(base_path, 'data_backward_' + cell_line + '.pt'))
18
+ #Builds datasets
19
+ data_treated = []
20
+ data_perturbagen = []
21
+ data_control = []
22
+ for data in data_backward:
23
+ data_control.append(data.diseased.numpy().tolist())
24
+ data_treated.append(data.treated.numpy().tolist())
25
+ data_perturbagen.append(data.perturbagen_name)
26
+ #Transforms datasets into pandas
27
+ data_control = pd.DataFrame(np.array(list(data_control)))
28
+ data_treated = pd.DataFrame(np.array(data_treated))
29
+ print(data_control.shape)
30
+ print(data_treated.shape)
31
+ #Creating obs
32
+ cellline = [cell_line for i in range(len(data_control) + len(data_treated))]
33
+ condition = ['control' for i in range(len(data_control))] + data_perturbagen
34
+ #Creates annotated data
35
+ X = pd.concat([data_control, data_treated], axis=0).reset_index(inplace=False, drop=True)
36
+ obs = pd.DataFrame([cellline, condition]).transpose()
37
+ obs.columns = ['cell_type', 'condition']
38
+ var = pd.DataFrame(data_backward[0].gene_symbols, columns = ['gene_symbols'])
39
+ train = anndata.AnnData(X, obs,var)
40
+ ind = torch.load(f"../../processed/splits/chemical/{cell_line}/random/5fold/splits.pt")
41
+ for j in range(1,6):
42
+ train_ = ind[j]["train_index_backward"]
43
+ test_ = ind[j]["test_index_backward"]
44
+ val_ = ind[j]["val_index_backward"]
45
+ print(len(train_) + len(test_) + len(val_))
46
+ assert len(train_) + len(test_) + len(val_) == len(train) / 2
47
+ print("Pass checking")
48
+ temp = np.array(['data0' for _ in range(len(data_treated))])
49
+ temp[train_] = 'train'
50
+ temp[test_] = 'test'
51
+ temp[val_] = 'val'
52
+ train.obs['split'+str(j)] = np.concatenate([temp, temp], axis=0) # same split for treated and control
53
+ train.write(
54
+ osp.join(base_path, 'data_split_' + cell_line +'.h5ad')
55
+ )
PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_scgen_genetic.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ import torch
5
+ import os.path as osp
6
+ import h5py
7
+
8
+
9
+
10
+ base_path = '../processed/real_lognorm'
11
+
12
+ #Loads datasets
13
+ #MCF7
14
+ # mcf7_forward = torch.load(osp.join(base_path, 'data_forward_MCF7.pt'))
15
+ mcf7_backward = torch.load(osp.join(base_path, 'data_backward_MCF7.pt'))
16
+
17
+ #A549
18
+ # a549_forward = torch.load(osp.join(base_path, 'data_forward_A549.pt'))
19
+ a549_backward = torch.load(osp.join(base_path, 'data_backward_A549.pt'))
20
+
21
+
22
+ #Builds datasets
23
+ mcf7_control = []
24
+ mcf7_treated = []
25
+ mcf7_perturbagen = []
26
+ for data in mcf7_backward:
27
+ mcf7_control.append(data.diseased.numpy().tolist())
28
+ mcf7_treated.append(data.treated.numpy().tolist())
29
+ mcf7_perturbagen.append(data.perturbagen_name)
30
+
31
+
32
+
33
+ a549_treated = []
34
+ a549_perturbagen = []
35
+ a549_control = []
36
+ for data in a549_backward:
37
+ a549_control.append(data.diseased.numpy().tolist())
38
+ a549_treated.append(data.treated.numpy().tolist())
39
+ a549_perturbagen.append(data.perturbagen_name)
40
+
41
+
42
+ #Transforms datasets into pandas
43
+ import numpy as np
44
+ import pandas as pd
45
+ mcf7_control = pd.DataFrame(np.array(list(mcf7_control)))
46
+ mcf7_treated = pd.DataFrame(np.array(mcf7_treated))
47
+ a549_control = pd.DataFrame(np.array(list(a549_control)))
48
+ a549_treated = pd.DataFrame(np.array(a549_treated))
49
+
50
+
51
+ #Creating obs
52
+ cell_line = ['MCF7' for i in range(len(mcf7_control) + len(mcf7_treated))] + ['A549' for i in range(len(a549_control) + len(a549_treated))]
53
+ condition = ['control' for i in range(len(mcf7_control))] + mcf7_perturbagen + ['control' for i in range(len(a549_control))] + a549_perturbagen
54
+
55
+
56
+ #Creates annotated data
57
+ X = pd.concat([mcf7_control, mcf7_treated, a549_control, a549_treated], 0).reset_index(inplace=False, drop=True)
58
+ obs = pd.DataFrame([cell_line, condition]).transpose()
59
+ obs.columns = ['cell_type', 'condition']
60
+ var = pd.DataFrame(a549_backward[0].gene_symbols, columns = ['gene_symbols'])
61
+
62
+ import anndata
63
+ train = anndata.AnnData(X, obs,var)
64
+
65
+ import hdf5plugin
66
+ train.write(
67
+ osp.join(base_path, 'data_scgen.h5ad')
68
+ )
69
+
70
+
PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_torch_geometric.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Exports data for proof of concept model
3
+ Code taken from rep-learning-approach
4
+ changed to adapt to new data sources (healthy cell lines + COSMIC)
5
+
6
+ '''
7
+
8
+
9
+ import pandas as pd
10
+ import networkx as nx
11
+ import numpy as np
12
+ import os
13
+ import os.path as osp
14
+ import math
15
+ import torch
16
+ from torch_geometric.data import Data
17
+ from torch_geometric.utils import add_remaining_self_loops, to_undirected
18
+
19
+ ############
20
+ #Data loading
21
+ ############
22
+ def load_ppi(path_edge_list, log_handle):
23
+ #Loads PPI
24
+ ppi = nx.read_edgelist(path_edge_list)
25
+ log_handle.write('----------------\nNumber of nodes in PPI:\t{}\n'.format(ppi.number_of_nodes()))
26
+ log_handle.write('Number of edges in PPI:\t{}\n'.format(ppi.number_of_edges()))
27
+ return ppi
28
+
29
+
30
+ def load_gene_metadata(file, log_handle):
31
+ #Loads gene metadata
32
+ gene_info = pd.read_csv(file)
33
+ # dict_symbol_index = dict(zip(gene_info['gene_symbol'], range(len(gene_info)))) #genes are ordered with the same ordering as rows in data matrices
34
+ dict_entrez_symbol = dict(zip(gene_info['gene_id'], gene_info['gene_symbol']))
35
+ dict_symbol_entrez = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
36
+ return gene_info, dict_entrez_symbol, dict_symbol_entrez
37
+
38
+ def load_cosmic(path_cosmic_file, log_handle):
39
+ data = pd.read_csv(path_cosmic_file)
40
+ log_handle.write('Loading COSMIC data. Number of cell lines:\t{}\n'.format(len(set(data['Sample name']))))
41
+ return data
42
+
43
+
44
+ def map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle):
45
+ cosmic_data = cosmic_data[cosmic_data['Sample name']==cell_line]
46
+ log_handle.write('Mapping cosmic genes to lincs. Mapped: {}/{}\n'.format(len(set(cosmic_data['Gene name']).intersection(gene_info['gene_symbol'])), len(set(cosmic_data['Gene name']))))
47
+ #Filter genes not mapped to LINCS
48
+ cosmic_data = cosmic_data[[gene_symbol in dict_symbol_entrez for gene_symbol in cosmic_data['Gene name']]]
49
+ #Save COSMIC mutations as entrez id (dataframe index)
50
+ try:
51
+ cosmic_mutations = list(set([dict_symbol_entrez[symbol] for symbol in cosmic_data['Gene name'].tolist()]))
52
+ except:
53
+ import pdb; pdb.set_trace()
54
+ return cosmic_mutations
55
+
56
+
57
+
58
+ def load_healthy_data(data_root_dir, healthy, log_handle):
59
+ healthy_data_path = osp.join(data_root_dir, 'cell_line_{}_pert_{}.npz'.format(healthy[0], healthy[1]))
60
+ healthy_metadata_path = osp.join(data_root_dir, 'cell_line_{}_pert_{}_metadata.txt'.format(healthy[0], healthy[1]))
61
+ #Loads metadata
62
+ healthy_metadata = pd.read_csv(healthy_metadata_path)
63
+ #Loads data
64
+ with np.load(healthy_data_path, allow_pickle=True) as arr:
65
+ healthy_data =arr['data']
66
+ col_ids = arr['col_ids']
67
+ row_ids = arr['row_ids']
68
+ healthy_data = pd.DataFrame(healthy_data, columns= col_ids, index=row_ids)
69
+ log_handle.write('Loading healthy cell line:\t{} Number of samples:\t{}\n'.format(healthy[0], healthy_data.shape[1]))
70
+ return healthy_data, healthy_metadata
71
+
72
+
73
+
74
+
75
+
76
+ def load_data(cell_line, data_root_dir, log_handle):
77
+ #Loads data matrix (observational)
78
+ file = osp.join(data_root_dir, 'cell_line_{}_pert_ctl_vector.npz'.format(cell_line))
79
+ file_metadata = osp.join(data_root_dir, 'cell_line_{}_pert_ctl_vector_metadata.txt'.format(cell_line))
80
+ obs_metadata = pd.read_csv(file_metadata)
81
+ with np.load(file, allow_pickle=True) as arr:
82
+ obs_data =arr['data']
83
+ col_ids = arr['col_ids']
84
+ row_ids = arr['row_ids']
85
+ obs_data = pd.DataFrame(obs_data, columns= col_ids, index=row_ids)
86
+ log_handle.write('Number of observational datapoints:\t{}\n'.format(len(obs_metadata)))
87
+ #Loads data matrix (interventional)
88
+ file = osp.join(data_root_dir, 'cell_line_{}_pert_trt_xpr.npz'.format(cell_line))
89
+ file_metadata = osp.join(data_root_dir, 'cell_line_{}_pert_trt_xpr_metadata.txt'.format(cell_line))
90
+ int_metadata = pd.read_csv(file_metadata)
91
+ with np.load(file, allow_pickle=True) as arr:
92
+ int_data =arr['data']
93
+ col_ids = arr['col_ids']
94
+ row_ids = arr['row_ids']
95
+ int_data = pd.DataFrame(int_data, columns= col_ids, index=row_ids)
96
+ log_handle.write('Number of interventional datapoints:\t{}\n'.format(len(int_metadata)))
97
+ return obs_metadata, obs_data, int_metadata, int_data
98
+
99
+
100
+
101
+
102
+ ############
103
+ #Processing
104
+ ############
105
+
106
+ def filter_data(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle):
107
+ #1.Filter out obs and int data to keep only genes that are in the PPI
108
+ gene_symbols_in_ppi = list(ppi.nodes())
109
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
110
+ gene_ids_in_ppi = [dict_symbol_id[i] for i in gene_symbols_in_ppi]
111
+ gene_info.index = gene_info['gene_id']; gene_info = gene_info.loc[gene_ids_in_ppi].reset_index(inplace=False, drop=True)
112
+ obs_data = obs_data.loc[gene_ids_in_ppi]
113
+ int_data = int_data.loc[gene_ids_in_ppi]
114
+ if healthy_data is not None:
115
+ healthy_data = healthy_data.loc[gene_ids_in_ppi]
116
+ if cosmic_mutations is not None:
117
+ cosmic_mutations = pd.DataFrame(cosmic_mutations)[[e in gene_ids_in_ppi for e in cosmic_mutations]][0].tolist()
118
+ #2. Filter out samples whose interventions are not in the remaining genes (those in the PPI)
119
+ keep = []
120
+ for i, gene_symbol in enumerate(int_metadata['cmap_name']):
121
+ if gene_symbol in gene_symbols_in_ppi:
122
+ keep.append(int_metadata.at[i, 'sample_id'])
123
+ int_metadata.index = int_metadata['sample_id']; int_metadata = int_metadata.loc[keep].reset_index(inplace=False, drop=True)
124
+ int_data = int_data[keep]
125
+ log_handle.write('Number of interventional datapoints after keeping only those with perturbed genes in PPI:\t{}\n'.format(len(int_metadata)))
126
+ return healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info
127
+
128
+
129
+
130
+
131
+
132
+ ############
133
+ #Asembling the data
134
+ ############
135
+
136
+ def assemble_data_list(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle):
137
+ log_handle.write('Assembling data...\n')
138
+
139
+ #First, we re-index genes in PPI and data
140
+ #Gene symbol to index to ordered index
141
+ gene_symbol_to_index = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
142
+ gene_index_to_ordered_index = dict(zip(gene_info['gene_id'], range(len(gene_info))))
143
+ gene_info['ordered_index'] = [gene_index_to_ordered_index[i] for i in gene_info['gene_id']]
144
+
145
+
146
+ #Reindex genes in PPI, obs_data, int_data, healty_data, and cosmic_mutations
147
+ ppi = nx.relabel_nodes(ppi, gene_symbol_to_index)
148
+ ppi = nx.relabel_nodes(ppi, gene_index_to_ordered_index)
149
+ int_data.index = [gene_index_to_ordered_index[i] for i in int_data.index]
150
+ int_data = int_data.sort_index(inplace=False)
151
+ obs_data.index = [gene_index_to_ordered_index[i] for i in obs_data.index]
152
+ obs_data = obs_data.sort_index(inplace=False)
153
+ if healthy_data is not None:
154
+ healthy_data.index = [gene_index_to_ordered_index[i] for i in healthy_data.index]
155
+ healthy_data = healthy_data.sort_index(inplace=False)
156
+ if cosmic_mutations is not None:
157
+ cosmic_mutations = [gene_index_to_ordered_index[i] for i in cosmic_mutations]
158
+ cosmic_vector = np.zeros(len(healthy_data))
159
+ cosmic_vector[cosmic_mutations] = 1
160
+
161
+
162
+ #Assembling samples
163
+ edge_index = torch.LongTensor(np.array(ppi.edges()).transpose())
164
+ edge_index = add_remaining_self_loops(edge_index)[0]
165
+ edge_index = to_undirected(edge_index)
166
+ number_of_nodes = ppi.number_of_nodes()
167
+
168
+ #remove incoming edges to perturbed nodes (mutated nodes)
169
+ # mask = [e not in cosmic_mutations for e in edge_index[1,:]]
170
+ # edge_index_mutilated = edge_index[:, mask]
171
+ # edge_index_mutilated = add_remaining_self_loops(edge_index_mutilated)[0]
172
+
173
+ dict_forward_sample_and_mutations = dict() #saves the mutation vector used in forward
174
+
175
+
176
+
177
+ forward_data_list = []
178
+ if healthy_data is not None: #we only build forward data when we have healthy samples
179
+ #FORWARD DATA - healthy_data, cosmic_vector, obs_data
180
+ #each Data object will be a pairing of a random healthy_data column, the cosmic mutations, and a obs_data column
181
+ #will have as many as obs_data columns
182
+ i = 0
183
+ order = np.array(range(healthy_data.shape[1]))
184
+ np.random.shuffle(order)
185
+ for sample_id in obs_data.columns:
186
+ #sample a random healthy GE vector
187
+ i = i % healthy_data.shape[1]
188
+ sample_index = order[i]
189
+ healthy_sample = healthy_data[healthy_data.columns[i]].values
190
+ healthy = torch.Tensor(healthy_sample)
191
+ #mutation
192
+ #randomize mutations. First select the percentage of mutations to include, then select the mutations
193
+ perc_to_include = np.random.choice([0.25, 0.50, 0.75, 1], 1).item()
194
+ if int_metadata['cell_mfc_name'][0].split('.')[0] == 'PC3':
195
+ perc_to_include = 1
196
+ cosmic_mutations_i = np.random.choice(cosmic_mutations, int(len(cosmic_mutations)* perc_to_include))
197
+ cosmic_vector = np.zeros(len(healthy_data))
198
+ cosmic_vector[cosmic_mutations_i] = 1
199
+ mutations = torch.Tensor(cosmic_vector)
200
+ #diseased
201
+ diseased = torch.Tensor(obs_data[sample_id])
202
+ data = Data(healthy = healthy, mutations=mutations, diseased=diseased, gene_symbols = gene_info['gene_symbol'].tolist())
203
+ data.num_nodes = number_of_nodes
204
+ forward_data_list.append(data)
205
+ #Save
206
+ i +=1
207
+ dict_forward_sample_and_mutations[sample_id] = mutations
208
+ print('finished data forward')
209
+
210
+
211
+ #BACKWARD DATA - obs_data, int_data
212
+ #dict sample id: perturbed gene ordered index
213
+ dict_sample_id_perturbed_gene_ordered_index = dict()
214
+ for sample_id, cmap_name in zip(int_metadata['sample_id'], int_metadata['cmap_name']):
215
+ dict_sample_id_perturbed_gene_ordered_index[sample_id] = gene_index_to_ordered_index[gene_symbol_to_index[cmap_name]]
216
+
217
+
218
+ #these are helpers to sample from obs_data
219
+ order = np.array(range(obs_data.shape[1]))
220
+ np.random.shuffle(order)
221
+ i = 0
222
+ #shuffle obs data columns
223
+ backward_data_list = []
224
+ unique_names_pert = set()
225
+ for sample_id in int_data.columns:
226
+ binary_indicator_perturbation = np.zeros(len(int_data))
227
+ binary_indicator_perturbation[dict_sample_id_perturbed_gene_ordered_index[sample_id]] = 1
228
+ #Get a random pre-intervention sample
229
+ i = i % obs_data.shape[1]
230
+ sample_index = order[i]
231
+ obs_sample_id = obs_data.columns[i]
232
+ obs_sample = obs_data[obs_data.columns[i]].values
233
+ #concat initial node features and perturbation indicator
234
+ diseased = torch.Tensor(obs_sample)
235
+ intervention = torch.Tensor(binary_indicator_perturbation)
236
+ if healthy_data is not None:
237
+ mutations = dict_forward_sample_and_mutations[obs_sample_id]
238
+ else:
239
+ mutations = torch.Tensor(np.zeros(len(diseased)))
240
+ # torch.Tensor(np.stack([obs_sample, binary_indicator_perturbation], 1))
241
+ #post-intervention
242
+ treated = torch.Tensor(int_data[sample_id])
243
+ #remove incoming edges to perturbed node
244
+ # perturbed_node = dict_sample_id_perturbed_gene_ordered_index[sample_id]
245
+ # edge_index_mutilated = edge_index[:, edge_index[1,:] != perturbed_node]
246
+
247
+ gene_name = int_metadata[int_metadata['sample_id'] == sample_id]['cmap_name'].item()
248
+ unique_names_pert.add(gene_name)
249
+ data = Data(perturbagen_name = gene_name, diseased = diseased, intervention=intervention, treated = treated, gene_symbols = gene_info['gene_symbol'].tolist(), mutations = mutations)
250
+ data.num_nodes = number_of_nodes
251
+ backward_data_list.append(data)
252
+ i +=1
253
+
254
+ log_handle.write('Samples forward:\t{}\n'.format(len(forward_data_list)))
255
+ log_handle.write('Samples backward:\t{}\n'.format(len(backward_data_list)))
256
+ log_handle.write('Unique perturbagens:\t{}\n'.format(len(unique_names_pert)))
257
+
258
+ return forward_data_list, backward_data_list, edge_index
259
+
260
+
261
+
262
+
263
+ def save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle):
264
+ log_handle.write('Saving data {} ...\n\n\n'.format(cell_line))
265
+ torch.save(forward_data_list, osp.join(outdir, 'data_forward_{}.pt'.format(cell_line)))
266
+ torch.save(backward_data_list, osp.join(outdir, 'data_backward_{}.pt'.format(cell_line)))
267
+ torch.save(edge_index, osp.join(outdir, 'edge_index_{}.pt'.format(cell_line)))
268
+ return
269
+
270
+
271
+ binarization = 'real_lognorm'
272
+ outdir = '../../processed/torch_data/{}/'.format(binarization)
273
+ os.makedirs(outdir, exist_ok=True)
274
+
275
+
276
+
277
+
278
+ def main():
279
+ #cell-line wise
280
+ log_handle = open(osp.join(outdir, 'log_export_data.txt'), 'w')
281
+ data_root_dir = '../../processed/lincs/{}'.format(binarization)
282
+
283
+ #Samples with healthy counterparts
284
+ for cell_line, healthy in zip(['A549', 'MCF7', 'PC3'], [('NL20', 'ctl_vehicle'), ('MCF10A', 'ctl_untrt'), ('RWPE1', 'ctl_vector')]):
285
+ log_handle.write('----------------\n\nCELL LINE:{}\n----------------\n'.format(cell_line))
286
+ #PPI
287
+ ppi = load_ppi('../../processed/ppi/ppi_all_genes_edgelist.txt', log_handle)
288
+ #gene info
289
+ gene_info, dict_entrez_symbol, dict_symbol_entrez = load_gene_metadata('../../processed/lincs/gene_info.txt', log_handle)
290
+ #FORWARD DATA
291
+ #healthy GE data
292
+ healthy_data, healthy_metadata = load_healthy_data(data_root_dir, healthy, log_handle)
293
+ #COSMIC
294
+ cosmic_data = load_cosmic('../../processed/cosmic/CosmicCLP_MutantExport_only_verified_and_curated.csv', log_handle)
295
+ cosmic_mutations = map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle)
296
+ #BACKWARD DATA
297
+ #LINCS
298
+ obs_metadata, obs_data, int_metadata, int_data = load_data(cell_line, data_root_dir, log_handle)
299
+ healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info = filter_data(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
300
+
301
+
302
+ forward_data_list, backward_data_list, edge_index = assemble_data_list(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
303
+ # save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle)
304
+
305
+
306
+
307
+
308
+ #Samples without healthy counterparts
309
+ for cell_line, healthy in zip(['A375', 'HT29', 'ES2', 'BICR6', 'YAPC', 'AGS', 'U251MG'], [None, None, None, None, None, None, None]):
310
+ log_handle.write('----------------\n\nCELL LINE:{}\n----------------\n'.format(cell_line))
311
+ #PPI
312
+ ppi = load_ppi('../../processed/ppi/ppi_all_genes_edgelist.txt', log_handle)
313
+ #gene info
314
+ gene_info, dict_entrez_symbol, dict_symbol_entrez = load_gene_metadata('../../processed/lincs/gene_info.txt', log_handle)
315
+
316
+
317
+ #FORWARD DATA
318
+ #healthy GE data
319
+ # healthy_data, healthy_metadata = load_healthy_data(data_root_dir, healthy, log_handle)
320
+ #COSMIC
321
+ # cosmic_data = load_cosmic('../../processed/cosmic/CosmicCLP_MutantExport_only_verified_and_curated.csv', log_handle)
322
+ # cosmic_mutations = map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle)
323
+ #BACKWARD DATA
324
+ #LINCS
325
+ obs_metadata, obs_data, int_metadata, int_data = load_data(cell_line, data_root_dir, log_handle)
326
+
327
+
328
+ healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info = filter_data(None, None, None, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
329
+
330
+
331
+ forward_data_list, backward_data_list, edge_index = assemble_data_list(None, None, None, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
332
+ # save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle)
333
+
334
+
335
+ log_handle.close()
336
+
337
+
338
+
339
+
340
+
341
+
342
+
343
+ if __name__ == "__main__":
344
+ main()
PDGrapher/data/scripts/rep-learning-approach-3-all-genes/export_data_for_torch_geometric_chemical.py ADDED
@@ -0,0 +1,391 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Exports data for proof of concept model
3
+ Code taken from rep-learning-approach
4
+ changed to adapt to new data sources (healthy cell lines + COSMIC)
5
+
6
+ '''
7
+
8
+
9
+ import pandas as pd
10
+ import networkx as nx
11
+ import numpy as np
12
+ import os
13
+ import os.path as osp
14
+ import math
15
+ import torch
16
+ from torch_geometric.data import Data
17
+ from torch_geometric.utils import add_remaining_self_loops, to_undirected
18
+
19
+
20
+
21
+
22
+ ############
23
+ #Data loading
24
+ ############
25
+ def load_ppi(path_edge_list, log_handle):
26
+ #Loads PPI
27
+ ppi = nx.read_edgelist(path_edge_list)
28
+ log_handle.write('----------------\nNumber of nodes in PPI:\t{}\n'.format(ppi.number_of_nodes()))
29
+ log_handle.write('Number of edges in PPI:\t{}\n'.format(ppi.number_of_edges()))
30
+ return ppi
31
+
32
+
33
+ def load_gene_metadata(file, log_handle):
34
+ #Loads gene metadata
35
+ gene_info = pd.read_csv(file)
36
+ # dict_symbol_index = dict(zip(gene_info['gene_symbol'], range(len(gene_info)))) #genes are ordered with the same ordering as rows in data matrices
37
+ dict_entrez_symbol = dict(zip(gene_info['gene_id'], gene_info['gene_symbol']))
38
+ dict_symbol_entrez = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
39
+ return gene_info, dict_entrez_symbol, dict_symbol_entrez
40
+
41
+ def load_cosmic(path_cosmic_file, log_handle):
42
+ data = pd.read_csv(path_cosmic_file)
43
+ log_handle.write('Loading COSMIC data. Number of cell lines:\t{}\n'.format(len(set(data['Sample name']))))
44
+ return data
45
+
46
+
47
+ def map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle):
48
+ cosmic_data = cosmic_data[cosmic_data['Sample name']==cell_line]
49
+ log_handle.write('Mapping cosmic genes to lincs. Mapped: {}/{}\n'.format(len(set(cosmic_data['Gene name']).intersection(gene_info['gene_symbol'])), len(set(cosmic_data['Gene name']))))
50
+ #Filter genes not mapped to LINCS
51
+ cosmic_data = cosmic_data[[gene_symbol in dict_symbol_entrez for gene_symbol in cosmic_data['Gene name']]]
52
+ #Save COSMIC mutations as entrez id (dataframe index)
53
+ cosmic_mutations = list(set([dict_symbol_entrez[symbol] for symbol in cosmic_data['Gene name']]))
54
+ return cosmic_mutations
55
+
56
+
57
+
58
+ def load_healthy_data(data_root_dir, healthy, log_handle):
59
+ healthy_data_path = osp.join(data_root_dir, 'cell_line_{}_pert_{}.npz'.format(healthy[0], healthy[1]))
60
+ healthy_metadata_path = osp.join(data_root_dir, 'cell_line_{}_pert_{}_metadata.txt'.format(healthy[0], healthy[1]))
61
+ #Loads metadata
62
+ healthy_metadata = pd.read_csv(healthy_metadata_path)
63
+ #Loads data
64
+ with np.load(healthy_data_path, allow_pickle=True) as arr:
65
+ healthy_data =arr['data']
66
+ col_ids = arr['col_ids']
67
+ row_ids = arr['row_ids']
68
+ healthy_data = pd.DataFrame(healthy_data, columns= col_ids, index=row_ids)
69
+ log_handle.write('Loading healthy cell line:\t{} Number of samples:\t{}\n'.format(healthy[0], healthy_data.shape[1]))
70
+ return healthy_data, healthy_metadata
71
+
72
+
73
+
74
+
75
+
76
+ def load_data(cell_line, data_root_dir, log_handle):
77
+ #Loads data matrix (observational)
78
+ file = osp.join(data_root_dir, 'cell_line_{}_pert_ctl_vehicle.npz'.format(cell_line))
79
+ file_metadata = osp.join(data_root_dir, 'cell_line_{}_pert_ctl_vehicle_metadata.txt'.format(cell_line))
80
+ obs_metadata = pd.read_csv(file_metadata)
81
+ with np.load(file, allow_pickle=True) as arr:
82
+ obs_data =arr['data']
83
+ col_ids = arr['col_ids']
84
+ row_ids = arr['row_ids']
85
+ obs_data = pd.DataFrame(obs_data, columns= col_ids, index=row_ids)
86
+ log_handle.write('Number of observational datapoints:\t{}\n'.format(len(obs_metadata)))
87
+ #Loads data matrix (interventional)
88
+ file = osp.join(data_root_dir, 'cell_line_{}_pert_trt_cp.npz'.format(cell_line))
89
+ file_metadata = osp.join(data_root_dir, 'cell_line_{}_pert_trt_cp_metadata.txt'.format(cell_line))
90
+ int_metadata = pd.read_csv(file_metadata)
91
+ with np.load(file, allow_pickle=True) as arr:
92
+ int_data =arr['data']
93
+ col_ids = arr['col_ids']
94
+ row_ids = arr['row_ids']
95
+ int_data = pd.DataFrame(int_data, columns= col_ids, index=row_ids)
96
+ log_handle.write('Number of interventional datapoints:\t{}\n'.format(len(int_metadata)))
97
+ return obs_metadata, obs_data, int_metadata, int_data
98
+
99
+
100
+
101
+
102
+ ############
103
+ #Processing
104
+ ############
105
+
106
+ def filter_data(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle):
107
+ #1.Filter out obs and int data to keep only genes that are in the PPI
108
+ gene_symbols_in_ppi = list(ppi.nodes())
109
+ dict_symbol_id = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
110
+ gene_ids_in_ppi = [dict_symbol_id[i] for i in gene_symbols_in_ppi]
111
+ gene_info.index = gene_info['gene_id']; gene_info = gene_info.loc[gene_ids_in_ppi].reset_index(inplace=False, drop=True)
112
+ obs_data = obs_data.loc[gene_ids_in_ppi]
113
+ int_data = int_data.loc[gene_ids_in_ppi]
114
+ if healthy_data is not None:
115
+ healthy_data = healthy_data.loc[gene_ids_in_ppi]
116
+ if cosmic_mutations is not None:
117
+ cosmic_mutations = pd.DataFrame(cosmic_mutations)[[e in gene_ids_in_ppi for e in cosmic_mutations]][0].tolist()
118
+ log_handle.write('Mutations remaining in PPI:\t{}\n'.format(len(cosmic_mutations)))
119
+ #2. Filter out samples whose interventions are not in the remaining genes (those in the PPI)
120
+ keep = []
121
+ for i, gene_symbols in enumerate(int_metadata['target_names']):
122
+ gene_symbols = gene_symbols.replace("[\'", "").replace("\']", "").replace(' ','').replace('\'','').split(',')
123
+ if len(set(gene_symbols).intersection(set(gene_symbols_in_ppi))) > 0:
124
+ keep.append(int_metadata.at[i, 'sample_id'])
125
+ int_metadata.index = int_metadata['sample_id']; int_metadata = int_metadata.loc[keep].reset_index(inplace=False, drop=True)
126
+ int_data = int_data[keep]
127
+ log_handle.write('Number of interventional datapoints after keeping only those with perturbed genes in PPI:\t{}\n'.format(len(int_metadata)))
128
+ return healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info
129
+
130
+
131
+
132
+
133
+
134
+ ############
135
+ #Asembling the data
136
+ ############
137
+
138
+ def assemble_data_list(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle):
139
+ log_handle.write('Assembling data...\n')
140
+
141
+ #First, we re-index genes in PPI and data
142
+ #Gene symbol to index to ordered index
143
+ gene_symbol_to_index = dict(zip(gene_info['gene_symbol'], gene_info['gene_id']))
144
+ gene_index_to_ordered_index = dict(zip(gene_info['gene_id'], range(len(gene_info))))
145
+ gene_info['ordered_index'] = [gene_index_to_ordered_index[i] for i in gene_info['gene_id']]
146
+
147
+
148
+ #Reindex genes in PPI, obs_data, int_data, healty_data, and cosmic_mutations
149
+ ppi = nx.relabel_nodes(ppi, gene_symbol_to_index)
150
+ ppi = nx.relabel_nodes(ppi, gene_index_to_ordered_index)
151
+ int_data.index = [gene_index_to_ordered_index[i] for i in int_data.index]
152
+ int_data = int_data.sort_index(inplace=False)
153
+ obs_data.index = [gene_index_to_ordered_index[i] for i in obs_data.index]
154
+ obs_data = obs_data.sort_index(inplace=False)
155
+ if healthy_data is not None:
156
+ healthy_data.index = [gene_index_to_ordered_index[i] for i in healthy_data.index]
157
+ healthy_data = healthy_data.sort_index(inplace=False)
158
+ if cosmic_mutations is not None:
159
+ cosmic_mutations = [gene_index_to_ordered_index[i] for i in cosmic_mutations]
160
+ cosmic_vector = np.zeros(len(healthy_data))
161
+ cosmic_vector[cosmic_mutations] = 1
162
+
163
+
164
+ #Assembling samples
165
+ edge_index = torch.LongTensor(np.array(ppi.edges()).transpose())
166
+ edge_index = add_remaining_self_loops(edge_index)[0]
167
+ edge_index = to_undirected(edge_index)
168
+ number_of_nodes = ppi.number_of_nodes()
169
+
170
+ #Pre-compute distances from each node to each of the nodes mutated and save in a dictionary
171
+
172
+ G = nx.Graph()
173
+ G.add_edges_from(tuple(zip(edge_index[0,:].tolist(), edge_index[1,:].tolist())))
174
+ # dict_node_mutation_spl = dict()
175
+ # for node_index in range(G.number_of_nodes()):
176
+ # for mutation in cosmic_mutations:
177
+ # spl = nx.shortest_path_length(G, node_index, mutation)
178
+ # dict_node_mutation_spl[(node_index, mutation)] = spl
179
+
180
+
181
+
182
+
183
+ #remove incoming edges to perturbed nodes (mutated nodes)
184
+ # mask = [e not in cosmic_mutations for e in edge_index[1,:]]
185
+ # edge_index_mutilated = edge_index[:, mask]
186
+ # edge_index_mutilated = add_remaining_self_loops(edge_index_mutilated)[0]
187
+
188
+ dict_forward_sample_and_mutations = dict() #saves the mutation vector used in forward
189
+ forward_data_list = []
190
+ if healthy_data is not None: #Only process forward list if we have healthy data
191
+ #FORWARD DATA - healthy_data, cosmic_vector, obs_data
192
+ #each Data object will be a pairing of a random healthy_data column, the cosmic mutations, and a obs_data column
193
+ #will have as many as obs_data columns
194
+ i = 0
195
+ order = np.array(range(healthy_data.shape[1]))
196
+ np.random.shuffle(order)
197
+
198
+ for sample_id in obs_data.columns:
199
+ #sample a random healthy GE vector
200
+ i = i % healthy_data.shape[1]
201
+ sample_index = order[i]
202
+ healthy_sample = healthy_data[healthy_data.columns[i]].values
203
+ healthy = torch.Tensor(healthy_sample)
204
+ #mutation
205
+ #randomize mutations. First select the percentage of mutations to include, then select the mutations
206
+
207
+ perc_to_include = np.random.choice([0.25, 0.50, 0.75, 1], 1).item()
208
+ if int_metadata['cell_mfc_name'][0].split('.')[0] == 'PC3' or int_metadata['cell_mfc_name'][0].split('.')[0] == 'VCAP':
209
+ perc_to_include = 1
210
+
211
+ cosmic_mutations_i = np.random.choice(cosmic_mutations, int(len(cosmic_mutations)* perc_to_include))
212
+ cosmic_vector = np.zeros(len(healthy_data))
213
+ cosmic_vector[cosmic_mutations_i] = 1
214
+ mutations = torch.Tensor(cosmic_vector)
215
+ #diseased
216
+ diseased = torch.Tensor(obs_data[sample_id])
217
+ #additional features
218
+ mutation_gene_indices = torch.where(mutations)[0].tolist()
219
+ # additional_features = []
220
+ # for node_index in range(len(healthy)):
221
+ # spls = [dict_node_mutation_spl[(node_index, e)] for e in mutation_gene_indices]
222
+ # additional_features.append(torch.Tensor([np.min(spls), np.max(spls), np.mean(spls)]))
223
+ data = Data(healthy = healthy, mutations=mutations, diseased=diseased, gene_symbols = gene_info['gene_symbol'].tolist())
224
+ data.num_nodes = number_of_nodes
225
+ forward_data_list.append(data)
226
+ #Save
227
+ i +=1
228
+ dict_forward_sample_and_mutations[sample_id] = mutations
229
+
230
+ print('finished data forward')
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+ #BACKWARD DATA - obs_data, int_data
239
+
240
+
241
+ #dict sample id: perturbed gene ordered index
242
+
243
+ dict_sample_id_perturbed_gene_ordered_index = dict()
244
+ for sample_id, gene_symbols in zip(int_metadata['sample_id'], int_metadata['target_names']):
245
+ dict_sample_id_perturbed_gene_ordered_index[sample_id] = []
246
+ for gene in gene_symbols.replace("[\'", "").replace("\']", "").replace(' ','').replace('\'','').split(','):
247
+ if gene in gene_symbol_to_index:
248
+ dict_sample_id_perturbed_gene_ordered_index[sample_id].append(gene_index_to_ordered_index[gene_symbol_to_index[gene]])
249
+ if len(dict_sample_id_perturbed_gene_ordered_index[sample_id])==0:
250
+ print(sample_id)
251
+
252
+
253
+ #Fill dictionary with remaining spls
254
+ # perturbations = list(dict_sample_id_perturbed_gene_ordered_index.values())
255
+ # perturbations = [item for sublist in perturbations for item in sublist]
256
+ # perturbations = list(set(perturbations))
257
+ # dict_node_mutation_spl = dict()
258
+ # for node_index in range(G.number_of_nodes()):
259
+ # for mutation in perturbations:
260
+ # if (node_index, mutation) in dict_node_mutation_spl:
261
+ # continue
262
+ # else:
263
+ # spl = nx.shortest_path_length(G, node_index, mutation)
264
+ # dict_node_mutation_spl[(node_index, mutation)] = spl
265
+
266
+
267
+ #these are helpers to sample from obs_data
268
+ order = np.array(range(obs_data.shape[1]))
269
+ np.random.shuffle(order)
270
+ i = 0
271
+ #shuffle obs data columns
272
+ backward_data_list = []
273
+ unique_names_pert = set()
274
+ for sample_id in int_data.columns:
275
+ binary_indicator_perturbation = np.zeros(len(int_data))
276
+ binary_indicator_perturbation[dict_sample_id_perturbed_gene_ordered_index[sample_id]] = 1
277
+ #Get a random pre-intervention sample
278
+ i = i % obs_data.shape[1]
279
+ sample_index = order[i]
280
+ obs_sample_id = obs_data.columns[i]
281
+ obs_sample = obs_data[obs_data.columns[i]].values
282
+ #concat initial node features and perturbation indicator
283
+ diseased = torch.Tensor(obs_sample)
284
+ intervention = torch.Tensor(binary_indicator_perturbation)
285
+ if healthy_data is not None:
286
+ mutations = dict_forward_sample_and_mutations[obs_sample_id]
287
+ else:
288
+ mutations = torch.Tensor(np.zeros(len(diseased)))
289
+ # torch.Tensor(np.stack([obs_sample, binary_indicator_perturbation], 1))
290
+ #post-intervention
291
+ treated = torch.Tensor(int_data[sample_id])
292
+ #remove incoming edges to perturbed node
293
+ # perturbed_node = dict_sample_id_perturbed_gene_ordered_index[sample_id]
294
+ # edge_index_mutilated = edge_index[:, edge_index[1,:] != perturbed_node]
295
+ #additional features
296
+ # additional_features = []
297
+ # for node_index in range(len(diseased)):
298
+ # spls = [dict_node_mutation_spl[(node_index, e)] for e in dict_sample_id_perturbed_gene_ordered_index[sample_id]]
299
+ # additional_features.append(torch.Tensor([np.min(spls), np.max(spls), np.mean(spls)]))
300
+ drug_name = int_metadata[int_metadata['sample_id'] == sample_id]['cmap_name'].item()
301
+ unique_names_pert.add(drug_name)
302
+ data = Data(perturbagen_name = drug_name, diseased = diseased, intervention=intervention, treated = treated, gene_symbols = gene_info['gene_symbol'].tolist(), mutations = mutations)
303
+ data.num_nodes = number_of_nodes
304
+ backward_data_list.append(data)
305
+ i +=1
306
+
307
+ log_handle.write('Samples forward:\t{}\n'.format(len(forward_data_list)))
308
+ log_handle.write('Samples backward:\t{}\n'.format(len(backward_data_list)))
309
+ log_handle.write('Unique perturbagens:\t{}\n'.format(len(unique_names_pert)))
310
+ return forward_data_list, backward_data_list, edge_index
311
+
312
+
313
+
314
+
315
+ def save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle):
316
+ log_handle.write('Saving data {} ...\n\n\n'.format(cell_line))
317
+ torch.save(forward_data_list, osp.join(outdir, 'data_forward_{}.pt'.format(cell_line)))
318
+ torch.save(backward_data_list, osp.join(outdir, 'data_backward_{}.pt'.format(cell_line)))
319
+ torch.save(edge_index, osp.join(outdir, 'edge_index_{}.pt'.format(cell_line)))
320
+ return
321
+
322
+
323
+ binarization = 'real_lognorm'
324
+ outdir = '../../processed/torch_data/chemical/{}'.format(binarization)
325
+ os.makedirs(outdir, exist_ok=True)
326
+
327
+
328
+
329
+
330
+ def main():
331
+ #cell-line wise
332
+ log_handle = open(osp.join(outdir, 'log_export_data.txt'), 'w')
333
+ data_root_dir = '../../processed/lincs/chemical/nofilter_dose_timepoint/{}'.format(binarization)
334
+ data_root_dir_healthy = '../../processed/lincs/chemical/{}'.format(binarization)
335
+ # , ('RWPE1', 'ctl_vector')
336
+
337
+ #Cell lines with healthy counterparts
338
+ for cell_line, healthy in zip(['A549', 'MCF7', 'PC3', 'VCAP', 'MDAMB231', 'BT20'], [('NL20', 'ctl_vehicle'), ('MCF10A', 'ctl_vehicle'), ('RWPE1', 'ctl_vector'), ('RWPE1', 'ctl_vector'), ('MCF10A', 'ctl_vehicle'), ('MCF10A', 'ctl_vehicle')]):
339
+ log_handle.write('----------------\n\nCELL LINE:{}\n----------------\n'.format(cell_line))
340
+ #PPI
341
+ ppi = load_ppi('../../processed/ppi/ppi_all_genes_edgelist.txt', log_handle)
342
+ #gene info
343
+ gene_info, dict_entrez_symbol, dict_symbol_entrez = load_gene_metadata('../../processed/lincs/chemical/nofilter_dose_timepoint/gene_info.txt', log_handle)
344
+ #FORWARD DATA
345
+ #healthy GE data
346
+ healthy_data, healthy_metadata = load_healthy_data(data_root_dir_healthy, healthy, log_handle)
347
+ #COSMIC
348
+ cosmic_data = load_cosmic('../../processed/cosmic/CosmicCLP_MutantExport_only_verified_and_curated.csv', log_handle)
349
+ cosmic_mutations = map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle)
350
+ #BACKWARD DATA
351
+ #LINCS
352
+ obs_metadata, obs_data, int_metadata, int_data = load_data(cell_line, data_root_dir, log_handle)
353
+ healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info = filter_data(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
354
+
355
+
356
+ forward_data_list, backward_data_list, edge_index = assemble_data_list(healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
357
+ # save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle)
358
+
359
+
360
+ #Cell lines without healthy counterparts
361
+ for cell_line, healthy in zip(['HA1E', 'HT29', 'A375', 'HELA'], [None, None, None, None]):
362
+ log_handle.write('----------------\n\nCELL LINE:{}\n----------------\n'.format(cell_line))
363
+ #PPI
364
+ ppi = load_ppi('../../processed/ppi/ppi_all_genes_edgelist.txt', log_handle)
365
+ #gene info
366
+ gene_info, dict_entrez_symbol, dict_symbol_entrez = load_gene_metadata('../../processed/lincs/chemical/nofilter_dose_timepoint/gene_info.txt', log_handle)
367
+ #FORWARD DATA
368
+ #healthy GE data
369
+ # healthy_data, healthy_metadata = load_healthy_data(data_root_dir_healthy, healthy, log_handle)
370
+ #COSMIC
371
+ cosmic_data = load_cosmic('../../processed/cosmic/CosmicCLP_MutantExport_only_verified_and_curated.csv', log_handle)
372
+ cosmic_mutations = map_cosmic_to_lincs(cosmic_data, cell_line, gene_info, dict_symbol_entrez, log_handle)
373
+ #BACKWARD DATA
374
+ #LINCS
375
+ obs_metadata, obs_data, int_metadata, int_data = load_data(cell_line, data_root_dir, log_handle)
376
+ healthy_data, healthy_metadata, cosmic_mutations, obs_metadata, obs_data, int_metadata, int_data, gene_info = filter_data(None, None, None, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
377
+
378
+
379
+ forward_data_list, backward_data_list, edge_index = assemble_data_list(None, None, None, obs_metadata, obs_data, int_metadata, int_data, ppi, gene_info, log_handle)
380
+ # save_data(forward_data_list, backward_data_list, edge_index, cell_line, log_handle)
381
+
382
+ log_handle.close()
383
+
384
+
385
+
386
+
387
+
388
+
389
+
390
+ if __name__ == "__main__":
391
+ main()
PDGrapher/data/scripts/splits/create_standard_splits.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##Create splits to be used for training across all models
2
+
3
+ import os
4
+ import os.path as osp
5
+ from sklearn.model_selection import KFold, train_test_split
6
+ import torch
7
+ from sklearn.metrics import jaccard_score
8
+ import pandas as pd
9
+ import numpy as np
10
+ import matplotlib.pyplot as plt
11
+
12
+
13
+
14
+ def create_splits_n_fold(dataset, splits_type, nfolds, outdir):
15
+ kf = KFold(nfolds, shuffle=True, random_state=42)
16
+ os.makedirs(outdir, exist_ok = True)
17
+
18
+ #datasets forward and backward
19
+ dataset_forward = dataset[0]; dataset_backward = dataset[1]
20
+ splits = {}
21
+
22
+
23
+ if splits_type =='random':
24
+ i = 1
25
+ if len(dataset_forward)> 0:
26
+ for train_test_index_forward, train_test_index_backward in zip(kf.split(dataset_forward), kf.split(dataset_backward)):
27
+ #Forward
28
+ train_index_forward = train_test_index_forward[0]; test_index_forward = train_test_index_forward[1]
29
+ train_index_backward = train_test_index_backward[0]; test_index_backward = train_test_index_backward[1]
30
+ #Backward
31
+ train_index_forward, val_index_forward = train_test_split(train_index_forward, test_size=0.2, random_state=42)
32
+ train_index_backward, val_index_backward = train_test_split(train_index_backward, test_size=0.2, random_state=42)
33
+
34
+ assert len(dataset_backward) == len(train_index_backward) + len(val_index_backward) + len(test_index_backward), 'Splitted datasets should have the same number of samples as full dataset'
35
+ assert len(set(test_index_forward).intersection(train_index_forward)) ==0, "Overlap between train and test indices should be zero"
36
+ assert len(set(test_index_forward).intersection(val_index_forward)) ==0, "Overlap between val and test indices should be zero"
37
+ assert len(set(train_index_forward).intersection(val_index_forward)) ==0, "Overlap between train and val indices should be zero"
38
+ assert len(set(test_index_backward).intersection(train_index_backward)) ==0, "Overlap between train and test indices should be zero"
39
+ assert len(set(test_index_backward).intersection(val_index_backward)) ==0, "Overlap between val and test indices should be zero"
40
+ assert len(set(train_index_backward).intersection(val_index_backward)) ==0, "Overlap between train and val indices should be zero"
41
+
42
+ splits[i] = {'train_index_forward': train_index_forward,
43
+ 'val_index_forward': val_index_forward,
44
+ 'test_index_forward': test_index_forward,
45
+ 'train_index_backward': train_index_backward,
46
+ 'val_index_backward': val_index_backward,
47
+ 'test_index_backward': test_index_backward}
48
+ i += 1
49
+ else:
50
+ for train_test_index_backward in kf.split(dataset_backward):
51
+ #Backward
52
+ train_index_backward = train_test_index_backward[0]; test_index_backward = train_test_index_backward[1]
53
+ train_index_backward, val_index_backward = train_test_split(train_index_backward, test_size=0.2, random_state=42)
54
+
55
+ assert len(dataset_backward) == len(train_index_backward) + len(val_index_backward) + len(test_index_backward), 'Splitted datasets should have the same number of samples as full dataset'
56
+ assert len(set(test_index_backward).intersection(train_index_backward)) ==0, "Overlap between train and test indices should be zero"
57
+ assert len(set(test_index_backward).intersection(val_index_backward)) ==0, "Overlap between val and test indices should be zero"
58
+ assert len(set(train_index_backward).intersection(val_index_backward)) ==0, "Overlap between train and val indices should be zero"
59
+
60
+ splits[i] = {'train_index_forward': None,
61
+ 'val_index_forward': None,
62
+ 'test_index_forward': None,
63
+ 'train_index_backward': train_index_backward,
64
+ 'val_index_backward': val_index_backward,
65
+ 'test_index_backward': test_index_backward}
66
+ i += 1
67
+
68
+ torch.save(splits, osp.join(outdir,'splits.pt'))
69
+ return
70
+
71
+
72
+
73
+
74
+ ###Generate splits
75
+ os.makedirs('../../processed/splits/', exist_ok=True)
76
+ nfolds = 5
77
+ for dataset_type in ['genetic', 'chemical']:
78
+ for dataset_name in ['A375', 'A549', 'MCF7', 'PC3', 'HT29', 'ES2', 'BICR6', 'YAPC', 'AGS', 'U251MG', 'VCAP', 'MDAMB231', 'BT20', 'HA1E', 'HELA']:
79
+ for splits_type in ['random']:
80
+ splits_setting = '{}fold'.format(nfolds)
81
+ outdir = '../../processed/splits/{}/{}/{}/{}'.format(dataset_type, dataset_name, splits_type, splits_setting)
82
+
83
+ if dataset_type == 'genetic':
84
+ base_path = "../../processed/torch_data/real_lognorm"
85
+ elif dataset_type =='chemical':
86
+ base_path = "../../processed/torch_data/chemical/real_lognorm"
87
+
88
+ try:
89
+ path = osp.join(base_path, 'data_forward_{}.pt'.format(dataset_name))
90
+ dataset_forward = torch.load(path)
91
+ path = osp.join(base_path, 'data_backward_{}.pt'.format(dataset_name))
92
+ dataset_backward = torch.load(path)
93
+ dataset = [dataset_forward, dataset_backward]
94
+
95
+ create_splits_n_fold(dataset, splits_type, nfolds, outdir)
96
+ except:
97
+ continue