andrey.lpcmci#
- andrey.lpcmci(data, *, tau_max=1, pc_alpha=0.05, n_preliminary_iterations=1, indep_test='student_t')[source]#
Learn a time-series partial ancestral graph that allows hidden common causes with LPCMCI.
LPCMCI [1] finds the lagged and same-step links of one multivariate time series when some variables that drive several observed ones are not measured. Like FCI it returns a partial ancestral graph: an arrowhead says an end is not a cause of the other, a tail that it is, and a circle leaves it open, so a link with arrowheads at both ends is a hidden common cause. It orients links while it removes them and conditions every test on the parents found so far, which keeps true links in strongly autocorrelated series. Use it on one series when an unmeasured variable may confound the measured ones.
- Parameters:
data (
ArrayLike) – A multivariate time series, one row per time step. Coerced tofloat64. A DataFrame’s column names become the structure’slabels.tau_max (
int) – The largest lag, at least1: the graph covers the time stepst - tau_maxtot, and links at lags0totau_maxare tested.pc_alpha (
float) – Significance level of every test, in(0, 1): a link is removed when a test gives it a p-value abovepc_alpha.n_preliminary_iterations (
int) – How many preliminary rounds run before the final one, at least0. Each round learns parents that the next one conditions on from its first test.indep_test (
str) – The partial-correlation test behind every p-value. Both report the same partial correlation;"student_t"takes its p-value from the Student-t distribution and"fisherz"from Fisher’s z-transform.
- Returns:
Wraps a
temporalTemporalStructurewith lags0totau_max.structure.lag(0)is apagof the same-step links:i -> j,i o-> j,i <-> j(a hidden common cause), andi o-o j.structure.lag(k),k >= 1, is adigraphof the lagged links whose earlier end is a tail, the definite causes: its edgei -> jsays variableiat timet - kcauses variablejat timet, and a self-loop is a variable’s effect on its own future. The structure has nolag_weights.metadata["links"][k][i][j]holds every link between variableiatt - kand variablejattas three characters,""when there is none: the mark ati(-tail,<arrowhead,ocircle,xconflict),-, and the mark atj(>,-,o, orx), such as"o->","<->", or"-->"; lag0lists both orders.metadata["conflicts"]lists the[i, k, j]links with a conflict mark, whichstructure.lag(0)shows as a circle andstructure.lag(k)leaves out.metadata["p_values"][k][i][j]is the largest p-value of the final round’s tests of that pair, andmetadata["statistics"][k][i][j]the partial correlation of that test; lag0is symmetric with1and0on the diagonal.metadata["parents"][j]lists the[i, k]pairs (variableiat lagk) the last preliminary round found to be parents of variablej.orderingisNone, andmetadata["algorithm"]is"lpcmci".- Return type:
- Raises:
TypeError – If
tau_maxorn_preliminary_iterationsis not an int.ValueError – If
tau_maxis below 1,n_preliminary_iterationsbelow 0,pc_alphanot in(0, 1),indep_testneither"student_t"nor"fisherz", or ifdatais not a usable 2-D matrix with at leastn_variables * (tau_max + 1) + 2 * tau_max + 1rows, the length at which every test keeps a degree of freedom. Also if a variable repeats another up to scale and shift, at the same step or up to2 * tau_maxsteps apart, before any test runs; one message names every group of copies, a lagged value as'x' at lag k, and says to keep one column per group.
Notes
The graph starts complete, with every lagged link
o->(time order rules out the later end as a cause of the earlier one) and every same-step linko-o. A round removes links in stepsp = 0, 1, ...: it tests a link givenpof the neighbors of its later end that are not known non-causes of it, plus the parents of both ends, and tests the autodependency links first, then the cross links lag by lag. A same-step link is also tested from its other end. After each step that removes a link, orientation rules mark new tails and arrowheads on the lagged links and the round restarts atp = 0, as in the paper, so that the separating sets found later stay weakly minimal. In these passes the rules R9’ and R10’ orient lagged links only, but their paths may run through same-step links, directed or not, as the paper’s rules allow. Once nothing is left to test, the full set of rules runs, including the collider rule, which first tests the two links of a triple again given each stored separating set of the outer pair plus the parents of their ends. A preliminary round keeps only the parents it found and starts over from the complete graph. The final round also tests the links that may join two variables neither of which causes the other, given subsets of a wider neighborhood. Whether a node lies outside the separating set of two others is a majority vote over the distinct separating sets stored and found among the neighbors of the two. A mark that rules orient both ways is a conflict. The candidates of a step are ordered by statistics frozen when its group of links starts, so the order in which a group’s links are tested changes nothing. Equal statistics are ordered by each variable’s rank, as inhc(); the column-order guide says what the rank keeps. The collider rule stores every separating set its tests find, each made weakly minimal by dropping first the node whose removal leaves the largest p-value, so the stored sets do not depend on the order of the variables.All tests use the same time steps, the last
n_samples - 2 * tau_max, and every node a test conditions on lies withintau_maxsteps of the later end. A test’s partial correlation is computed from the correlation matrix, and from the least-squares residuals when the conditions are collinear to working precision. The defaults are the authors’ published defaults. The earlier end of a lagged link is searched with the empty set only, since time order already rules out the later end as its cause.Limitations. Measured on simulated linear-Gaussian series with strong autocorrelation, one cross-link per variable, 30% of them within a time step and the rest at lags 1 to 3, and 30% of the series unobserved, from 5 to 20 variables with 500 to 2,000 time steps, with
tau_max=3. Its median errors (endpoint SHD against the true PAG of the observed series) stayed below the empty graph’s at every size. It assumes linear effects, a stationary series, and no selection bias; hidden common causes are allowed. The graph coverstau_max + 1time steps, and a hidden cause that acts through earlier steps can add links within that window. The removal and rule steps test subsets of a node’s neighbors, so the number of tests grows exponentially with the number of links at one node. A test conditions on up ton_variables * (tau_max + 1) - 2values, so the series needs many more time steps than that.References
Examples
>>> import numpy as np >>> from andrey import lpcmci >>> rng = np.random.default_rng(0) >>> hidden = rng.standard_normal(1000) >>> x, y = np.zeros(1000), np.zeros(1000) >>> for t in range(1, 1000): ... x[t] = 0.5 * x[t - 1] + 0.7 * hidden[t] + rng.standard_normal() ... y[t] = 0.6 * y[t - 1] + 0.6 * hidden[t] + rng.standard_normal() >>> out = lpcmci(np.column_stack([x, y]), tau_max=2) >>> out.metadata["links"][0][0][1] '<->' >>> out.structure.lag(1).oriented_edges() [(0, 0, 'directed'), (1, 1, 'directed')]