@@ -181,9 +181,100 @@ def _func_viper(
181181 penalty : int | float = 20 ,
182182 verbose : bool = False ,
183183) -> Tuple [np .ndarray , np .ndarray ]:
184- """
184+ r """
185185 Virtual Inference of Protein-activity by Enriched Regulon analysis (VIPER) :cite:`viper`.
186186
187+ This approach first ranks features based on their absolute values and computes a one-tail score.
188+
189+ .. math::
190+
191+ \begin{align}
192+ w &= \frac{w}{max(|w|)} \\
193+ l_{orig} &= 1_{w \neq 0} \\
194+ l &= \frac{l_{orig}}{\sum_{i=1}^{k} \frac{l_i}{max(l_{orig})}max(l_{orig})} \\
195+ q^{norm} &= \Phi^{-1}(2|q-0.5| + (1 + max(|q-0.5|))) \\
196+ S_1 &= \sum_{i=1}^{k}q_i^{norm}l_i(1-|w_i|) \\
197+ \end{align}
198+
199+ Where:
200+
201+ - :math:`w \in [-1, +1]` is a vector of interaction weights across features
202+ - :math:`l \in [0, 1]` is a vector of interaction likelihoods across features
203+ - :math:`q \in [0, 1]` is a vector of quantiles based on the molecular readouts across features
204+ - :math:`k` is the number of features in :math:`q`
205+ - :math:`\Phi^{-1}` is is the inverse of the cumulative distribution function of the standard normal distribution
206+ - :math:`q^{norm} \in [-\infty,+\infty]` are the z-scores of the deviation of quantiles from 0.5
207+
208+ :math:`S_1` encodes for the magnitude of the enrichment score, irrespective of the interaction signs in ``net``.
209+
210+ Then, :math:`q` are z-transformed and weighted by their interaction strength and likelihood.
211+
212+ .. math::
213+
214+ S_2 = \sum_{i=1}^{k}w_il_i(\Phi^{-1}(q_i))
215+
216+ In this case, :math:`S_2` takes the direction (sign) of interactions into consideration.
217+
218+ Afterwards, a summary score :math:`S_3` is obtained.
219+
220+ .. math::
221+
222+ S_3 =
223+ \begin{cases}
224+ (|S_2| + S_1) \times \mathrm{sgn}(S_2) & \text{if } S_1 > 0 \\
225+ S_2 & \text{if } S_1 < 0
226+ \end{cases}
227+
228+ An enrichment score :math:`ES` is obtained by comparing :math:`S_3` to a
229+ null model generated through an analytical approach that shuffles features.
230+
231+ .. math::
232+
233+ ES = S_3\sqrt{\sum_{i=1}^{k}l_{orig,i}^{2}}
234+
235+ Together with a :math:`p_{value}`
236+
237+ .. math::
238+
239+ p_{value} = \Phi(ES)
240+
241+ Additionaly, computing multiple sources simultaneously, a pleiotropic correction is employed.
242+
243+ In brief, all possible pairs of sources AB are generated under two conditions:
244+
245+ 1. both A and B are significantly enriched (p < ``reg_sign=0.05``)
246+ 2. they share at least ``n_targets=10`` features
247+
248+ Subsequently, a :math:`ES` and its associated :math:`p_{value}` is computed for
249+ both A (:math:`pA`) and B (:math:`pB`) based only on the shared features.
250+ Then the pleiotropy score (:math:`PS`) is computed.
251+
252+ .. math::
253+
254+ PS =
255+ \begin{cases}
256+ \frac{1}{(1+|\log_{10}(pB) - \log_{10}(pA)|)^{\frac{20}{n_a}}} \text{ if } pA < pB \\
257+ \frac{1}{(1+|\log_{10}(pA) - \log_{10}(pB)|)^{\frac{20}{n_b}}} \text{ if } pA > pB
258+ \end{cases}
259+
260+ Where:
261+
262+ - :math:`n_a` is the number of test pairs involving the source A
263+ - :math:`n_b` is the number of test pairs involving the source B
264+
265+ This score is used to update :math:`l_{orig}`.
266+
267+ .. math::
268+
269+ l_{orig, i} =
270+ \begin{cases}
271+ PS \times 1_{\{i \in A\}} \text{ if } pA < pB \\
272+ PS \times 1_{\{i \in B\}} \text{ if } pA > pB
273+ \end{cases}
274+
275+ A new :math:`ES` and :math:`p_{value}` are calculated following all
276+ the previous steps but using the updated :math:`l_{orig}`
277+
187278 %(yestest)s
188279
189280 %(params)s
0 commit comments