Class FaskPool

java.lang.Object
edu.cmu.tetrad.search.FaskPool

public class FaskPool extends Object
Orients a common adjacency graph over multiple datasets by pooling the FASK left-right statistic across the datasets, rather than voting on per-dataset orientations as FaskVote does.

The procedure has two stages:

  1. Obtain a common adjacency graph: by combining external graphs supplied by the caller, one per dataset, or from a PooledAdjacencySearch (IMaGES, pooled FAS, or one of the moral-graph-based methods designed to remain correct when the true graph is cyclic; see PooledAdjacencySearch.Method). Where that stage compels a direction, it is retained as orientation evidence; see below.
  2. For each adjacency X—Y, compute the signed FASK left-right statistic lr_k separately within each dataset k (on standardized columns, with FASK's skew-sign correction applied within each dataset, as Fask.leftRightDiff(double[], double[], int) does internally), and combine them as a weighted average, lr = Σ w_k lr_k / Σ w_k. The edge is oriented X→Y when lr > 0 and Y→X when lr < 0.

This is the meta-analytic fixed-effect analog of FASK-Vote: where a vote discards the magnitude of each dataset's evidence, the pooled statistic retains it, so a dataset in which the left-right statistic is decisive counts for more than one in which it is a near coin flip. It is to FASK-Vote what the IMaGES averaged BIC score is to voting over per-dataset graphs.

Two weighting schemes are provided:

  • FaskPool.Weighting.N (default): w_k = n_k, the sample size of dataset k. This is exact when the datasets are homogeneous in everything but sample size and requires no variance estimation.
  • FaskPool.Weighting.INVERSE_VARIANCE: w_k = 1 / Var(lr_k), where Var(lr_k) is estimated by a within-dataset pairwise bootstrap. This is the standard fixed-effect meta-analysis estimator and downweights noisy datasets even when they are large.

Optionally, when the orientation alpha is set above zero, a bootstrap standard error of the pooled statistic is computed and the edge is left undirected (an abstention) unless the pooled statistic differs significantly from zero at that level. With the default alpha of zero, every adjacency is oriented by the sign of the pooled statistic, matching single-dataset FASK's behavior. A Cochran Q heterogeneity statistic is recorded per edge whenever bootstrap variances are available, so edges on which the datasets genuinely disagree in direction can be inspected via getEdgeStats().

Important: the datasets are never concatenated. Between-dataset differences in location, scale, or skew would make the concatenated sample a mixture, and mixtures can manufacture exactly the kind of asymmetric conditional-correlation structure the left-right rules read as causal signal. Only the finished, within-dataset, sign-corrected statistics are combined.

Orientation evidence. The graph-based stage does not only deliver adjacencies: where it compels a direction, that direction is evidence, and the pooled left-right statistic must beat it rather than simply replace it. Evidence comes from one of two sources, never both:

  • The adjacency stage. With PooledAdjacencySearch.Method.IMAGES and setUseAdjacencyOrientations(boolean) left at its default of true, the compelled edges of the IMaGES CPDAG—BOSS over the score averaged across the datasets—are kept as default orientations. Because IMaGES pools the score over all the datasets, its CPDAG is already a combination of them, and it counts as one unanimous evidence graph. The other adjacency methods return undirected graphs and so contribute no orientation evidence.
  • External graphs. setExternalGraphs(List) takes one graph per dataset—each dataset's own search result—and combines them, which is the point: a single external graph fitted to one dataset, or to the datasets pooled, would impose one skeleton and one set of orientations on all of them and defeat the cross-dataset construction. The composite skeleton keeps a pair when it is adjacent in more than setExternalAdjacencyFraction(double) of the graphs (default: a strict majority), and the compelled orientations are tallied per pair: the majority direction, if there is one, becomes the default, and a tie leaves the pair to the pooled statistic. When the adjacency stage is thereby skipped, setUseExternalOrientations(boolean) set to false makes the graphs contribute adjacencies only.

Only compelled orientations act: a graph that is a legal DAG (e.g., BOSS run with CPDAG output off, or a graph drawn by hand) is converted to its CPDAG first, so that reversible edges do not masquerade as compelled, and reversible edges are oriented from the pooled statistic exactly as if no evidence graph had been supplied.

What it takes to overturn a default scales with the strength of the evidence for it. In every case the pooled statistic must oppose the default and, when the orientation alpha is above zero, be significant at that level; beyond that, if the evidence is unanimous (no evidence graph compels the opposite direction), every dataset's statistic must individually oppose the default as well (strict cross-dataset sign consensus), whereas evidence that is itself divided yields to the pooled statistic alone. This is a lexicographic override, not additive pooling: the score-based orientation is the default, and the higher-moment statistic overrules it only on a counter-signal at least as strong as the evidence it is displacing. Note that with a single dataset the sign consensus is vacuous, so a positive orientation alpha should be set to give the override a meaningful gate. The provenance of each orientation, and the evidence counts behind it, are recorded in getEdgeStats().

Background knowledge is respected: a required or forbidden edge orients the pair regardless of the pooled statistic. Two-cycle detection is off by default, following FASK-Vote. When the two-cycle alpha is set above zero, the single-dataset FASK two-cycle test is run separately within each dataset, and the pair is output as a two-cycle only when EVERY dataset passes the test (unanimity). Caution: in a resimulation-null calibration on real data, the two-cycle channel of the closely-related single-dataset override procedure reproduced its detections under an acyclic null, so detections from this channel should not be trusted without a calibration of that kind on the data at hand.

Mixed data. With discrete variables in the datasets, the adjacency stage must be IMaGES with a score for mixed data (or external graphs). The pooled left-right statistic and the two-cycle test are computed for continuous pairs only, and only continuous variables are conditioned on in the two-cycle test. An adjacency with a discrete endpoint is oriented by knowledge or by the majority compelled orientation of the evidence graphs, if either applies, and is otherwise kept as an undirected edge, which means only that the method does not orient the pair.

Author:
josephramsey
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Pooled statistics for one edge.
    static enum 
    The provenance of an orientation decision, recorded per edge in getEdgeStats().
    static enum 
    The weighting scheme for pooling per-dataset left-right statistics.
  • Constructor Summary

    Constructors
    Constructor
    Description
    FaskPool(List<DataSet> dataSets, ScoreWrapper score)
    Constructs a pooled-FASK search from the supplied datasets and score wrapper.
  • Method Summary

    Modifier and Type
    Method
    Description
    Returns the per-edge pooled statistics recorded during the last search, keyed by the edge added to the result graph.
    search(Parameters parameters)
    Runs the search and returns the composite graph.
    void
    Sets how the common adjacency structure is obtained when no external graph is set.
    void
    setExternalAdjacencyFraction(double externalAdjacencyFraction)
    Sets the fraction of the external graphs in which a pair must be adjacent for it to be an adjacency of the composite skeleton: the pair is kept when its count exceeds this fraction of the number of graphs.
    void
    setExternalGraph(Graph externalGraph)
    Sets a single external graph, applied to every dataset.
    void
    setExternalGraphs(List<Graph> externalGraphs)
    Sets the external graphs, one per dataset, in the order of the datasets.
    void
    setFasAlpha(double fasAlpha)
    Sets the alpha level for the FAS-style adjacency tests.
    void
    setFasDepth(int fasDepth)
    Sets the depth of the FAS-style adjacency searches (-1 for unlimited; capped at 4 in MG_FAS).
    void
    setFastIcaA(double fastIcaA)
    Sets the FastICA tanh nonlinearity parameter for the LiNG adjacency stage.
    void
    setFastIcaMaxIter(int fastIcaMaxIter)
    Sets the FastICA maximum iterations for the LiNG adjacency stage.
    void
    setFastIcaTolerance(double fastIcaTolerance)
    Sets the FastICA convergence tolerance for the LiNG adjacency stage.
    void
    Sets background knowledge for the search.
    void
    Sets the left-right rule used within each dataset.
    void
    setLingThreshold(double lingThreshold)
    Sets the threshold on the pooled absolute LiNG B-hat entries above which a moral pair is kept as an adjacency.
    void
    setNumBootstraps(int numBootstraps)
    Sets the number of bootstrap resamples per dataset used to estimate Var(lr_k).
    void
    setOrientationAlpha(double orientationAlpha)
    Sets the significance level for the orientation decision.
    void
    setTwoCycleAlpha(double twoCycleAlpha)
    Sets the alpha for the per-dataset two-cycle test.
    void
    setUseAdjacencyOrientations(boolean useAdjacencyOrientations)
    Sets whether the adjacency stage's compelled orientations act as default orientations in the same way.
    void
    setUseExternalOrientations(boolean useExternalOrientations)
    Sets whether the external graphs' compelled orientations act as default orientations that the pooled statistic can overturn only on strong opposing evidence (see the class Javadoc).
    void
    Sets the weighting scheme for pooling.

    Methods inherited from class Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • FaskPool

      public FaskPool(List<DataSet> dataSets, ScoreWrapper score)
      Constructs a pooled-FASK search from the supplied datasets and score wrapper.
      Parameters:
      dataSets - the datasets to search over
      score - the score wrapper for the IMaGES adjacency stage
      Throws:
      NullPointerException - if any argument is null
      IllegalArgumentException - if the dataset list is empty
  • Method Details

    • search

      public Graph search(Parameters parameters) throws InterruptedException
      Runs the search and returns the composite graph.
      Parameters:
      parameters - the search parameters (passed to the IMaGES stage)
      Returns:
      the composite graph
      Throws:
      InterruptedException - if the underlying IMaGES search is interrupted
    • setKnowledge

      public void setKnowledge(Knowledge knowledge)
      Sets background knowledge for the search. A defensive copy is stored.
      Parameters:
      knowledge - knowledge containing forbidden and required edges
      Throws:
      NullPointerException - if the supplied knowledge is null
    • setExternalGraph

      public void setExternalGraph(Graph externalGraph)
      Sets a single external graph, applied to every dataset. Equivalent to setExternalGraphs(List) with a one-element list; since one graph cannot disagree with itself, its compelled orientations count as unanimous evidence, so a positive orientation alpha should be set to give the override a meaningful gate. Prefer supplying one graph per dataset.
      Parameters:
      externalGraph - the external graph, or null to use the adjacency search
    • setExternalGraphs

      public void setExternalGraphs(List<Graph> externalGraphs)
      Sets the external graphs, one per dataset, in the order of the datasets. When nonempty, the adjacency stage is skipped and these graphs are combined: a pair is an adjacency of the composite skeleton when it is adjacent in more than setExternalAdjacencyFraction(double) of them, and their compelled orientations are tallied into orientation evidence, with the majority direction (if any) becoming the default orientation of that pair.

      The list need not have one entry per dataset—any number of graphs over the same variables is combined the same way—but supplying each dataset's own graph is the point: it is what makes the evidence cross-dataset, so that unanimity among the graphs means something.

      Parameters:
      externalGraphs - the external graphs, or null or empty to use the adjacency search
    • setUseExternalOrientations

      public void setUseExternalOrientations(boolean useExternalOrientations)
      Sets whether the external graphs' compelled orientations act as default orientations that the pooled statistic can overturn only on strong opposing evidence (see the class Javadoc). When false, the external graphs contribute adjacencies only. Only consulted when external graphs have been set. Default: true.
      Parameters:
      useExternalOrientations - true to use the external orientations as defaults
    • setUseAdjacencyOrientations

      public void setUseAdjacencyOrientations(boolean useAdjacencyOrientations)
      Sets whether the adjacency stage's compelled orientations act as default orientations in the same way. Only PooledAdjacencySearch.Method.IMAGES produces any: the CPDAG of a BOSS search over the score averaged across the datasets, whose compelled orientations are score-based, cross-dataset evidence about direction. When false, only the adjacencies of that CPDAG are used and every edge is oriented from the pooled statistic. Only consulted when no external graphs have been set. Default: true.
      Parameters:
      useAdjacencyOrientations - true to use the adjacency stage's orientations as defaults
    • setExternalAdjacencyFraction

      public void setExternalAdjacencyFraction(double externalAdjacencyFraction)
      Sets the fraction of the external graphs in which a pair must be adjacent for it to be an adjacency of the composite skeleton: the pair is kept when its count exceeds this fraction of the number of graphs. Zero takes the union of the skeletons, 0.5 (the default) a strict majority, and 1.0 the intersection. Ignored unless more than one external graph is supplied.
      Parameters:
      externalAdjacencyFraction - the fraction, in [0, 1]
    • setTwoCycleAlpha

      public void setTwoCycleAlpha(double twoCycleAlpha)
      Sets the alpha for the per-dataset two-cycle test. Zero (the default) disables two-cycle detection; above zero, a pair is output as a two-cycle only when every dataset passes the single-dataset FASK two-cycle test at this level. See the class Javadoc for a caution about this channel.
      Parameters:
      twoCycleAlpha - the significance level, in [0, 1]
    • setLeftRight

      public void setLeftRight(Fask.LeftRight leftRight)
      Sets the left-right rule used within each dataset. Default: FASK2.
      Parameters:
      leftRight - the left-right rule
    • setWeighting

      public void setWeighting(FaskPool.Weighting weighting)
      Sets the weighting scheme for pooling. Default: N (sample-size weights).
      Parameters:
      weighting - the weighting scheme
    • setAdjacencyMethod

      public void setAdjacencyMethod(PooledAdjacencySearch.Method method)
      Sets how the common adjacency structure is obtained when no external graph is set. Default: IMAGES. Ignored when an external graph has been set.
      Parameters:
      method - the adjacency method
    • setFasAlpha

      public void setFasAlpha(double fasAlpha)
      Sets the alpha level for the FAS-style adjacency tests. Default: 0.05.
      Parameters:
      fasAlpha - the alpha level, in (0, 1)
    • setFasDepth

      public void setFasDepth(int fasDepth)
      Sets the depth of the FAS-style adjacency searches (-1 for unlimited; capped at 4 in MG_FAS). Default: -1.
      Parameters:
      fasDepth - the depth
    • setLingThreshold

      public void setLingThreshold(double lingThreshold)
      Sets the threshold on the pooled absolute LiNG B-hat entries above which a moral pair is kept as an adjacency. Default: 0.1.
      Parameters:
      lingThreshold - the threshold, nonnegative
    • setFastIcaMaxIter

      public void setFastIcaMaxIter(int fastIcaMaxIter)
      Sets the FastICA maximum iterations for the LiNG adjacency stage. Default: 2000.
      Parameters:
      fastIcaMaxIter - maximum iterations, positive
    • setFastIcaTolerance

      public void setFastIcaTolerance(double fastIcaTolerance)
      Sets the FastICA convergence tolerance for the LiNG adjacency stage. Default: 1e-6.
      Parameters:
      fastIcaTolerance - the tolerance, positive
    • setFastIcaA

      public void setFastIcaA(double fastIcaA)
      Sets the FastICA tanh nonlinearity parameter for the LiNG adjacency stage. Default: 1.1.
      Parameters:
      fastIcaA - the parameter
    • setOrientationAlpha

      public void setOrientationAlpha(double orientationAlpha)
      Sets the significance level for the orientation decision. Zero (the default) orients every adjacency by the sign of the pooled statistic; above zero, an edge is left undirected unless the pooled statistic differs significantly from zero at this level (two-sided, bootstrap standard error).
      Parameters:
      orientationAlpha - the significance level, in [0, 1]
    • setNumBootstraps

      public void setNumBootstraps(int numBootstraps)
      Sets the number of bootstrap resamples per dataset used to estimate Var(lr_k). Default: 200.
      Parameters:
      numBootstraps - the number of resamples, at least 2
    • getEdgeStats

      public Map<Edge, FaskPool.EdgeStat> getEdgeStats()
      Returns the per-edge pooled statistics recorded during the last search, keyed by the edge added to the result graph. The z and Q entries are NaN when bootstrap variances were not computed (n-weighting with orientation alpha zero).
      Returns:
      an unmodifiable view of the per-edge statistics