Source code for acore.multiple_testing

import numpy as np
import pandas as pd
import pingouin as pg
from scipy.special import factorial
from sklearn.utils import shuffle
from statsmodels.stats import multitest

# ? dictionary with available methods in statsmodels.stats.multitest.multipletests:
# multitest.multitest_methods_names


[docs] def apply_pvalue_correction( pvalues: np.ndarray, alpha: float = 0.05, method: str = "bonferroni" ) -> tuple[np.ndarray, np.ndarray]: """ Performs p-value correction using the specified method as in statsmodels.stats.multitest.multipletests_. .. _statsmodels.stats.multitest.multipletests: \ https://www.statsmodels.org/dev/generated/statsmodels.stats.multitest.multipletests.html :param numpy.ndarray pvalues: et of p-values of the individual tests. :param float alpha: error rate. :param str method: method of p-value correction: - 'bonferroni' : one-step correction - 'sidak' : one-step correction - 'holm-sidak' : step down method using Sidak adjustments - 'holm' : step-down method using Bonferroni adjustments - 'simes-hochberg' : step-up method (independent) - 'hommel' : closed method based on Simes tests (non-negative) - 'fdr_bh' : Benjamini/Hochberg (non-negative) - 'fdr_by' : Benjamini/Yekutieli (negative) - 'fdr_tsbh' : two stage fdr correction (non-negative) - 'fdr_tsbky' : two stage fdr correction (non-negative) :return: Tuple with two `numpy.array`s, boolen for rejecting H0 hypothesis and float for adjusted p-value. Can contain missing values if `pvalues` contain missing values. Example:: result = apply_pvalue_correction(pvalues, alpha=0.05, method='bonferroni') """ p = np.array(pvalues) mask = np.isfinite(p) pval_corrected = np.full(p.shape, np.nan) _rejected, _pvals_corrected, _, _ = multitest.multipletests(p[mask], alpha, method) pval_corrected[mask] = _pvals_corrected rejected = np.full(p.shape, np.nan) rejected[mask] = _rejected return (rejected, pval_corrected)
[docs] def apply_pvalue_fdrcorrection(pvalues, alpha=0.05, method="indep"): """ Performs p-value correction for false discovery rate. For more information visit https://www.statsmodels.org/devel/generated/statsmodels.stats.multitest.fdrcorrection.html. :param numpy.ndarray pvalues: et of p-values of the individual tests. :param float alpha: error rate. :param str method: method of p-value correction ('indep', 'negcorr'). :return: Tuple with two arrays, boolen for rejecting H0 hypothesis and float for adjusted p-value. Example:: result = apply_pvalue_fdrcorrection(pvalues, alpha=0.05, method='indep') """ rejected, padj = multitest.fdrcorrection(pvalues, alpha, method) return (rejected, padj)
[docs] def apply_pvalue_twostage_fdrcorrection(pvalues, alpha=0.05, method="bh"): """ Iterated two stage linear step-up procedure with estimation of number of true hypotheses. For more information visit https://www.statsmodels.org/dev/generated/statsmodels.stats.multitest.fdrcorrection_twostage.html. :param numpy.ndarray pvalues: et of p-values of the individual tests. :param float alpha: error rate. :param str method: method of p-value correction ('bky', 'bh'). :return: Tuple with two arrays, boolen for rejecting H0 hypothesis and float for adjusted p-value. Example:: result = apply_pvalue_twostage_fdrcorrection(pvalues, alpha=0.05, method='bh') """ rejected, padj, num_hyp, alpha_stages = multitest.fdrcorrection_twostage( pvalues, alpha, method ) return (rejected, padj)
[docs] def apply_pvalue_permutation_fdrcorrection( df, observed_pvalues, group, alpha=0.05, permutations=50 ): """ This function applies multiple hypothesis testing correction using a permutation-based false discovery rate approach. :param df: pandas dataframe with samples as rows and features as columns. :param oberved_pvalues: pandas Series with p-values calculated on the originally measured data. :param str group: name of the column containing group identifiers. :param float alpha: error rate. Values velow alpha are considered significant. :param int permutations: number of permutations to be applied. :return: Pandas dataframe with adjusted p-values and rejected columns. Example:: result = apply_pvalue_permutation_fdrcorrection(df, observed_pvalues, group='group', alpha=0.05, permutations=50) """ i = permutations df_index = df.index.values df_columns = df.columns.values seen = [str([df_index] + df_columns.tolist())] rand_pvalues = [] while i > 0: df_index = shuffle(df_index) df_columns = shuffle(df_columns) df_random = df.reset_index(drop=True) df_random.index = df_index df_random.index.name = group df_random.columns = df_columns rand_index = str([df_random.index] + df_columns.tolist()) if rand_index not in seen: seen.append(rand_index) df_random = df_random.reset_index() for col in df_random.columns.drop(group): rand_pvalues.append( calculate_anova(df_random, column=col, group=group)[-1] ) i -= 1 rand_pvalues = np.array(rand_pvalues) qvalues = [] for i, row in observed_pvalues.to_frame(): qvalues.append( get_counts_permutation_fdr( row["pvalue"], rand_pvalues, df["pvalue"], permutations, alpha ) + (i,) ) qvalues = pd.DataFrame( qvalues, columns=["padj", "rejected", "identifier"] ).set_index("identifier") return qvalues
[docs] def calculate_anova(df, column, group="group"): """ Calculates one-way ANOVA using pingouin. :param df: pandas dataframe with group as rows and protein identifier as column :param str column: name of the column in df to run ANOVA on :param str group: column with group identifiers :return: Tuple with t-statistics and p-value. """ aov_result = pg.anova(data=df, dv=column, between=group) df1, df2, t, pvalue = aov_result[["ddof1", "ddof2", "F", "p-unc"]].values.tolist()[ 0 ] return (column, df1, df2, t, pvalue)
[docs] def get_counts_permutation_fdr(value, random, observed, n, alpha): """ Calculates local FDR values (q-values) by computing the fraction of accepted hits from the permuted data over accepted hits from the measured data normalized by the total number of permutations. :param float value: computed p-value on measured data for a feature. :param numpy.ndarray random: p-values computed on the permuted data. :param observed: pandas Series with p-values calculated on the originally measured data. :param int n: number of permutations to be applied. :param float alpha: error rate. Values velow alpha are considered significant. :return: Tuple with q-value and boolean for H0 rejected. Example:: result = get_counts_permutation_fdr(value, random, observed, n=250, alpha=0.05) """ a = random[random <= value].shape[0] + 0.0000000000001 # Offset in case of a = 0.0 b = (observed <= value).sum() qvalue = a / b / float(n) return (qvalue, qvalue <= alpha)
[docs] def get_max_permutations(df, group="group"): """ Get maximum number of permutations according to number of samples. :param df: pandas dataframe with samples as rows and protein identifiers as columns :param str group: column with group identifiers :return: Maximum number of permutations. :rtype: int """ num_groups = len(list(df.index)) num_per_group = df.groupby(group).size().tolist() max_perm = factorial(num_groups) / np.prod(factorial(np.array(num_per_group))) return max_perm
[docs] def correct_pairwise_ttest(df, alpha, correction="fdr_bh"): posthoc_df = list() required_col = ["group1", "group2", "posthoc pvalue"] for _col in required_col: if _col not in df: raise KeyError(f"Did not find '{_col}' in columns of data.") for comparison in df.groupby(["group1", "group2"]).groups: index = df.groupby(["group1", "group2"]).groups.get(comparison) posthoc_pvalues = df.loc[index, "posthoc pvalue"].tolist() _, posthoc_padj = apply_pvalue_correction( posthoc_pvalues, alpha=alpha, method=correction ) _posthoc_df = pd.DataFrame({"index": index, "posthoc padj": posthoc_padj}) posthoc_df.append(_posthoc_df) posthoc_df = pd.concat(posthoc_df) posthoc_df = posthoc_df.set_index("index") df = df.join(posthoc_df) return df