decoupler 1.3.2__tar.gz → 1.9.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. decoupler-1.9.2/PKG-INFO +95 -0
  2. decoupler-1.3.2/PKG-INFO → decoupler-1.9.2/README.md +18 -22
  3. decoupler-1.9.2/decoupler/__init__.py +39 -0
  4. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/benchmark.py +38 -22
  5. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/decouple.py +23 -9
  6. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_aucell.py +52 -59
  7. decoupler-1.9.2/decoupler/method_gsea.py +368 -0
  8. decoupler-1.9.2/decoupler/method_gsva.py +324 -0
  9. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_mdt.py +13 -15
  10. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_mlm.py +19 -21
  11. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_ora.py +97 -70
  12. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_udt.py +11 -12
  13. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_ulm.py +41 -45
  14. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_viper.py +22 -19
  15. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_wmean.py +30 -31
  16. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/method_wsum.py +29 -30
  17. decoupler-1.9.2/decoupler/method_zscore.py +89 -0
  18. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/metrics.py +44 -0
  19. decoupler-1.9.2/decoupler/omnip.py +440 -0
  20. decoupler-1.9.2/decoupler/plotting.py +1909 -0
  21. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/pre.py +67 -19
  22. decoupler-1.9.2/decoupler/tests/__init__.py +0 -0
  23. decoupler-1.9.2/decoupler/tests/test_aucell.py +39 -0
  24. decoupler-1.9.2/decoupler/tests/test_benchmark.py +89 -0
  25. decoupler-1.9.2/decoupler/tests/test_consensus.py +31 -0
  26. decoupler-1.9.2/decoupler/tests/test_decouple.py +64 -0
  27. decoupler-1.9.2/decoupler/tests/test_gsea.py +49 -0
  28. decoupler-1.9.2/decoupler/tests/test_gsva.py +96 -0
  29. decoupler-1.9.2/decoupler/tests/test_mdt.py +52 -0
  30. decoupler-1.9.2/decoupler/tests/test_metrics.py +122 -0
  31. decoupler-1.9.2/decoupler/tests/test_mlm.py +33 -0
  32. decoupler-1.9.2/decoupler/tests/test_omnip.py +62 -0
  33. decoupler-1.9.2/decoupler/tests/test_ora.py +61 -0
  34. decoupler-1.9.2/decoupler/tests/test_plotting.py +495 -0
  35. decoupler-1.9.2/decoupler/tests/test_pre.py +141 -0
  36. decoupler-1.9.2/decoupler/tests/test_udt.py +53 -0
  37. decoupler-1.9.2/decoupler/tests/test_ulm.py +84 -0
  38. decoupler-1.9.2/decoupler/tests/test_utils.py +162 -0
  39. decoupler-1.9.2/decoupler/tests/test_utilsanndata.py +585 -0
  40. decoupler-1.9.2/decoupler/tests/test_utilsbenchmark.py +421 -0
  41. decoupler-1.9.2/decoupler/tests/test_viper.py +43 -0
  42. decoupler-1.9.2/decoupler/tests/test_wmean.py +33 -0
  43. decoupler-1.9.2/decoupler/tests/test_wsum.py +33 -0
  44. decoupler-1.9.2/decoupler/tests/test_zscore.py +52 -0
  45. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/utils.py +12 -7
  46. decoupler-1.9.2/decoupler/utils_anndata.py +1120 -0
  47. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/utils_benchmark.py +85 -62
  48. decoupler-1.9.2/pyproject.toml +105 -0
  49. decoupler-1.3.2/README.md +0 -45
  50. decoupler-1.3.2/decoupler/__init__.py +0 -27
  51. decoupler-1.3.2/decoupler/method_gsea.py +0 -270
  52. decoupler-1.3.2/decoupler/method_gsva.py +0 -237
  53. decoupler-1.3.2/decoupler/omnip.py +0 -467
  54. decoupler-1.3.2/decoupler/plotting.py +0 -710
  55. decoupler-1.3.2/decoupler/utils_anndata.py +0 -544
  56. decoupler-1.3.2/decoupler.egg-info/PKG-INFO +0 -59
  57. decoupler-1.3.2/decoupler.egg-info/SOURCES.txt +0 -30
  58. decoupler-1.3.2/decoupler.egg-info/dependency_links.txt +0 -1
  59. decoupler-1.3.2/decoupler.egg-info/requires.txt +0 -4
  60. decoupler-1.3.2/decoupler.egg-info/top_level.txt +0 -1
  61. decoupler-1.3.2/setup.cfg +0 -4
  62. decoupler-1.3.2/setup.py +0 -27
  63. {decoupler-1.3.2 → decoupler-1.9.2}/LICENSE +0 -0
  64. {decoupler-1.3.2 → decoupler-1.9.2}/decoupler/consensus.py +0 -0
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.3
2
+ Name: decoupler
3
+ Version: 1.9.2
4
+ Summary: Ensemble of methods to infer biological activities from omics data
5
+ License: GPL-3.0-only
6
+ Keywords: systems biology,molecular biology,signaling network,transcriptomics,modeling,mechanistic modeling,activity inference,molecular network,omics,biomedicine,molecular footprint,molecular signature
7
+ Author: Pau Badia i Mompel
8
+ Author-email: pau.badia@uni-heidelberg.de
9
+ Requires-Python: >=3.10,<3.12
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Natural Language :: English
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
21
+ Provides-Extra: full
22
+ Requires-Dist: adjusttext (>=1.1.1,<2.0.0) ; extra == "full"
23
+ Requires-Dist: igraph (>=0.11.5,<0.12.0) ; extra == "full"
24
+ Requires-Dist: liana (>=1.5.0,<2.0.0) ; extra == "full"
25
+ Requires-Dist: marsilea (>=0.4.5,<0.5.0) ; extra == "full"
26
+ Requires-Dist: numba (>=0.61.0,<0.62.0)
27
+ Requires-Dist: numpy (>=2,<3)
28
+ Requires-Dist: pandas (>=2.2.2,<3.0.0)
29
+ Requires-Dist: pybiomart (>=0.2.0,<0.3.0) ; extra == "full"
30
+ Requires-Dist: pydeseq2 (>=0.4.0,<0.5.0) ; extra == "full"
31
+ Requires-Dist: scikit-learn (>=1.5.0,<2.0.0) ; extra == "full"
32
+ Requires-Dist: tqdm (>=4.66.4,<5.0.0)
33
+ Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
34
+ Project-URL: Bug Tracker, https://github.com/saezlab/decoupler-py/issues
35
+ Project-URL: Documentation, https://decoupler.readthedocs.io/
36
+ Project-URL: Homepage, https://decoupler.readthedocs.io/
37
+ Project-URL: Repository, https://github.com/saezlab/decoupler-py
38
+ Description-Content-Type: text/markdown
39
+
40
+ # decoupler - Ensemble of methods to infer biological activities <img src="https://github.com/saezlab/decoupleR/blob/master/inst/figures/logo.svg?raw=1" align="right" width="120" class="no-scaled-link" />
41
+ <!-- badges: start -->
42
+ [![main](https://github.com/saezlab/decoupler-py/actions/workflows/ci.yml/badge.svg)](https://github.com/saezlab/decoupler-py/actions)
43
+ [![GitHub issues](https://img.shields.io/github/issues/saezlab/decoupler-py.svg)](https://github.com/saezlab/decoupler-py/issues/)
44
+ [![Documentation Status](https://readthedocs.org/projects/decoupler-py/badge/?version=latest)](https://decoupler-py.readthedocs.io/en/latest/?badge=latest)
45
+ [![codecov](https://codecov.io/gh/saezlab/decoupler-py/branch/main/graph/badge.svg?token=TM0P29KKN5)](https://codecov.io/gh/saezlab/decoupler-py)
46
+ [![Downloads](https://static.pepy.tech/badge/decoupler)](https://pepy.tech/project/decoupler)
47
+
48
+ [![Conda Recipe](https://img.shields.io/badge/recipe-decoupler--py-green.svg)](https://anaconda.org/conda-forge/decoupler-py)
49
+ [![Conda page](https://img.shields.io/conda/vn/conda-forge/decoupler-py.svg)](https://anaconda.org/conda-forge/decoupler-py)
50
+ [![Conda downloads](https://img.shields.io/conda/dn/conda-forge/decoupler-py.svg)](https://anaconda.org/conda-forge/decoupler-py)
51
+ <!-- badges: end -->
52
+
53
+ `decoupler` is a package containing different enrichment statistical methods to extract biologically driven scores from omics data within a unified framework.
54
+ This is its faster and memory efficient Python implementation, for the R version go [here](https://github.com/saezlab/decoupleR).
55
+
56
+ For further information and example tutorials, please check our [documentation](https://decoupler-py.readthedocs.io/en/latest/index.html).
57
+
58
+ If you have any question or problem do not hesitate to open an [issue](https://github.com/saezlab/decoupler-py/issues).
59
+
60
+ ## Installation
61
+
62
+ `decoupler` can be installed from `pip` (lightweight installation)::
63
+ ```
64
+ pip install decoupler
65
+ ```
66
+
67
+ It can also be installed from `conda` and `mamba` (this includes extra dependencies):
68
+ ```
69
+ mamba create -n=decoupler conda-forge::decoupler-py
70
+ ```
71
+
72
+ Alternatively, to stay up-to-date with the newest unreleased version, install from source:
73
+ ```
74
+ pip install git+https://github.com/saezlab/decoupler-py.git
75
+ ```
76
+
77
+ ## scverse
78
+ `decoupler` is part of the [scverse](https://scverse.org) ecosystem, a collection of tools for single-cell omics data analysis in python.
79
+ For more information check the link.
80
+
81
+ ## License
82
+ Enrichment methods inside decoupler can be used for academic or commercial purposes, except `viper` which holds a non-commercial license.
83
+
84
+ The data redistributed by OmniPath does not have a single license, each original resource has its own. By default, `decoupler`
85
+ assumes an academic license, but commercial or nonprofit licenses can be specified in the `license` parameter of `decoupler`'s OmniPath functions.
86
+ [Here](https://omnipathdb.org/info) one can find the license information of all the resources in OmniPath.
87
+
88
+ ## Citation
89
+
90
+ Badia-i-Mompel P., Vélez Santiago J., Braunger J., Geiss C., Dimitrov D.,
91
+ Müller-Dott S., Taus P., Dugourd A., Holland C.H., Ramirez Flores R.O.
92
+ and Saez-Rodriguez J. 2022. decoupleR: Ensemble of computational methods
93
+ to infer biological activities from omics data. Bioinformatics Advances.
94
+ <https://doi.org/10.1093/bioadv/vbac016>
95
+
@@ -1,27 +1,17 @@
1
- Metadata-Version: 2.1
2
- Name: decoupler
3
- Version: 1.3.2
4
- Summary: Ensemble of methods to infer biological activities from omics data
5
- Home-page: https://github.com/saezlab/decoupler-py
6
- Author: Pau Badia i Mompel
7
- Author-email: pau.badia@uni-heidelberg.de
8
- Project-URL: Bug Tracker, https://github.com/saezlab/decoupler-py/issues
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.6
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
-
15
1
  # decoupler - Ensemble of methods to infer biological activities <img src="https://github.com/saezlab/decoupleR/blob/master/inst/figures/logo.svg?raw=1" align="right" width="120" class="no-scaled-link" />
16
2
  <!-- badges: start -->
17
- [![main](https://github.com/saezlab/decoupler-py/actions/workflows/main.yml/badge.svg)](https://github.com/saezlab/decoupler-py/actions)
3
+ [![main](https://github.com/saezlab/decoupler-py/actions/workflows/ci.yml/badge.svg)](https://github.com/saezlab/decoupler-py/actions)
18
4
  [![GitHub issues](https://img.shields.io/github/issues/saezlab/decoupler-py.svg)](https://github.com/saezlab/decoupler-py/issues/)
19
- [![Downloads](https://pepy.tech/badge/decoupler)](https://pepy.tech/project/decoupler)
20
5
  [![Documentation Status](https://readthedocs.org/projects/decoupler-py/badge/?version=latest)](https://decoupler-py.readthedocs.io/en/latest/?badge=latest)
21
6
  [![codecov](https://codecov.io/gh/saezlab/decoupler-py/branch/main/graph/badge.svg?token=TM0P29KKN5)](https://codecov.io/gh/saezlab/decoupler-py)
7
+ [![Downloads](https://static.pepy.tech/badge/decoupler)](https://pepy.tech/project/decoupler)
8
+
9
+ [![Conda Recipe](https://img.shields.io/badge/recipe-decoupler--py-green.svg)](https://anaconda.org/conda-forge/decoupler-py)
10
+ [![Conda page](https://img.shields.io/conda/vn/conda-forge/decoupler-py.svg)](https://anaconda.org/conda-forge/decoupler-py)
11
+ [![Conda downloads](https://img.shields.io/conda/dn/conda-forge/decoupler-py.svg)](https://anaconda.org/conda-forge/decoupler-py)
22
12
  <!-- badges: end -->
23
13
 
24
- **decoupler** is a package containing different statistical methods to extract biological activities from omics data within a unified framework.
14
+ `decoupler` is a package containing different enrichment statistical methods to extract biologically driven scores from omics data within a unified framework.
25
15
  This is its faster and memory efficient Python implementation, for the R version go [here](https://github.com/saezlab/decoupleR).
26
16
 
27
17
  For further information and example tutorials, please check our [documentation](https://decoupler-py.readthedocs.io/en/latest/index.html).
@@ -30,24 +20,30 @@ If you have any question or problem do not hesitate to open an [issue](https://g
30
20
 
31
21
  ## Installation
32
22
 
33
- To install the latest stable version run:
23
+ `decoupler` can be installed from `pip` (lightweight installation)::
34
24
  ```
35
25
  pip install decoupler
36
26
  ```
37
27
 
38
- Alternatively, to stay up-to-date with the newest version, run:
28
+ It can also be installed from `conda` and `mamba` (this includes extra dependencies):
29
+ ```
30
+ mamba create -n=decoupler conda-forge::decoupler-py
31
+ ```
32
+
33
+ Alternatively, to stay up-to-date with the newest unreleased version, install from source:
39
34
  ```
40
35
  pip install git+https://github.com/saezlab/decoupler-py.git
41
36
  ```
42
37
 
43
38
  ## scverse
44
- **decoupler** is part of the [scverse](https://scverse.org) ecosystem, a collection of tools for single-cell omics data analysis in python.
39
+ `decoupler` is part of the [scverse](https://scverse.org) ecosystem, a collection of tools for single-cell omics data analysis in python.
45
40
  For more information check the link.
46
41
 
47
42
  ## License
48
- Footprint methods inside decoupler can be used for academic or commercial purposes, except `viper` which holds a non-commercial license.
43
+ Enrichment methods inside decoupler can be used for academic or commercial purposes, except `viper` which holds a non-commercial license.
49
44
 
50
- The data redistributed by OmniPath does not have a license, each original resource carries their own.
45
+ The data redistributed by OmniPath does not have a single license, each original resource has its own. By default, `decoupler`
46
+ assumes an academic license, but commercial or nonprofit licenses can be specified in the `license` parameter of `decoupler`'s OmniPath functions.
51
47
  [Here](https://omnipathdb.org/info) one can find the license information of all the resources in OmniPath.
52
48
 
53
49
  ## Citation
@@ -0,0 +1,39 @@
1
+ __version__ = '1.9.2' # noqa: F401
2
+ __version_info__ = tuple([int(num) for num in __version__.split('.')]) # noqa: F401
3
+
4
+ from .pre import extract, match, rename_net, get_net_mat, filt_min_n, mask_features, return_data, break_ties # noqa: F401
5
+ from .utils import (
6
+ melt, show_methods, check_corr, get_toy_data, summarize_acts, assign_groups, dense_run, p_adjust_fdr, shuffle_net,
7
+ read_gmt # noqa: F401
8
+ )
9
+ from .utils_anndata import (
10
+ get_acts, swap_layer, get_pseudobulk, get_contrast, rank_sources_groups, get_top_targets, format_contrast_results,
11
+ filter_by_expr, filter_by_prop, get_metadata_associations # noqa: F401
12
+ )
13
+ from .method_wmean import run_wmean # noqa: F401
14
+ from .method_wsum import run_wsum # noqa: F401
15
+ from .method_ulm import run_ulm # noqa: F401
16
+ from .method_mdt import run_mdt # noqa: F401
17
+ from .method_mlm import run_mlm # noqa: F401
18
+ from .method_udt import run_udt # noqa: F401
19
+ from .method_ora import run_ora, test1r, get_ora_df # noqa: F401
20
+ from .method_gsva import run_gsva # noqa: F401
21
+ from .method_gsea import run_gsea, get_gsea_df # noqa: F401
22
+ from .method_viper import run_viper # noqa: F401
23
+ from .method_aucell import run_aucell # noqa: F401
24
+ from .method_zscore import run_zscore # noqa: F401
25
+ from .decouple import decouple, run_consensus # noqa: F401
26
+ from .consensus import cons # noqa: F401
27
+ from .omnip import (
28
+ show_resources, get_resource, get_progeny, get_dorothea, translate_net, get_collectri, get_ksn_omnipath, show_organisms # noqa: F401
29
+ )
30
+ from .plotting import (
31
+ plot_volcano, plot_violins, plot_barplot, plot_metrics_scatter, plot_metrics_boxplot, plot_metrics_scatter_cols,
32
+ plot_psbulk_samples, plot_filter_by_expr, plot_filter_by_prop, plot_volcano_df, plot_targets, plot_running_score,
33
+ plot_dotplot, plot_barplot_df, plot_associations, plot_network # noqa: F401
34
+ )
35
+ from .benchmark import benchmark, format_benchmark_inputs, get_performances # noqa: F401
36
+ from .utils_benchmark import get_toy_benchmark_data, show_metrics # noqa: F401
37
+ from .metrics import (
38
+ metric_auroc, metric_auprc, metric_mcauroc, metric_mcauprc, metric_rank, metric_nrank, metric_recall # noqa: F401
39
+ )
@@ -9,15 +9,15 @@ import pandas as pd
9
9
  from .decouple import decouple
10
10
  from .utils_anndata import extract_psbulk_inputs
11
11
  from .pre import rename_net, filt_min_n
12
- from .utils_benchmark import format_acts_grts, append_metrics_scores
12
+ from .utils_benchmark import format_acts_grts, append_metrics_scores, adjust_sign
13
13
  from .utils_benchmark import validate_metrics, check_groupby, rename_obs
14
14
 
15
15
 
16
- def get_performances(res, obs, groupby, by, metrics, min_exp=5, pi0=0.5, n_iter=1000,
17
- seed=42, verbose=False):
16
+ def get_performances(res, obs, groupby, by, metrics, use_pval=None, min_exp=5, pi0=0.5,
17
+ n_iter=1000, seed=42, verbose=False):
18
18
 
19
19
  # Return acts, grts and msks tensors
20
- acts, grts, msks, srcs, mthds, grpbys, grps = format_acts_grts(res, obs, groupby)
20
+ acts, grts, msks, srcs, mthds, grpbys, grps = format_acts_grts(res, obs, groupby, use_pval)
21
21
 
22
22
  # Init empty df
23
23
  df = []
@@ -90,30 +90,36 @@ def format_benchmark_inputs(mat, obs, perturb, sign, net, groupby, by, f_expr=Tr
90
90
  srcs = net['source'].values.astype('U')
91
91
  for i, src in enumerate(obs['perturb']):
92
92
  msk[i] = np.any(np.isin(src, srcs))
93
- if verbose:
94
- n = np.sum(~msk)
95
- print("{0} experiments without sources in net, they will be removed.".format(n))
96
93
  mat, obs = mat[msk], obs.loc[msk]
94
+ if verbose:
95
+ n_removed = np.sum(~msk)
96
+ print("Removed {0} experiments without sources in net.".format(n_removed))
97
97
 
98
98
  # Remove sources without experiments in obs
99
99
  if f_srcs:
100
- msk = np.isin(net['source'].values, obs['perturb'].values.ravel())
101
- if verbose:
102
- n = np.sum(~msk)
103
- print("{0} sources without experiments in obs, they will be removed.".format(n))
100
+ srcs = net.loc[:, 'source'].values
101
+ msk = np.isin(srcs, obs['perturb'].values.ravel())
104
102
  net = net.loc[msk]
103
+ if verbose:
104
+ n_removed = np.unique(srcs[~msk]).size
105
+ print("Removed {0} sources without experiments in obs.".format(n_removed))
105
106
 
106
107
  return mat, obs, var, net, groupby
107
108
 
108
109
 
109
110
  def _benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc'], groupby=None, by='experiment', f_expr=True,
110
- f_srcs=False, min_exp=5, pi0=0.5, n_iter=1000, seed=42, verbose=True, use_raw=True, decouple_kws={}):
111
+ f_srcs=False, use_pval=None, min_exp=5, pi0=0.5, n_iter=1000, seed=42, verbose=True, use_raw=True,
112
+ decouple_kws={}):
111
113
 
112
114
  # Format inputs
113
115
  mat, obs, var, net, groupby = format_benchmark_inputs(mat, obs, perturb, sign, net, groupby, by, f_expr=f_expr,
114
116
  f_srcs=f_srcs, verbose=verbose, use_raw=use_raw,
115
117
  decouple_kws=decouple_kws)
116
118
 
119
+ # Adjust sign
120
+ mat = adjust_sign(mat, obs['sign'].values)
121
+ obs['sign'] = 1
122
+
117
123
  # Reset net names args
118
124
  decouple_kws['source'] = 'source'
119
125
  decouple_kws['target'] = 'target'
@@ -121,23 +127,31 @@ def _benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc'], groupby
121
127
 
122
128
  # Run prediction
123
129
  if verbose:
130
+ srcs = []
131
+ for p in obs.loc[:, 'perturb']:
132
+ if isinstance(p, list):
133
+ srcs.extend(p)
134
+ else:
135
+ srcs.append(p)
136
+ n_src = np.unique(srcs).size
137
+ print("Running {0} experiments for {1} unique sources.".format(mat.shape[0], n_src))
124
138
  print('Running methods...')
125
139
  res = decouple([mat, obs.index, var.index], net, verbose=verbose, **decouple_kws)
126
140
 
127
141
  # Compute metrics
128
142
  if verbose:
129
143
  print('Calculating metrics...')
130
- df = get_performances(res, obs, groupby, by, metrics, min_exp=min_exp, pi0=pi0,
131
- n_iter=n_iter, seed=seed, verbose=verbose)
144
+ df = get_performances(res, obs, groupby, by, metrics, use_pval=use_pval, min_exp=min_exp,
145
+ pi0=pi0, n_iter=n_iter, seed=seed, verbose=verbose)
132
146
  if verbose:
133
147
  print('Done.')
134
148
 
135
149
  return df
136
150
 
137
151
 
138
- def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc', 'mcauprc'], groupby=None,
139
- by='experiment', f_expr=True, f_srcs=False, min_exp=5, pi0=0.5, n_iter=1000, seed=42,
140
- verbose=True, use_raw=True, decouple_kws={}):
152
+ def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc', 'mcauprc', 'rank', 'nrank', 'recall'],
153
+ groupby=None, by='experiment', f_expr=True, f_srcs=False, use_pval=None, min_exp=5, pi0=0.5, n_iter=1000,
154
+ seed=42, verbose=True, use_raw=True, decouple_kws={}):
141
155
  """
142
156
  Benchmark methods or networks on a given set of perturbation experiments using activity inference with decoupler.
143
157
 
@@ -156,8 +170,7 @@ def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc'
156
170
  Column name in obs with sign of the perturbation. Can be set to 1 or -1 if all experiments are overexpression or
157
171
  knockouts, respectively.
158
172
  metrics : list, str
159
- Performance metric(s) to compute. See the description of get_performance for more details. Defaults
160
- to ['roc', 'calprc'].
173
+ Performance metric(s) to compute. See the description of get_performance for more details.
161
174
  groupby : list, str, None
162
175
  Performance metrics(s) can be computed per groups if enough experiments are available.
163
176
  by : str
@@ -166,6 +179,9 @@ def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc'
166
179
  Whether to filter out experiments whose perturbed sources are not in the given net. Defaults to True.
167
180
  f_srcs : bool
168
181
  Whether to fitler out sources in net for which there are not perturbation data. Defaults to False.
182
+ use_pval: None, float
183
+ Whether to fitler out activity scores by a given p-value after FDR correction (BH). Defaults to None. Methods that
184
+ generate no p-value will use the (1 - pvalue) quantile based on activity score as being significant.
169
185
  min_exp : int
170
186
  Minimum of perturbation experiments per group.
171
187
  pi0 : float
@@ -211,8 +227,8 @@ def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc'
211
227
  decouple_kws = {**default_kws, **decouple_kws}
212
228
 
213
229
  # Run benchmark
214
- df = _benchmark(mat, obs, net, perturb, sign, metrics, groupby, by, f_expr, f_srcs, min_exp, pi0,
215
- n_iter, seed, verbose, use_raw, decouple_kws)
230
+ df = _benchmark(mat, obs, net, perturb, sign, metrics, groupby, by, f_expr, f_srcs, use_pval, min_exp,
231
+ pi0, n_iter, seed, verbose, use_raw, decouple_kws)
216
232
  else:
217
233
  df = []
218
234
  for net_name in net:
@@ -226,7 +242,7 @@ def benchmark(mat, obs, net, perturb, sign, metrics=['auroc', 'auprc', 'mcauroc'
226
242
 
227
243
  # Run benchmark
228
244
  tmp = _benchmark(mat, obs, net[net_name], perturb, sign, metrics, groupby, by, f_expr, f_srcs,
229
- min_exp, pi0, n_iter, seed, verbose, use_raw, decouple_kws[net_name])
245
+ use_pval, min_exp, pi0, n_iter, seed, verbose, use_raw, decouple_kws[net_name])
230
246
  tmp['net'] = net_name
231
247
  df.append(tmp)
232
248
 
@@ -5,7 +5,7 @@ Code to run methods simultaneously.
5
5
 
6
6
  import decoupler as dc
7
7
  from anndata import AnnData
8
-
8
+ from .utils import show_methods, dense_run
9
9
  from .consensus import cons
10
10
  from .pre import extract
11
11
 
@@ -21,7 +21,7 @@ def get_wrappers(methods):
21
21
  return tmp
22
22
 
23
23
 
24
- def run_methods(mat, net, source, target, weight, methods, args, min_n, verbose, use_raw):
24
+ def run_methods(mat, net, source, target, weight, methods, args, min_n, verbose, use_raw, dense):
25
25
 
26
26
  # Retrieve wrapper functions
27
27
  wrappers = get_wrappers(methods)
@@ -45,10 +45,20 @@ def run_methods(mat, net, source, target, weight, methods, args, min_n, verbose,
45
45
  is_weighted = 'weight' in f.__code__.co_varnames
46
46
 
47
47
  # Run method
48
- if is_weighted:
48
+ if is_weighted and not dense:
49
49
  res = f(mat=mat, net=net, source=source, target=target, weight=weight, **a)
50
- else:
50
+ elif not is_weighted and not dense:
51
51
  res = f(mat=mat, net=net, source=source, target=target, **a)
52
+ else:
53
+ res = dense_run(
54
+ func=f,
55
+ mat=mat,
56
+ net=net,
57
+ source=source,
58
+ target=target,
59
+ weight=weight,
60
+ **a
61
+ )
52
62
 
53
63
  # Extract for AnnData
54
64
  if res is None:
@@ -78,7 +88,7 @@ def parse_methods(methods, cns_metds):
78
88
  cns_metds = ['mlm_estimate', 'ulm_estimate', 'wsum_norm']
79
89
  elif not isinstance(methods, list):
80
90
  if methods.lower() == 'all':
81
- methods = [method.split('run_')[1] for method in dc.show_methods()['Function'] if method != 'run_consensus']
91
+ methods = [method.split('run_')[1] for method in show_methods()['Function'] if method != 'run_consensus']
82
92
  else:
83
93
  methods = [methods]
84
94
 
@@ -86,7 +96,7 @@ def parse_methods(methods, cns_metds):
86
96
 
87
97
 
88
98
  def decouple(mat, net, source='source', target='target', weight='weight', methods=None, args={}, consensus=True,
89
- cns_metds=None, min_n=5, verbose=True, use_raw=True):
99
+ cns_metds=None, min_n=5, verbose=True, use_raw=True, dense=False):
90
100
  """
91
101
  Decouple function.
92
102
 
@@ -120,6 +130,8 @@ def decouple(mat, net, source='source', target='target', weight='weight', method
120
130
  Whether to show progress.
121
131
  use_raw : bool
122
132
  If mat is AnnData, use its raw attribute.
133
+ dense : bool
134
+ Whether to run methods ignoring zero values per observation. See ``decoupler.dense_run`` for more information.
123
135
 
124
136
  Returns
125
137
  -------
@@ -138,7 +150,7 @@ def decouple(mat, net, source='source', target='target', weight='weight', method
138
150
  print('Method name {0} in args not found in methods, will be ignored.'.format(methd))
139
151
 
140
152
  # Run methods
141
- results = run_methods(mat, net, source, target, weight, methods, args, min_n, verbose, use_raw)
153
+ results = run_methods(mat, net, source, target, weight, methods, args, min_n, verbose, use_raw, dense)
142
154
 
143
155
  # Run consensus score
144
156
  if consensus:
@@ -161,7 +173,7 @@ def decouple(mat, net, source='source', target='target', weight='weight', method
161
173
  return results
162
174
 
163
175
 
164
- def run_consensus(mat, net, source='source', target='target', weight='weight', min_n=5, verbose=False, use_raw=True):
176
+ def run_consensus(mat, net, source='source', target='target', weight='weight', min_n=5, verbose=False, use_raw=True, args={}):
165
177
  """
166
178
  Consensus score from top methods.
167
179
 
@@ -192,6 +204,8 @@ def run_consensus(mat, net, source='source', target='target', weight='weight', m
192
204
  Whether to show progress.
193
205
  use_raw : bool
194
206
  Use raw attribute of mat if present.
207
+ args : dict
208
+ Parameters for the ``decoupler.decouple`` function.
195
209
 
196
210
  Returns
197
211
  -------
@@ -209,7 +223,7 @@ def run_consensus(mat, net, source='source', target='target', weight='weight', m
209
223
 
210
224
  # Run top methods
211
225
  res = decouple(mat=[m, r, c], net=net, source=source, target=target, weight=weight,
212
- min_n=min_n, verbose=verbose, use_raw=use_raw)
226
+ min_n=min_n, verbose=verbose, use_raw=use_raw, args=args)
213
227
 
214
228
  # Exctract
215
229
  estimate, pvals = res['consensus_estimate'], res['consensus_pvals']
@@ -5,75 +5,75 @@ Code to run the AUCell method.
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
8
+ from scipy.sparse import csr_matrix
8
9
 
9
- from numpy.random import default_rng
10
+ from tqdm.auto import tqdm
10
11
 
11
- from .pre import extract, rename_net, filt_min_n
12
+ from .pre import extract, rename_net, filt_min_n, return_data, break_ties
12
13
 
13
- from anndata import AnnData
14
14
  import numba as nb
15
15
 
16
16
 
17
- @nb.njit(nb.f4[:, :](nb.i8, nb.i8, nb.f4[:], nb.i8[:], nb.i8[:], nb.i8[:], nb.i8[:], nb.i8), parallel=True, cache=True)
18
- def nb_aucell(n_samples, n_features, data, indptr, indices, net, offsets, n_up):
17
+ @nb.njit(nb.f4[:](nb.f4[:], nb.i8[:], nb.i8[:], nb.i8[:], nb.i8, nb.i8), parallel=True, cache=True)
18
+ def nb_aucell(row, net, starts, offsets, n_up, n_fsets):
19
19
 
20
- # Number of feature sets
21
- n_fsets = offsets.shape[0]
22
-
23
- # Define starts to subset offsets
24
- starts = np.zeros(n_fsets, dtype=nb.i8)
25
- starts[1:] = np.cumsum(offsets)[:-1]
20
+ # Rank row
21
+ row = np.argsort(np.argsort(-row)) + 1
26
22
 
27
23
  # Empty acts
28
- acts = np.zeros((n_samples, n_fsets), dtype=nb.f4)
24
+ es = np.zeros(n_fsets, dtype=nb.f4)
29
25
 
30
- # For each sample
31
- for i in nb.prange(n_samples):
26
+ # For each feature set
27
+ for j in nb.prange(n_fsets):
32
28
 
33
- # Extract sample from sparse matrix
34
- row = np.zeros(n_features, dtype=nb.f4)
35
- s, e = indptr[i], indptr[i+1]
36
- row[indices[s:e]] = data[s:e]
29
+ # Extract feature set
30
+ srt = starts[j]
31
+ off = offsets[j] + srt
32
+ fset = net[srt:off]
37
33
 
38
- # Rank row
39
- row = np.argsort(np.argsort(-row)) + 1
34
+ # Compute max AUC for fset
35
+ x_th = np.arange(1, stop=fset.shape[0]+1, dtype=nb.i8)
36
+ x_th = x_th[x_th < n_up]
37
+ max_auc = np.sum(np.diff(np.append(x_th, n_up)) * x_th)
40
38
 
41
- # For each feature set
42
- for j in range(n_fsets):
39
+ # Compute AUC
40
+ x = row[fset]
41
+ x = np.sort(x[x < n_up])
42
+ y = np.arange(x.shape[0]) + 1
43
+ x = np.append(x, n_up)
43
44
 
44
- # Extract feature set
45
- srt = starts[j]
46
- off = offsets[j] + srt
47
- fset = net[srt:off]
45
+ # Update acts matrix
46
+ es[j] = np.sum(np.diff(x) * y) / max_auc
48
47
 
49
- # Compute max AUC for fset
50
- x_th = np.arange(start=1, stop=fset.shape[0]+1, dtype=nb.i8)
51
- x_th = x_th[x_th < n_up]
52
- max_auc = np.sum(np.diff(np.append(x_th, n_up)) * x_th)
48
+ return es
53
49
 
54
- # Compute AUC
55
- x = row[fset]
56
- x = np.sort(x[x < n_up])
57
- y = np.arange(x.shape[0]) + 1
58
- x = np.append(x, n_up)
59
50
 
60
- # Update acts matrix
61
- acts[i, j] = np.sum(np.diff(x) * y)/max_auc
51
+ def aucell(mat, net, n_up, verbose):
62
52
 
63
- return acts
64
-
65
-
66
- def aucell(mat, net, n_up):
53
+ # Get dims
54
+ n_samples = mat.shape[0]
55
+ n_fsets = net.shape[0]
67
56
 
68
57
  # Flatten net and get offsets
69
58
  offsets = net.apply(lambda x: len(x)).values.astype(np.int64)
70
59
  net = np.concatenate(net.values)
71
60
 
72
- # Compute AUC per fset
73
- acts = nb_aucell(mat.shape[0], mat.shape[1], mat.data, mat.indptr.astype(np.int64),
74
- mat.indices.astype(np.int64), net, offsets, n_up)
61
+ # Define starts to subset offsets
62
+ starts = np.zeros(n_fsets, dtype=np.int64)
63
+ starts[1:] = np.cumsum(offsets)[:-1]
64
+
65
+ es = np.zeros((n_samples, n_fsets), dtype=np.float32)
66
+ for i in tqdm(range(mat.shape[0]), disable=not verbose):
67
+
68
+ if isinstance(mat, csr_matrix):
69
+ row = mat[i].toarray()[0]
70
+ else:
71
+ row = mat[i]
75
72
 
76
- return acts
73
+ # Compute AUC per row
74
+ es[i] = nb_aucell(row, net, starts, offsets, n_up, n_fsets)
75
+
76
+ return es
77
77
 
78
78
 
79
79
  def run_aucell(mat, net, source='source', target='target', n_up=None, min_n=5, seed=42, verbose=False, use_raw=True):
@@ -119,9 +119,10 @@ def run_aucell(mat, net, source='source', target='target', n_up=None, min_n=5, s
119
119
 
120
120
  # Set n_up
121
121
  if n_up is None:
122
- n_up = np.ceil(0.05*len(c))
122
+ n_up = int(np.ceil(0.05*len(c)))
123
123
  else:
124
- n_up = np.ceil(n_up)
124
+ n_up = int(np.ceil(n_up))
125
+ n_up = np.min([n_up, c.size]) # Limit n_up to max features
125
126
  if not 0 < n_up:
126
127
  raise ValueError('n_up needs to be a value higher than 0.')
127
128
 
@@ -130,27 +131,19 @@ def run_aucell(mat, net, source='source', target='target', n_up=None, min_n=5, s
130
131
  net = filt_min_n(c, net, min_n=min_n)
131
132
 
132
133
  # Randomize feature order to break ties randomly
133
- rng = default_rng(seed=seed)
134
- idx = np.arange(m.shape[1])
135
- rng.shuffle(idx)
136
- m, c = m[:, idx], c[idx]
134
+ m, c = break_ties(m, c, seed)
137
135
 
138
136
  # Transform targets to indxs
139
137
  table = {name: i for i, name in enumerate(c)}
140
138
  net['target'] = [table[target] for target in net['target']]
141
- net = net.groupby('source')['target'].apply(lambda x: np.array(x, dtype=np.int64))
139
+ net = net.groupby('source', observed=True)['target'].apply(lambda x: np.array(x, dtype=np.int64))
142
140
 
143
141
  if verbose:
144
142
  print('Running aucell on mat with {0} samples and {1} targets for {2} sources.'.format(m.shape[0], len(c), len(net)))
145
143
 
146
144
  # Run AUCell
147
- estimate = aucell(m, net, n_up)
145
+ estimate = aucell(m, net, n_up, verbose)
148
146
  estimate = pd.DataFrame(estimate, index=r, columns=net.index)
149
147
  estimate.name = 'aucell_estimate'
150
148
 
151
- # AnnData support
152
- if isinstance(mat, AnnData):
153
- # Update obsm AnnData object
154
- mat.obsm[estimate.name] = estimate
155
- else:
156
- return estimate
149
+ return return_data(mat=mat, results=(estimate, ))