Last active
June 27, 2020 18:15
-
-
Save ryananeff/c66cdf086979b13e855f2c3d0f3e54e1 to your computer and use it in GitHub Desktop.
[Python] ACAT test for combining p-values under the Cauchy distribution, inspired by ACAT R package (yaowuliu/ACAT)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import scipy as sp | |
def acat_test(pvalues,weights=None): | |
'''acat_test() | |
Aggregated Cauchy Assocaition Test | |
A p-value combination method using the Cauchy distribution. | |
Inspired by: https://github.com/yaowuliu/ACAT/blob/master/R/ACAT.R | |
Author: Ryan Neff | |
Inputs: | |
pvalues: <list or numpy array> | |
The p-values you want to combine. | |
weights: <list or numpy array>, default=None | |
The weights for each of the p-values. If None, equal weights are used. | |
Returns: | |
pval: <float> | |
The ACAT combined p-value. | |
''' | |
if any(np.isnan(pvalues)): | |
raise Exception("Cannot have NAs in the p-values.") | |
if any([(i>1)|(i<0) for i in pvalues]): | |
raise Exception("P-values must be between 0 and 1.") | |
if any([i==1 for i in pvalues])&any([i==0 for i in pvalues]): | |
raise Exception("Cannot have both 0 and 1 p-values.") | |
if any([i==0 for i in pvalues]): | |
print("Warn: p-values are exactly 0.") | |
return 0 | |
if any([i==1 for i in pvalues]): | |
print("Warn: p-values are exactly 1.") | |
return 1 | |
if weights==None: | |
weights = [1/len(pvalues) for i in pvalues] | |
elif len(weights)!=len(pvalues): | |
raise Exception("Length of weights and p-values differs.") | |
elif any([i<0 for i in weights]): | |
raise Exception("All weights must be positive.") | |
else: | |
weights = [i/len(weights) for i in weights] | |
pvalues = np.array(pvalues) | |
weights = np.array(weights) | |
if any([i<1e-16 for i in pvalues])==False: | |
cct_stat = sum(weights*np.tan((0.5-pvalues)*np.pi)) | |
else: | |
is_small = [i<(1e-16) for i in pvalues] | |
is_large = [i>=(1e-16) for i in pvalues] | |
cct_stat = sum((weights[is_small]/pvalues[is_small])/np.pi) | |
cct_stat += sum(weights[is_large]*np.tan((0.5-pvalues[is_large])*np.pi)) | |
if cct_stat>1e15: | |
pval = (1/cct_stat)/np.pi | |
else: | |
pval = 1 - sp.stats.cauchy.cdf(cct_stat) | |
return pval |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment