Tutorial: a first conditional-independence call¶
This tutorial walks through one full conditional-independence
calculation using citk, then plugs the same test into a
constraint-based discovery algorithm via the cross-package
cbcd.CITest Protocol. The reader is assumed to know what
conditional independence is and what role it plays in causal
discovery; for a primer see
Explanation: what is conditional independence.
A direct CI call¶
Every test in citk exposes the same three-member surface:
n_vars: int, __call__(X, Y, S), and details(X, Y, S). Construct
the test once with the data array, then query as many CI relations
as you need:
import numpy as np
from citk.tests.partial_correlation_tests import FisherZ
# X and Y are independent given Z under the chain X → Z → Y.
n = 500
X = np.random.randn(n)
Z = 2 * X + np.random.randn(n)
Y = 3 * Z + np.random.randn(n)
data = np.vstack([X, Y, Z]).T # columns: X, Y, Z
test = FisherZ(data)
p = test(0, 1, [2]) # X ⫫ Y | Z
print(f"p(X ⫫ Y | Z) = {p:.4f}") # large — fail to reject independence
p_marg = test(0, 1, []) # marginally not independent
print(f"p(X ⫫ Y) = {p_marg:.4f}") # small — reject independence
The conditioning set is passed positionally as a list of integer indices into the data columns. Returned values are p-values; the caller is responsible for thresholding (typically against an \(\alpha\) on the order of \(0.05\)).
For richer diagnostics — the test statistic, degrees of freedom,
effective sample size — call test.details(X, Y, S), which returns
a CITKResult value object.
Plugging citk into cbcd¶
Because every citk test satisfies the structural cbcd.CITest
Protocol, any constraint-based algorithm in the sister package
cbcd accepts a citk test
directly:
from cbcd import pc
from citk.tests.partial_correlation_tests import FisherZ
cpdag = pc(data, ci_test=FisherZ(data), alpha=0.05)
No adapter or wrapping is required. The Protocol contract is
verified at runtime — isinstance(FisherZ(data), cbcd.citest.CITest)
returns True — but the duck-typed dispatch needs no inheritance,
so neither package imports the other.
See also
The full four-package end-to-end story (data simulation through
metric scoring) is in the suite tutorial at
suite/docs/tutorial.md.
Choosing a different test¶
Switch to any other test by changing the import:
from citk.tests.partial_correlation_tests import Spearman # rank-based
from citk.tests.kernel_tests import KCI # non-parametric
from citk.tests.nearest_neighbor_tests import CMIknn # k-NN CMI
from citk.tests.regression_tests import RegressionCI # mixed-type
A practical mapping from data type and modelling assumption to test choice is given in How-to: choosing a CI test. The deeper theory — what makes each family of tests valid under which assumptions — is in Explanation: taxonomy of CI tests.
What is next¶
Per-test deep dives — every test has a dedicated page with Mathematical Formulation, Assumptions, and Code Example sections. Start at the Tests index.
The Protocol contract — Explanation: API stability.
Custom tests — implement the
CITKTestinterface and the test slots into both thecitkcache machinery andcbcd’s algorithm dispatch.