andrey.bootstrap#
- andrey.bootstrap(method, data, *, n_resamples=100, seed=None, threshold=0.5, strict=False, resampling='subsample', sample_fraction=0.5, block_length=None, keep_fits=False, **method_kwargs)[source]#
Refit a method on resamples of the rows; return each edge’s frequency and an averaged graph.
Each resample is a subsample,
sample_fractionof the rows ofdatadrawn without replacement, or a bootstrap resample, as many rows drawn with replacement (resampling), andmethodis fitted on it. The result counts, for every pair of variables, the fits that give each endpoint-mark pair (->,<-,--,<->,o->, …) and builds the averaged graph: the vote of the fits, made a valid graph of the method’s kind [1] [2] [3]. A method with a row-aligned input (cdnod’sdomain_index,gies’sinterventions) resamples that input with the rows. A time-series method on one series subsamples one stretch of consecutive rows (and bootstraps blocks of consecutive rows),longitudinal_lingamresamples whole units, andmulti_group_direct_lingamresamples each dataset on its own.- Parameters:
method (
str|Callable[...,Any]) – A method’s name, such as"pc", or the callable itself, such asandrey.pc.data (
ArrayLike|Sequence[ArrayLike]) – The data, as the method takes it.multi_group_direct_lingamandlongitudinal_lingamtake a sequence of arrays.n_resamples (
int) – The number of resamples and fits.n_boot, the former name, works with aDeprecatedArgumentWarningfor one more release.seed (
int|None) – The seed of the resamples, a non-negative integer.NoneusesANDREY_SEED, or 0 when it is unset. Resamplebdepends onseedandbalone. A method that takes aseedfits resamplebwith a seed derived from this one andb, so the method’s ownseedcannot be set here.threshold (
float) – A pair of the averaged graph must be adjacent in more than this share of the fits, or in all of them, in[0.5, 1]. Its most frequent edge must also be in more fits than no edge is, which needs more than half of them, so a value below 0.5 would change nothing.strict (
bool) – What happens when the vote of the fits has no valid graph of the method’s kind:Falsereturns the valid resample graph nearest the others with a warning, andTrueraisesValueError.resampling (
str) – How a resample is drawn."subsample"drawsround(sample_fraction * n_samples)distinct rows, kept in their original order; for a time-series method on one series it is one stretch of consecutive rows at a random start [4] [5]."bootstrap"drawsn_samplesrows with replacement; for a time-series method on one series it draws blocks ofblock_lengthconsecutive rows (a moving block bootstrap).sample_fraction (
float) – The share of the rows in a subsample, in(0, 1], so thatround(sample_fraction * n_samples)is at least 2; forlongitudinal_lingam, the share of the units, and formulti_group_direct_lingam, the share of each dataset’s rows. Not used by"bootstrap".block_length (
int|None) – Forresampling="bootstrap"of a time-series method on one series, the number of consecutive rows in a block, from 1 ton_samples.Noneusesmax(ceil(n_samples ** (1/3)), 10 * tau_max)for a method with atau_max, andceil(n_samples ** (1/3))for the others, at mostn_samples. A block break puts rows that were not neighbors side by side, which weakens a link that many steps long or longer, so a block should be at least ten times the longest lag. Not for any other resampling.keep_fits (
bool) – Keep every fit in thefitsproperty.**method_kwargs (
Any) – The method’s other arguments: its keyword parameters, and a row-aligned input such asdomain_index=.
- Returns:
The frequencies and the averaged graph; for
multi_group_direct_lingam, one per group.metadatarecords theresampling, thesample_fractionof a subsample, theblock_lengthof a block bootstrap, thetie_breakrule in effect (andrey.config), andaveraged_graph:"vote","nearest_resample"when the averaged graph is the valid resample graph nearest the others, or"nearest_resample_invalid"when no resample is a valid graph of the method’s kind.- Return type:
- Raises:
ValueError – If
methodis not a method of Andrey, an argument is out of range, a row-aligned input has a different number of rows fromdata,block_lengthis given for a resampling that does not use blocks,strict=Trueand the vote has no valid graph of the method’s kind, or a fit raises it: the error then names the resample in a note.NotImplementedError – For
gin, whose number of latent nodes varies from fit to fit.RuntimeError – If a worker process dies.
- Warns:
AndreyWarning – Each distinct warning the fits raised, once; and, with
strict=False, when the vote has no valid graph of the method’s kind, so the averaged graph is the valid resample graph nearest the others, or, when no resample is valid, the resample graph nearest the others.
Notes
Subsampling and the bootstrap. A bootstrap resample repeats some rows and leaves out others, so a conditional-independence test or a score sees more evidence than the resample holds. A method built on such tests, such as
pc, keeps weak and false edges in more resamples than it does ondata, and an orientation that needs two variables to stay non-adjacent, a collider, is found in fewer. A subsample holds distinct rows only, so it has no such excess. Banerjee, Andrews, and Kummerfeld [3] compared both schemes with two score searches on linear Gaussian data: no scheme was best everywhere, the bootstrap at the full size performed poorly, and subsampling half of the rows performed about as well as a bootstrap scored at the effective sample size, about half the size. The default draws half of the rows, as stability selection does [4], and it changes only the draw, so it means the same for every method.On linear data with 20 and 50 variables and 1,000 and 5,000 rows (
pc,ges, anddirect_lingam; 10 datasets per cell), the averaged graph of half-size subsamples had no more errors (SHD) than the bootstrap’s in any of the 10 cells, and fewer in 5; forgeswith 50 variables and 1,000 rows, 5.0 fewer on average (95% interval 2.7 to 7.9). Forgeswith 20 variables and 1,000 rows, the averaged graph had 18 wrong edge types instead of 32, and 9 of the 10 averaged graphs were valid CPDAGs instead of 3. The adjacency frequencies had a lower calibration error in 9 of the 10 cells, and a fit took 0.56 to 0.95 of the time, since it has half the rows. The one cell where the point estimate was worse,pcwith 20 variables and 1,000 rows, was 0.43 errors above the bootstrap’s over 30 datasets (interval -0.23 to 1.13). A largersample_fractiongives fits closer to the fit ondata, so the resamples agree more and the frequencies say less about how much the fit varies.For a time-series method on one series, a subsample is one stretch of consecutive rows, which keeps the lags inside it [5]. With
pcmci,pcmciplus,lpcmci, andvarma_lingamon simulated series with 5 and 10 variables and 500 and 1,000 rows (10 series per cell, 14 cells; 30 series per cell, 12 cells, for the first three), a stretch of half of the series had no more errors (SHD) than the block bootstrap in any cell, and fewer, by an interval below 0, in 9 of the 14 cells of 10 series. Those blocks wereceil(n_samples ** (1/3))rows, shorter than ten times the longest lag.The averaged graph. Each pair of variables takes its most frequent state in the fits, no edge counted as one of the states: the pair gets its most frequent edge when more fits have that edge than have no edge, which needs the pair adjacent in more than half of them, and
thresholdcan ask for more. When two edges tie, the pair takes the least committal one,--, oro-ofor apag. This vote is the graph with the least mean structural Hamming distance to the fits. It is theHighestensemble of Tetrad [6], with a tie between an edge and no edge going to no edge, as in tigramite’s majority vote [7].A vote of CPDAGs or PAGs is often not a valid CPDAG or PAG: it can direct an edge that no v-structure compels. So the vote is then made a valid graph of the method’s kind by the published steps. A
dagbecomes a consistent extension, a DAG with the vote’s skeleton, v-structures, and directed edges [8]: the vote itself when it has no directed cycle, with a tie edge pointing as the columns’tie_ranks()ondatadecide (tie_break,andrey.config: ranks computed from the data, or the column order under"position"), so reordering the columns relabels the graph. Acpdagbecomes the CPDAG [9] of a consistent extension, so an edge that no v-structure compels is undirected. Apagbecomes the PAG of the MAG that Zhang’s construction builds from it [10]. Withknowledge, the edges it directs stay directed: acpdagbecomes its maximally oriented PDAG, and apagis oriented asfciorients one under knowledge: the endpoints the knowledge sets come first, and Zhang’s orientation rules then run from them until no endpoint changes, as they do in a fit [10], [11]. A time-series result’s lag graphs keep the vote, as tigramite’s does [7]: a lag-0 graph is oriented with the lagged edges, which the steps for one graph do not see.The vote has no consistent extension or MAG when, for example, its directed edges form a cycle or its undirected edges a chordless cycle of four or more nodes. With
strict=False, the averaged graph is then the resample graph nearest the others, a graph the method returned: the fit whose state of each pair the most fits share, summed over the pairs, which is the fit with the least mean structural Hamming distance to the others (Tetrad’sMedian[6]). Only a resample that is a valid graph of the method’s kind can be that fit: acpdagwith a consistent DAG extension, or a PAG that passes the steps above, because a method can return a graph labeledcpdagthat no DAG extends (pcleaves conflicting orientations undirected). A warning says so, andmetadata["averaged_graph"]is"nearest_resample"; it is"vote"otherwise. When no resample is valid, a warning says so, the averaged graph is the resample nearest the others, andmetadata["averaged_graph"]is"nearest_resample_invalid".strict=Trueraises in both cases instead, as bnlearn’scextenddoes by default [12]. Either way,frequencyandtablekeep the whole vote.On linear data with 20 and 50 variables and 500, 1,000, and 5,000 rows (
pc,ges,fci, anddirect_lingam; 20 datasets per cell; 100 resamples withresampling="bootstrap"), the averaged graph had fewer errors (SHD) than the rule of 0.11.0 (a pair adjacent in at least half the fits takes its most frequent edge) in 11 of the 24 cells, by an interval below 0, and more in none. It had fewer errors than the fit on all the rows in 14 cells and more in one,geswith 20 variables and 1,000 rows. The vote had a valid graph of the method’s kind in 111 of the 120 datasets ofpc, 114 offci, and all ofgesanddirect_lingam; the rule of 0.11.0 gave a valid CPDAG or PAG in 0 to 13 of the 20 datasets of a cell.A frequency is a ranking of the edges, not a probability, and no error bound comes with the averaged graph. Resampling can also make a column constant; a fit that raises stops the run, and its row numbers count the rows of the resample.
Workers. The fits run on the worker processes
andrey.config.n_jobsandANDREY_N_JOBSset, as for every method:-1uses every usable core, and0or1fits in this process. Each fit runs on one worker and one BLAS thread, and the result is the same at any worker count.Limitations. Not benchmarked yet. Refitting is the cost:
n_resamplestimes the method’s own, shared across the workers. A moving block bootstrap weakens a link that spans a block break, and a stretch holds onlysample_fractionof the series, so each understates what a very short series can show.References
Examples
>>> import numpy as np >>> from andrey import bootstrap >>> rng = np.random.default_rng(0) >>> x = rng.standard_normal(300) >>> data = np.column_stack([x, x + rng.standard_normal(300), rng.standard_normal(300)]) >>> out = bootstrap("pc", data, n_resamples=10, seed=0) >>> out.n_resamples 10 >>> bool(out.frequency("absent")[0, 1] < 0.5) True >>> out.metadata["resampling"], out.metadata["sample_fraction"] ('subsample', 0.5)