@@ -21,6 +21,9 @@ class FastKCI_CInd(object):
2121 "A kernel-based conditional independence test and application in causal discovery", In UAI 2011.
2222 [2] M. Zhang, and S. Williamson,
2323 "Embarrassingly Parallel Inference for Gaussian Processes", In JMLR 20 (2019)
24+ [3] O. Schacht, and B. Huang
25+ "FastKCI: A fast Kernel-based Conditional Indepdence test with application to causal discovery",
26+ Working Paper.
2427
2528 """
2629 def __init__ (self , K = 10 , J = 8 , alpha = 500 , epsilon = 1e-3 , eig_thresh = 1e-6 , trimming_thresh = 1e-3 , use_gp = False ):
@@ -65,21 +68,17 @@ def compute_pvalue(self, data_x=None, data_y=None, data_z=None):
6568 self .n = data_x .shape [0 ]
6669
6770 Z_proposal = Parallel (n_jobs = - 1 )(delayed (self .partition_data )() for i in range (self .J ))
68- self .Z_proposal , self . prob_Z = zip (* Z_proposal )
71+ self .Z_proposal = zip (* Z_proposal )
6972 block_res = Parallel (n_jobs = - 1 )(delayed (self .pvalue_onblocks )(self .Z_proposal [i ]) for i in range (self .J ))
7073 test_stat , null_samples , log_likelihood = zip (* block_res )
7174
7275 log_likelihood = np .array (log_likelihood )
73- self .prob_Z += log_likelihood
74- self .prob_Z = np .around (np .exp (self .prob_Z - logsumexp (self .prob_Z )), 6 ) # experimental, not used
7576 self .all_null_samples = np .vstack (null_samples )
7677 self .all_p = np .array ([np .sum (self .all_null_samples [i ,] > test_stat [i ]) / float (self .nullss ) for i in range (self .J )])
7778 self .prob_weights = np .around (np .exp (log_likelihood - logsumexp (log_likelihood )), 6 )
7879 self .all_test_stats = np .array (test_stat )
7980 self .test_stat = np .average (np .array (test_stat ), weights = self .prob_weights )
8081 self .null_samples = np .average (null_samples , axis = 0 , weights = self .prob_weights )
81- # experimental, not used
82- self .pvalue_alt = np .sum (np .average (null_samples , axis = 0 , weights = self .prob_Z ) > np .average (np .array (test_stat ), weights = self .prob_Z )) / float (self .nullss )
8382 self .pvalue = np .sum (self .null_samples > self .test_stat ) / float (self .nullss )
8483
8584 return self .pvalue , self .test_stat
@@ -104,8 +103,7 @@ def partition_data(self):
104103 Z = np .array ([np .random .multinomial (1 , np .exp (ll [n , :]- logsumexp (ll [n , :]))).argmax () for n in range (self .n )])
105104 le = LabelEncoder ()
106105 Z = le .fit_transform (Z )
107- prob_Z = np .take_along_axis (ll , Z [:, None ], axis = 1 ).sum () # experimental, might be removed
108- return Z , prob_Z
106+ return Z
109107
110108 def pvalue_onblocks (self , Z_proposal ):
111109 """
@@ -130,7 +128,7 @@ def pvalue_onblocks(self, Z_proposal):
130128 X_k = np .copy (self .data [0 ][K_mask ])
131129 Y_k = np .copy (self .data [1 ][K_mask ])
132130 Z_k = np .copy (self .data_z [K_mask ])
133- if (Z_k .shape [0 ] < 6 ): # small blocks cause problems in GP, experimental
131+ if (Z_k .shape [0 ] < 6 ): # small blocks cause problems in GP
134132 continue
135133 Kx , Ky , Kzx , Kzy , epsilon_x , epsilon_y , likelihood_x , likelihood_y = self .kernel_matrix (X_k , Y_k , Z_k )
136134 KxR , Rzx = Kernel .center_kernel_matrix_regression (Kx , Kzx , epsilon_x )
@@ -214,7 +212,8 @@ def kernel_matrix(self, data_x, data_y, data_z):
214212 vx = vx [:, np .abs (wx ) > np .abs (wx ).max () * 1e-10 ]
215213 wx = wx [np .abs (wx ) > np .abs (wx ).max () * 1e-10 ]
216214 vx = 2 * np .sqrt (n ) * vx .dot (np .diag (np .sqrt (wx ))) / np .sqrt (wx [0 ])
217- kernelx = ConstantKernel (1.0 , (1e-3 , 1e3 )) * RBF (widthz * np .ones (Dz ), (1e-2 , 1e2 )) + WhiteKernel (0.1 , (1e-10 , 1e+1 ))
215+ kernelx = ConstantKernel (1.0 , (1e-3 , 1e3 )) * RBF (widthz * np .ones (Dz ), (1e-2 , 1e2 )) \
216+ + WhiteKernel (0.1 , (1e-10 , 1e+1 ))
218217 gpx = GaussianProcessRegressor (kernel = kernelx )
219218 # fit Gaussian process, including hyperparameter optimization
220219 with warnings .catch_warnings ():
@@ -237,7 +236,8 @@ def kernel_matrix(self, data_x, data_y, data_z):
237236 vy = vy [:, np .abs (wy ) > np .abs (wy ).max () * 1e-10 ]
238237 wy = wy [np .abs (wy ) > np .abs (wy ).max () * 1e-10 ]
239238 vy = 2 * np .sqrt (n ) * vy .dot (np .diag (np .sqrt (wy ))) / np .sqrt (wy [0 ])
240- kernely = ConstantKernel (1.0 , (1e-3 , 1e3 )) * RBF (widthz * np .ones (Dz ), (1e-2 , 1e2 )) + WhiteKernel (0.1 , (1e-10 , 1e+1 ))
239+ kernely = ConstantKernel (1.0 , (1e-3 , 1e3 )) * RBF (widthz * np .ones (Dz ), (1e-2 , 1e2 )) \
240+ + WhiteKernel (0.1 , (1e-10 , 1e+1 ))
241241 gpy = GaussianProcessRegressor (kernel = kernely )
242242 # fit Gaussian process, including hyperparameter optimization
243243 with warnings .catch_warnings ():
@@ -341,14 +341,18 @@ def null_sample_spectral(self, uu_prod, size_u, T):
341341
342342class FastKCI_UInd (object ):
343343 """
344- Python implementation of as speed-up version of the Kernel-based Conditional Independence (KCI) test. Unconditional version.
344+ Python implementation of as speed-up version of the Kernel-based Conditional Independence (KCI) test.
345+ Unconditional version.
345346
346347 References
347348 ----------
348349 [1] K. Zhang, J. Peters, D. Janzing, and B. Schölkopf,
349350 "A kernel-based conditional independence test and application in causal discovery," In UAI 2011.
350351 [2] M. Zhang, and S. Williamson,
351352 "Embarrassingly Parallel Inference for Gaussian Processes" In JMLR 20 (2019)
353+ [3] O. Schacht, and B. Huang
354+ "FastKCI: A fast Kernel-based Conditional Indepdence test with application to causal discovery",
355+ Working Paper.
352356 """
353357 def __init__ (self , K = 10 , J = 8 , alpha = 500 , trimming_thresh = 1e-3 ):
354358 """
0 commit comments