Skip to content

Instantly share code, notes, and snippets.

@ryananeff
Last active June 27, 2020 18:15
Show Gist options
  • Save ryananeff/c66cdf086979b13e855f2c3d0f3e54e1 to your computer and use it in GitHub Desktop.
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)
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