# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np def _ecdf(x): """No frills empirical cdf used in fdrcorrection.""" nobs = len(x) return np.arange(1, nobs + 1) / float(nobs) def fdr_correction(pvals, alpha=0.05, method="indep"): """P-value correction with False Discovery Rate (FDR). Correction for multiple comparison using FDR :footcite:`GenoveseEtAl2002`. This covers Benjamini/Hochberg for independent or positively correlated and Benjamini/Yekutieli for general or negatively correlated tests. Parameters ---------- pvals : array_like Set of p-values of the individual tests. alpha : float Error rate. method : 'indep' | 'negcorr' If 'indep' it implements Benjamini/Hochberg for independent or if 'negcorr' it corresponds to Benjamini/Yekutieli. Returns ------- reject : array, bool True if a hypothesis is rejected, False if not. pval_corrected : array P-values adjusted for multiple hypothesis testing to limit FDR. References ---------- .. footbibliography:: """ pvals = np.asarray(pvals) shape_init = pvals.shape pvals = pvals.ravel() pvals_sortind = np.argsort(pvals) pvals_sorted = pvals[pvals_sortind] sortrevind = pvals_sortind.argsort() if method in ["i", "indep", "p", "poscorr"]: ecdffactor = _ecdf(pvals_sorted) elif method in ["n", "negcorr"]: cm = np.sum(1.0 / np.arange(1, len(pvals_sorted) + 1)) ecdffactor = _ecdf(pvals_sorted) / cm else: raise ValueError("Method should be 'indep' and 'negcorr'") reject = pvals_sorted < (ecdffactor * alpha) if reject.any(): rejectmax = max(np.nonzero(reject)[0]) else: rejectmax = 0 reject[:rejectmax] = True pvals_corrected_raw = pvals_sorted / ecdffactor pvals_corrected = np.minimum.accumulate(pvals_corrected_raw[::-1])[::-1] pvals_corrected[pvals_corrected > 1.0] = 1.0 pvals_corrected = pvals_corrected[sortrevind].reshape(shape_init) reject = reject[sortrevind].reshape(shape_init) return reject, pvals_corrected def bonferroni_correction(pval, alpha=0.05): """P-value correction with Bonferroni method. Parameters ---------- pval : array_like Set of p-values of the individual tests. alpha : float Error rate. Returns ------- reject : array, bool True if a hypothesis is rejected, False if not. pval_corrected : array P-values adjusted for multiple hypothesis testing to limit FDR. """ pval = np.asarray(pval) pval_corrected = pval * float(pval.size) # p-values must not be larger than 1. pval_corrected = pval_corrected.clip(max=1.0) reject = pval_corrected < alpha return reject, pval_corrected