Package {lingamr}


Type: Package
Title: 'LiNGAM' Algorithms for Causal Discovery
Version: 0.1.2
Description: R implementation of 'LiNGAM' (Linear Non-Gaussian Acyclic Model) algorithms for causal discovery, following Shimizu et al. (2011) https://www.jmlr.org/papers/v12/shimizu11a.html. Based on the 'Python' implementation by Ikeuchi et al. (2023) https://github.com/cdt15/lingam. The 'VAR-LiNGAM' residual diagnostics are inspired by the 'VARLiNGAM' R code of Moneta et al. https://sites.google.com/site/dorisentner/publications/VARLiNGAM.
License: MIT + file LICENSE
URL: https://github.com/morimotoosamu/lingamr, https://morimotoosamu.github.io/lingamr/
BugReports: https://github.com/morimotoosamu/lingamr/issues
Depends: R (≥ 4.1.0)
Imports: generics, grDevices, parallel, stats, utils
Suggests: DiagrammeR, ggplot2, glmnet, igraph, knitr, lavaan, mice, nortest, pcalg, rmarkdown, spelling, testthat (≥ 3.0.0), tseries
VignetteBuilder: knitr
Config/testthat/edition: 3
Encoding: UTF-8
Language: en-US
Config/roxygen2/version: 8.0.0
NeedsCompilation: no
Packaged: 2026-07-08 17:03:11 UTC; morimoto.osamu
Author: Osamu Morimoto [aut, cre, cph], T. Ikeuchi [cph], G. Haraoka [cph], M. Ide [cph], W. Kurebayashi [cph], S. Shimizu [cph]
Maintainer: Osamu Morimoto <galactic.supermarket@gmail.com>
Repository: CRAN
Date/Publication: 2026-07-17 13:20:07 UTC

lingamr: 'LiNGAM' Algorithms for Causal Discovery

Description

logo

R implementation of 'LiNGAM' (Linear Non-Gaussian Acyclic Model) algorithms for causal discovery, following Shimizu et al. (2011) https://www.jmlr.org/papers/v12/shimizu11a.html. Based on the 'Python' implementation by Ikeuchi et al. (2023) https://github.com/cdt15/lingam. The 'VAR-LiNGAM' residual diagnostics are inspired by the 'VARLiNGAM' R code of Moneta et al. https://sites.google.com/site/dorisentner/publications/VARLiNGAM.

Details

tutorial: vignette("lingamr", package = "lingamr")

Author(s)

Maintainer: Osamu Morimoto galactic.supermarket@gmail.com [copyright holder]

Authors:

Other contributors:

References

Shimizu, S., et al. (2011). DirectLiNGAM: A direct method for learning a linear non-Gaussian structural equation model. Journal of Machine Learning Research, 12, 1225-1248.

Hyvärinen, A., Zhang, K., Shimizu, S., & Hoyer, P. O. (2010). Estimation of a structural vector autoregression model using non-Gaussianity. Journal of Machine Learning Research, 11, 1709-1731.

Moneta, A., Entner, D., Hoyer, P. O., & Coad, A. (2013). Causal inference by independent component analysis: Theory and applications. Oxford Bulletin of Economics and Statistics, 75(5), 705-730. VARLiNGAM R code: https://sites.google.com/site/dorisentner/publications/VARLiNGAM

Shimizu, S. (2012). Joint estimation of linear non-Gaussian acyclic models. Neurocomputing, 81, 104-107. (MultiGroup Direct LiNGAM)

Tashiro, T., Shimizu, S., Hyvärinen, A., & Washio, T. (2014). ParceLiNGAM: A causal ordering method robust against latent confounders. Neural Computation, 26(1), 57-83.

Maeda, T. N., & Shimizu, S. (2020). RCD: Repetitive causal discovery of linear non-Gaussian acyclic models with latent confounders. AISTATS 2020, PMLR 108, 735-745.

Wang, Y. S., & Drton, M. (2020). High-dimensional causal discovery under non-Gaussianity. Biometrika, 107(1), 41-59.

Zeng, Y., Shimizu, S., Matsui, H., & Sun, F. (2022). Causal discovery for linear mixed data. Proceedings of the First Conference on Causal Learning and Reasoning (CLeaR 2022), PMLR 177, 994-1009.

Python implementation (DirectLiNGAM, VAR-LiNGAM, MultiGroup, ParceLiNGAM, RCD, LiM, HighDim): cdt15/lingam, https://github.com/cdt15/lingam

See Also

Useful links:


Collapse an ImputationBootstrapResult into a BootstrapResult

Description

bootstrap_with_imputation()'s result carries an extra n_repeats dimension (one causal-structure estimate per imputed dataset per bootstrap iteration), which the existing bootstrap analysis functions (get_probabilities(), get_causal_direction_counts(), get_directed_acyclic_graph_counts(), get_causal_order_stability(), tidy()) do not expect. This collapses that dimension by aggregating the n_repeats adjacency matrices of each iteration into one, producing a regular lingam_direct_bootstrap()-style BootstrapResult.

Usage

as_bootstrap_result(x, aggregate = c("median", "mean"))

Arguments

x

An ImputationBootstrapResult, as returned by bootstrap_with_imputation().

aggregate

How to aggregate across the n_repeats dimension: "median" (default) or "mean".

Value

A BootstrapResult (see lingam_direct_bootstrap()) with total_effects = NULL (total effects are not computed by bootstrap_with_imputation()); calling get_total_causal_effects() on it raises the usual "not computed" error.

Examples

set.seed(1)
sample6 <- generate_lingam_sample_6(n = 300, seed = 1)
X <- sample6$data
X$x5[sample.int(nrow(X), size = 30)] <- NA

if (requireNamespace("mice", quietly = TRUE)) {
  res <- bootstrap_with_imputation(X,
    n_sampling = 5L, n_repeats = 3L, seed = 42, verbose = FALSE
  )
  bs <- as_bootstrap_result(res, aggregate = "median")
  get_probabilities(bs)

  # get_total_causal_effects() is not available: total effects were never computed
  tryCatch(get_total_causal_effects(bs), error = function(e) conditionMessage(e))
}

Plot the causal graph of a LiMResult with ggplot2

Description

Draws the estimated causal structure of a LiM model as a ggplot2-based directed graph, exactly like autoplot.LingamResult().

Usage

## S3 method for class 'LiMResult'
autoplot(
  object,
  threshold = 0,
  node_size = 16,
  node_color = "lightblue",
  label_edges = TRUE,
  label_pos = 0.35,
  ...
)

Arguments

object

Return value of lingam_lim() (a LiMResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

node_size

Node size (default: 16)

node_color

Node fill color (default: "lightblue")

label_edges

Whether to display coefficient labels on edges (default: TRUE)

label_pos

Position of each coefficient label along its edge, as a fraction from the source (0) to the target (1). The default 0.35 places labels off-center (toward the source) so labels on crossing edges do not overlap near the midpoint.

...

Unused

Value

A ggplot object

Examples


if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("igraph", quietly = TRUE)) {
  library(ggplot2)
  set.seed(1)
  dat <- generate_lim_sample(n = 300)
  model <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
  autoplot(model)
}


Plot the causal graph of a LingamResult with ggplot2

Description

Draws the estimated causal structure as a ggplot2-based directed graph. Node positions are computed with igraph's hierarchical layout (sugiyama), so the causal flow is generally arranged from top to bottom. Because the output is a static image, it is stable in RMarkdown / Quarto. If you need an interactive HTML figure, use plot_adjacency() (DiagrammeR-based).

Usage

## S3 method for class 'LingamResult'
autoplot(
  object,
  threshold = 0,
  node_size = 16,
  node_color = "lightblue",
  label_edges = TRUE,
  label_pos = 0.35,
  ...
)

Arguments

object

Return value of lingam_direct() (a LingamResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

node_size

Node size (default: 16)

node_color

Node fill color (default: "lightblue")

label_edges

Whether to display coefficient labels on edges (default: TRUE)

label_pos

Position of each coefficient label along its edge, as a fraction from the source (0) to the target (1). The default 0.35 places labels off-center (toward the source) so labels on crossing edges do not overlap near the midpoint.

...

Unused

Details

autoplot() is a ggplot2 generic, so you must load ggplot2 with library(ggplot2) before using it. Plotting requires ggplot2 and igraph.

Value

A ggplot object

Examples


if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("igraph", quietly = TRUE)) {
  library(ggplot2)
  dat <- generate_lingam_sample_6()
  model <- lingam_direct(dat$data, reg_method = "ols")
  autoplot(model)
}


Plot one group of a MultiGroupLingamResult with ggplot2

Description

Extracts a single group's result with get_group_result() and draws it like autoplot.LingamResult(), with the group shown in the subtitle. The causal order is shared across groups, but the coefficients (and therefore the plotted edges) are group specific.

Usage

## S3 method for class 'MultiGroupLingamResult'
autoplot(
  object,
  group = 1,
  threshold = 0,
  node_size = 16,
  node_color = "lightblue",
  label_edges = TRUE,
  label_pos = 0.35,
  ...
)

Arguments

object

Return value of lingam_multi_group() (a MultiGroupLingamResult object)

group

Which group to plot: a group name (character) or a 1-based index (default: 1)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

node_size

Node size (default: 16)

node_color

Node fill color (default: "lightblue")

label_edges

Whether to display coefficient labels on edges (default: TRUE)

label_pos

Position of each coefficient label along its edge, as a fraction from the source (0) to the target (1). The default 0.35 places labels off-center (toward the source) so labels on crossing edges do not overlap near the midpoint.

...

Unused

Value

A ggplot object

Examples


if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("igraph", quietly = TRUE)) {
  library(ggplot2)
  mg <- generate_multi_group_sample()
  model <- lingam_multi_group(mg$data_list, reg_method = "ols")
  autoplot(model, group = 2)
}


Plot the causal graph of a ParceLingamResult with ggplot2

Description

Draws the estimated causal structure as a ggplot2-based directed graph, like autoplot.LingamResult(). Variable pairs whose adjacency-matrix entries are NA (unresolved order / suspected latent confounding) are drawn as dashed, arrowless segments.

Usage

## S3 method for class 'ParceLingamResult'
autoplot(
  object,
  threshold = 0,
  node_size = 16,
  node_color = "lightblue",
  label_edges = TRUE,
  label_pos = 0.35,
  ...
)

Arguments

object

Return value of lingam_parce() (a ParceLingamResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

node_size

Node size (default: 16)

node_color

Node fill color (default: "lightblue")

label_edges

Whether to display coefficient labels on edges (default: TRUE)

label_pos

Position of each coefficient label along its edge, as a fraction from the source (0) to the target (1). The default 0.35 places labels off-center (toward the source) so labels on crossing edges do not overlap near the midpoint.

...

Unused

Value

A ggplot object

Examples


if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("igraph", quietly = TRUE)) {
  library(ggplot2)
  dat <- generate_parce_sample(n = 500, seed = 42)
  model <- lingam_parce(dat$data)
  autoplot(model)
}


Plot the causal graph of an RCDResult with ggplot2

Description

Draws the estimated causal structure as a ggplot2-based directed graph, like autoplot.LingamResult(). Variable pairs suspected to share a latent confounder (NA entries in the adjacency matrix) are drawn as dashed, arrowless segments.

Usage

## S3 method for class 'RCDResult'
autoplot(
  object,
  threshold = 0,
  node_size = 16,
  node_color = "lightblue",
  label_edges = TRUE,
  label_pos = 0.35,
  ...
)

Arguments

object

Return value of lingam_rcd() (an RCDResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

node_size

Node size (default: 16)

node_color

Node fill color (default: "lightblue")

label_edges

Whether to display coefficient labels on edges (default: TRUE)

label_pos

Position of each coefficient label along its edge, as a fraction from the source (0) to the target (1). The default 0.35 places labels off-center (toward the source) so labels on crossing edges do not overlap near the midpoint.

...

Unused

Value

A ggplot object

Examples


if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("igraph", quietly = TRUE)) {
  library(ggplot2)
  confounded <- generate_rcd_sample(n = 300, seed = 1)
  model <- lingam_rcd(confounded$data)
  autoplot(model)
}


Bootstrap with Multiple Imputation for Direct LiNGAM

Description

Causal discovery on data containing missing values (NA). Each bootstrap resample (drawn with replacement, missing values retained) is multiply imputed into n_repeats complete datasets, and a common causal structure is jointly estimated across those datasets with lingam_multi_group() (Shimizu 2012), treating the imputed copies as "groups" sharing one causal order. R port of the Python lingam.tools.bootstrap_with_imputation().

Usage

bootstrap_with_imputation(
  X,
  n_sampling,
  n_repeats = 10L,
  imputer = NULL,
  cd_fit = NULL,
  prior_knowledge = NULL,
  apply_prior_knowledge_softly = FALSE,
  seed = NULL,
  verbose = TRUE
)

Arguments

X

A numeric matrix or data frame (n_samples x n_features). May contain NA. If X has no missing values, a warning suggests using lingam_direct_bootstrap() instead, and estimation proceeds anyway.

n_sampling

Number of bootstrap iterations (positive integer)

n_repeats

Number of imputed datasets generated per bootstrap sample (positive integer, default 10L). Ignored when a custom imputer is supplied; the number of datasets it returns is used instead.

imputer

NULL, or a ⁠function(X_boot)⁠ returning a list of complete (no-NA) numeric matrices, each with the same dimensions as X_boot. Defaults to multiple imputation via mice::mice(method = "norm").

cd_fit

NULL, or a ⁠function(X_list)⁠ returning ⁠list(causal_order = <integer vector, 1-based permutation>, adjacency_matrices = <list of p x p matrices, one per element of X_list>)⁠. Defaults to joint estimation via lingam_multi_group().

prior_knowledge

Prior knowledge matrix (NULL allowed). Only used when cd_fit = NULL; a warning is issued if supplied together with a custom cd_fit.

apply_prior_knowledge_softly

Apply prior knowledge softly (logical). Same restriction as prior_knowledge.

seed

Random seed (NULL allowed). Set once before the bootstrap loop; governs both the resampling and (via the global RNG) mice's imputation.

verbose

Whether to display progress (logical)

Details

Procedure: for each of n_sampling iterations, (1) resample X with replacement (missing values are retained), (2) impute the resample into n_repeats complete datasets, (3) jointly estimate one causal structure shared by all n_repeats datasets with lingam_multi_group(). This assumes the same causal structure underlies every imputed copy.

Default imputer. mice::mice(method = "norm") (Bayesian linear regression, multiple imputation by chained equations) is the closest standard R analogue of the upstream Python default (IterativeImputer(sample_posterior = TRUE)). The two do not produce numerically identical imputations.

Custom imputer / cd_fit. Supply your own imputation or causal-discovery routine by passing a function with the signature described above; the return value is validated and a descriptive error is raised on violation. This replaces the abstract base classes (BaseMultipleImputation, BaseMultiGroupCDModel) of the Python original.

Downstream analysis. The result's shape (an extra n_repeats dimension for adjacency_matrices and imputation_results) differs from lingam_direct_bootstrap()'s BootstrapResult, so it cannot be passed directly to get_probabilities() etc. Use as_bootstrap_result() to collapse the n_repeats dimension (aggregating by median or mean) into a BootstrapResult.

On iteration failures: each iteration is wrapped in tryCatch(); a failing iteration (e.g. mice fails to converge on a particular resample) is skipped with a warning, and only if every iteration fails is an error raised, mirroring lingam_direct_bootstrap().

Sequential execution only. Unlike lingam_direct_bootstrap(), this function does not support parallel = TRUE; the upstream Python implementation is sequential as well. If needed in the future, it can be parallelized following the parallel::makePSOCKcluster() pattern used by lingam_direct_bootstrap().

Value

An ImputationBootstrapResult (list) containing:

Examples

set.seed(1)
sample6 <- generate_lingam_sample_6(n = 300, seed = 1)
X <- sample6$data
X$x5[sample.int(nrow(X), size = round(0.1 * nrow(X)))] <- NA # MCAR 10% on x5


if (requireNamespace("mice", quietly = TRUE)) {
  res <- bootstrap_with_imputation(X,
    n_sampling = 5L, n_repeats = 3L, seed = 42, verbose = FALSE
  )
  print(res)

  # Collapse the n_repeats dimension to reuse the existing bootstrap tooling
  bs <- as_bootstrap_result(res, aggregate = "median")
  get_probabilities(bs)
}


Build the RCD adjacency matrix from parents and confounder pairs

Description

Faithful port of rcd.py's adjacency-matrix construction (original 368-408 lines). B[i, j] is the coefficient of j -> i, matching the lingamr convention; no transpose is needed.

Usage

build_adjacency_matrix_rcd(X, P, C)

Arguments

X

(uncentered) data matrix

P

parent list from extract_parents()

C

confounder-pair list from extract_vars_sharing_confounders()

Value

adjacency matrix B (n_features x n_features), with NA entries for confounder pairs


Build the lagged design matrix for VAR models

Description

Constructs Z such that column block k (columns (k-1)*p+1 to k*p) contains ⁠X_{t-k}⁠ for ⁠t = lags+1, ..., n⁠.

Usage

build_lag_matrix(X, lags)

Arguments

X

numeric matrix (n_samples x n_features)

lags

lag order

Value

matrix of shape ⁠(n - lags, lags * p)⁠


Build a lavaan model string from an adjacency matrix

Description

Converts a lingamr-convention adjacency matrix (B[i, j] = causal coefficient from j to i) into a lavaan model syntax string. Non-zero elements become regression paths (xi ~ xj); NA elements (used by e.g. lingam_parce() to mark a latent confounder between two variables) become a residual covariance (xi ~~ xj) between the two machine-named variables, which is the standard lavaan idiom equivalent to a two-indicator latent common cause with one loading fixed (as used by the Python semopy-based original).

Usage

build_lavaan_model(B, var_names)

Arguments

B

adjacency matrix (machine names ⁠x0, x1, ...⁠ expected as row/column indices; the caller supplies names via var_names)

var_names

machine variable names, length ncol(B)

Value

character scalar, lavaan model syntax (possibly empty string)


Build the true adjacency matrix from edge specifications

Description

Build the true adjacency matrix from edge specifications

Usage

build_true_adjacency(var_names, from, to, coef)

Arguments

var_names

vector of variable names

from

vector of cause (source) variable names for the edges

to

vector of effect (target) variable names for the edges (same length as from)

coef

vector of edge coefficients (same length as from)

Value

adjacency matrix (p x p). m[to, from] = coef (row = to, col = from)


Unconditional non-Gaussianity statistic (tau)

Description

Unconditional non-Gaussianity statistic (tau)

Usage

calc_tau(k, pa, ch)

Arguments

k

moment degree

pa

candidate parent column

ch

candidate child column

Value

a single non-negative numeric statistic


Conditional non-Gaussianity statistics (tau), minimized over all conditioning subsets

Description

Per Wang & Drton (2020), the pruning statistic for a candidate variable is the minimum of the conditional tau statistic over every size-appropriate conditioning subset. Upstream HighDimDirectLiNGAM (cdt15/lingam) has a return mis-indented inside its loop over conditioning sets, so it only ever evaluates the first subset; this R port intentionally does NOT replicate that bug and instead evaluates every subset in cond_sets, so results differ numerically from the Python package (see dev/high-dim-direct-lingam-implementation.md).

Usage

calc_taus(Y, yty, pa, ch, k, cond_sets, an_sets)

Arguments

Y

data matrix

yty

cached Gram matrix t(Y) %*% Y

pa

index of the candidate parent variable (scalar)

ch

indices of candidate child variables

k

moment degree

cond_sets

list of conditioning sets (each an integer vector of 1-based column indices, always including last_root)

an_sets

list, parallel to cond_sets, of ancestor-candidate sets (conditioning-set variables excluded from the corresponding subset)

Value

numeric vector of length ncol(Y), minimum statistic per variable


Compute the total causal effect between two variables from an adjacency matrix

Description

Returns the sum of all path effects enumerated by find_all_paths(). Returns 0 if no path exists.

Usage

calculate_total_effect(adjacency_matrix, from_index, to_index)

Arguments

adjacency_matrix

Adjacency matrix (n x n). B[i,j] is the coefficient of j -> i.

from_index

Index of the cause variable (1-based)

to_index

Index of the effect variable (1-based)

Value

Total causal effect (scalar)


Check whether glmnet is available

Description

If it is not available, raise an error indicating which regression method required it.

Usage

check_glmnet_available(method)

Arguments

method

name of the regression method that requires glmnet (for the error message)


Check whether lavaan is available

Description

Check whether lavaan is available

Usage

check_lavaan_available()

Check that the 'mice' package is available

Description

Check that the 'mice' package is available

Usage

check_mice_available(context)

Arguments

context

Short description used in the error message


Check the stationarity of a fitted VAR-LiNGAM model

Description

Recovers the reduced-form VAR coefficients ⁠M_k = (I - B0)^{-1} B_k⁠ from the structural matrices and inspects the eigenvalues of the VAR companion matrix. The process is stationary when every eigenvalue lies strictly inside the unit circle (all moduli < 1); a modulus on or outside it signals a (near-)unit root, under which the VAR-LiNGAM estimates are unreliable.

Usage

check_var_stationarity(result, tol = 1)

Arguments

result

a VARLiNGAMResult from lingam_var()

tol

stationarity threshold for the eigenvalue moduli (default 1)

Value

a var_stationarity object (list) with moduli (sorted descending), max_modulus, is_stationary (logical), lags, and tol.

References

Stationarity diagnostics in the spirit of the VARLiNGAM R code of Moneta, A., Entner, D., Hoyer, P. O., & Coad, A. (2013), Oxford Bulletin of Economics and Statistics, 75(5), 705-730. https://sites.google.com/site/dorisentner/publications/VARLiNGAM

Examples

s <- generate_varlingam_sample(n = 1000, seed = 42)
m <- lingam_var(s$data, lags = 1, reg_method = "ols", prune = FALSE)
check_var_stationarity(m)

Residual matrix to diagnose for a VAR-LiNGAM model

Description

Returns the series targeted by the residual diagnostics: either the LiNGAM innovations ⁠e_t = (I - B0) n_t⁠ (the independent errors) or the reduced-form VAR residuals n_t. Shared by the normality tests and the QQ plot.

Usage

compute_varlingam_residuals(result, on = c("innovations", "var"))

Arguments

result

a VARLiNGAMResult

on

"innovations" or "var"

Value

residual matrix (n_obs x n_features), column names preserved


Signal a hook contract violation (imputer / cd_fit return value)

Description

A plain error, but always called from outside the per-iteration tryCatch() in bootstrap_with_imputation() (see validate_imputer_output() / validate_cd_fit_output() call sites there), so that a programming error in a user-supplied hook aborts the whole call immediately instead of being swallowed as a per-iteration stochastic estimation failure.

Usage

contract_violation(msg)

Arguments

msg

Error message


Create a BootstrapResult

Description

Create a BootstrapResult

Usage

create_bootstrap_result(
  adjacency_matrices,
  total_effects,
  resampled_indices = NULL,
  causal_orders = NULL
)

Arguments

adjacency_matrices

array (n_sampling x n_features x n_features)

total_effects

array (n_sampling x n_features x n_features)

resampled_indices

list of index vectors

causal_orders

matrix (n_sampling x n_features). Each row is the causal order of one sample.

Value

BootstrapResult (list with class attribute)


Create a VARBootstrapResult

Description

Create a VARBootstrapResult

Usage

create_var_bootstrap_result(
  adjacency_matrices,
  total_effects,
  lags,
  resampled_indices = NULL,
  causal_orders = NULL
)

Arguments

adjacency_matrices

list (length n_sampling); each element is a joined adjacency matrix (n_features x n_features*(1 + lags))

total_effects

array (n_sampling x n_features x n_features*(1 + lags))

lags

lag order used

resampled_indices

list of residual-index vectors (NULL allowed)

causal_orders

matrix (n_sampling x n_features) (NULL allowed)

Value

a VARBootstrapResult (list with class attribute)


Default causal-discovery fit: joint estimation via lingam_multi_group()

Description

Treats the imputed datasets as "groups" sharing a common causal order.

Usage

default_cd_fit(X_list, prior_knowledge, apply_prior_knowledge_softly)

Arguments

X_list

List of imputed datasets (one per repeat)

prior_knowledge

Prior knowledge matrix (NULL allowed)

apply_prior_knowledge_softly

Apply prior knowledge softly (logical)

Value

⁠list(causal_order = <integer vector>, adjacency_matrices = <list>)⁠


Default imputer: multiple imputation via mice::mice(method = "norm")

Description

The closest standard R equivalent of the upstream Python default (sklearn.impute.IterativeImputer(sample_posterior = TRUE), Bayesian linear regression chained equations with posterior sampling) is mice::mice(method = "norm") (Bayesian linear regression). Numeric values will not match the Python implementation; the multiple-imputation design is equivalent.

Usage

default_imputer(X_boot, n_repeats)

Arguments

X_boot

Bootstrap-resampled data (matrix, may contain NA)

n_repeats

Number of imputed datasets to generate

Value

A list of n_repeats complete numeric matrices


Difference of mutual information

Description

Difference of mutual information

Usage

diff_mutual_info(xi_std, xj_std, ri_j, rj_i)

Arguments

xi_std

Standardized xi

xj_std

Standardized xj

ri_j

Residual of xi regressed on xj

rj_i

Residual of xj regressed on xi

Value

Difference of mutual information


Maximum-entropy approximation of entropy

Description

Maximum-entropy approximation of entropy

Usage

entropy_approx(u)

Arguments

u

Input vector

Value

Approximate entropy value


Estimate the adjacency matrix from a causal order

Description

Estimate the adjacency matrix from a causal order

Usage

estimate_adjacency_matrix(
  X,
  causal_order,
  prior_knowledge = NULL,
  method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

original data

causal_order

causal order (vector of 1-based indices)

prior_knowledge

prior-knowledge matrix (NULL allowed)

method

regression method "ols" : ordinary least squares (default) "lasso" : LASSO regression (glmnet) "adaptive_lasso": Adaptive LASSO (two-stage) "ridge" : Ridge regression (glmnet)

lambda

LASSO penalty (NULL = automatic selection by cross-validation) "lambda.min" : minimum prediction error "lambda.1se" : 1SE rule (sparser) "AIC" : minimum AIC (no CV, fast) "BIC" : minimum BIC (no CV, fast, sparsest), default "oracle" : Adaptive LASSO only. Not usable with Ridge.

init_method

estimation method for the initial weights of Adaptive LASSO "ols" : ordinary least squares (default) "ridge" : Ridge regression

Value

adjacency matrix B (n_features x n_features)


Estimate the adjacency matrix by causal order using the n <= p route

Description

Estimate the adjacency matrix by causal order using the n <= p route

Usage

estimate_adjacency_matrix_high_dim_np(X, causal_order)

Arguments

X

original-scale data matrix

causal_order

integer vector, 1-based causal order

Value

adjacency matrix B (n_features x n_features)


Estimate the adjacency matrix from a ParceLiNGAM causal order

Description

causal_order is a list whose first element may be an unresolved block (length > 1); all remaining elements are length-1. Block members are never regression targets (their parents cannot be identified), but they are valid predictors for downstream variables. Pairs within the block are set to NA.

Usage

estimate_adjacency_matrix_parce(
  X,
  causal_order,
  prior_knowledge,
  method,
  lambda,
  init_method
)

Arguments

X

original (uncentered) data

causal_order

list as produced by lingam_parce()

prior_knowledge

prior-knowledge matrix (NULL allowed)

method

regression method

lambda

lambda selection

init_method

adaptive LASSO initial-weight method

Value

adjacency matrix B (n_features x n_features)


Estimate the total causal effects between all variables at once

Description

Estimate the total causal effects between all variables at once

Usage

estimate_all_total_effects(
  X,
  lingam_result,
  method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Original data (n_samples x n_features)

lingam_result

Return value of lingam_direct()

method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge")

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC")

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

Value

Matrix of total causal effects (n_features x n_features). Convention: TE[i, j] is the total causal effect from variable j to variable i (j -> i). Same index convention as the adjacency matrix adjacency_matrix. The sum of direct and indirect effects.

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

model <- LiNGAM_sample_1000$data |>
  lingam_direct(reg_method = "ols")

LiNGAM_sample_1000$data |>
  estimate_all_total_effects(model)

Estimate the total causal effect between two specified variables

Description

Estimate the total causal effect between two specified variables

Usage

estimate_total_effect(
  X,
  lingam_result,
  from_index,
  to_index,
  method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Original data (matrix or data.frame)

lingam_result

Return value of lingam_direct()

from_index

Cause variable (1-based index or variable name)

to_index

Effect variable (1-based index or variable name)

method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge"). Default is adaptive_lasso

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle"). Default is BIC

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

Value

Estimated total causal effect

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

model <- LiNGAM_sample_1000$data |>
  lingam_direct(reg_method = "ols")

LiNGAM_sample_1000$data |>
  estimate_total_effect(model, 4, 1)

Estimate the total causal effect between two variables (ParceLiNGAM)

Description

Analogous to estimate_total_effect(), but for lingam_parce() results, which may contain NA entries in the adjacency matrix.

Usage

estimate_total_effect_parce(
  X,
  parce_result,
  from_index,
  to_index,
  method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Original data (matrix or data.frame)

parce_result

Return value of lingam_parce()

from_index

Cause variable (1-based index or variable name)

to_index

Effect variable (1-based index or variable name)

method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge"). Default is adaptive_lasso

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle"). Default is BIC

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

Value

Estimated total causal effect, or NA (with a warning) if from_index is part of an unresolved block (its parents cannot be identified).

Examples

confounded <- generate_parce_sample(n = 500, seed = 1)
result <- lingam_parce(confounded$data, reg_method = "ols")

# A well-identified pair returns a numeric estimate
estimate_total_effect_parce(confounded$data, result, from_index = 1, to_index = 5)

Estimate the total causal effect between two variables (RCD)

Description

Analogous to estimate_total_effect(), but for lingam_rcd() results, which may contain NA entries in the adjacency matrix.

Usage

estimate_total_effect_rcd(
  X,
  rcd_result,
  from_index,
  to_index,
  method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Original data (matrix or data.frame)

rcd_result

Return value of lingam_rcd()

from_index

Cause variable (1-based index or variable name)

to_index

Effect variable (1-based index or variable name)

method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge"). Default is adaptive_lasso

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle"). Default is BIC

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

Value

Estimated total causal effect, or NA (with a warning) if from_index is part of a suspected latent confounder pair (its parents cannot be identified). Also warns (without altering the estimate) if to_index is an ancestor of from_index according to ancestors_list, since that is inconsistent with a from -> to effect.

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
result <- lingam_rcd(confounded$data)

# A well-identified pair returns a numeric estimate
estimate_total_effect_rcd(confounded$data, result, from_index = 6, to_index = 1)

Estimate a total causal effect in a VAR-LiNGAM model

Description

Estimates the total causal effect from from_index (optionally at lag from_lag) to to_index (at the current time) using the fitted VAR-LiNGAM model. Port of the Python reference estimate_total_effect: the destination variable is regressed on the source variable together with the source's parents (a back-door adjustment), and the source's coefficient is returned.

Usage

estimate_var_total_effect(X, result, from_index, to_index, from_lag = 0)

Arguments

X

original data (matrix or data frame), rows ordered in time

result

a VARLiNGAMResult from lingam_var()

from_index

source variable (1-based index or variable name)

to_index

destination variable (1-based index or variable name)

from_lag

lag of the source variable (0 = current time, default)

Value

the estimated total effect (scalar)

Examples

sample <- generate_varlingam_sample(n = 1000, seed = 42)
model <- lingam_var(sample$data, lags = 1, reg_method = "ols", prune = FALSE)

# total effect of x0 (current) on x2 (current)
estimate_var_total_effect(sample$data, model, from_index = 1, to_index = 3)

Evaluate model fit of an estimated causal graph

Description

Fits the causal graph implied by adjacency_matrix as a structural equation model (SEM) via lavaan::sem() and returns standard SEM fit measures (CFI, RMSEA, AIC/BIC, etc.). This is an R port of the Python lingam.utils.evaluate_model_fit(), which delegates to the Python package semopy; this R version delegates to lavaan instead.

Usage

evaluate_model_fit(adjacency_matrix, X, is_ordinal = NULL)

Arguments

adjacency_matrix

p x p numeric adjacency matrix (NA allowed for latent confounder pairs), or a lingamr result object (e.g. LingamResult, ParceLingamResult, LiMResult) with an adjacency_matrix element, from which the matrix is extracted automatically

X

numeric matrix or data frame (n_samples x p) with no missing values

is_ordinal

logical or 0/1 vector of length p. TRUE marks a variable as ordinal (categorical), fit with lavaan's WLSMV-based estimator. NULL (default) treats all variables as continuous.

Details

Value

A one-row data.frame of fit measures: DoF, DoF Baseline, chi2, chi2 p-value, chi2 Baseline, CFI, GFI, AGFI, NFI, TLI, RMSEA, AIC, BIC, LogLik. When is_ordinal is used, AIC/BIC/LogLik and some other measures are not defined by the WLSMV estimator and are returned as NA.

References

Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. doi:10.18637/jss.v048.i02

Examples

if (requireNamespace("lavaan", quietly = TRUE)) {
  dat <- generate_lingam_sample_6()
  result <- lingam_direct(dat$data, reg_method = "ols")
  evaluate_model_fit(result, dat$data)
}

Whether xi can be excluded from sink candidacy given the ancestor sets known so far

Description

Faithful port of the exclusion rule in rcd.py (original 165-174 lines): xi cannot be the sink of U if (a) xi is already known to be an ancestor of some other member of U, or (b) every other member of U is already known to be an ancestor of xi.

Usage

exists_ancestor_in_U(M, U, xi, xj_list)

Arguments

M

current ancestor-set list

U

variable-set under consideration (unused except via xj_list, kept for signature parity with the upstream port)

xi

candidate variable

xj_list

U minus xi

Value

TRUE if xi should be excluded from sink candidacy


Extract an adjacency matrix from a result object or matrix

Description

Extract an adjacency matrix from a result object or matrix

Usage

extract_adjacency_matrix(adjacency_matrix)

Extract the ancestor sets M(x_i) for every variable

Description

Faithful port of rcd.py's extract_ancestors() (original 254-316 lines). Repeatedly scans variable subsets of increasing size, growing each variable's ancestor set whenever a unique "sink" is found within a subset. See dev/rcd-implementation.md section 3.2 for the full algorithm description and the reasoning behind the cache-update position.

Usage

extract_ancestors(
  X,
  max_explanatory_num,
  cor_alpha,
  ind_alpha,
  shapiro_alpha,
  MLHSICR,
  independence,
  ind_corr
)

Arguments

X

(uncentered) data matrix

max_explanatory_num

maximum subset size minus 1

cor_alpha

correlation-test significance level

ind_alpha

independence-test significance level (hsic)

shapiro_alpha

non-Gaussianity significance level

MLHSICR

whether to use MLHSICR regression as a fallback

independence

"hsic" or "fcorr"

ind_corr

F-correlation rejection threshold (fcorr)

Value

list of length ncol(X); each element is a sorted integer vector of ancestor indices (possibly empty)


Extract parents from the ancestor sets

Description

Faithful port of rcd.py's extract_parents() (original 318-343 lines).

Usage

extract_parents(X, M, cor_alpha)

Arguments

X

(uncentered) data matrix

M

ancestor-set list from extract_ancestors()

cor_alpha

correlation-test significance level

Value

list of length ncol(X); each element is a sorted integer vector of parent indices (subset of the corresponding ancestor set)


Extract partial orders from prior knowledge

Description

Extract partial orders from prior knowledge

Usage

extract_partial_orders(pk)

Arguments

pk

Prior knowledge matrix (NaN = unknown)

Value

matrix (n x 2), each row is a (from, to) partial order


Detect variable pairs sharing an unobserved latent confounder

Description

Faithful port of rcd.py's extract_vars_sharing_confounders() (original 352-366 lines). Only pairs with no parent-child relationship in either direction are considered.

Usage

extract_vars_sharing_confounders(X, P, cor_alpha)

Arguments

X

(uncentered) data matrix

P

parent list from extract_parents()

cor_alpha

correlation-test significance level

Value

list of length ncol(X); each element is a sorted integer vector of indices sharing a latent confounder with that variable (symmetric)


F-correlation (kernel canonical correlation) between two variables

Description

Bach & Jordan (2002) kernel canonical correlation, as used by BottomUpParceLiNGAM's independence = "fcorr" option. Returns a value in (roughly) ⁠[0, 1]⁠; larger means more dependent.

Usage

f_correlation(x, y)

Arguments

x

numeric vector

y

numeric vector (same length as x)

Details

A constant x or y (zero variance) carries no dependence information and is treated as trivially independent (returns 0) rather than propagating a division-by-zero standardization into NaN/Inf.

Value

F-correlation value (scalar)


Low-rank SVD transform used inside f_correlation()

Description

Given the (already column-centered) incomplete-Cholesky factor G, returns the orthonormalized basis U and the shrinkage vector R used to assemble the block canonical-correlation matrix R_kappa.

Usage

fcorr_svd_transform(G, kappa, n)

Arguments

G

n x d centered incomplete-Cholesky factor

kappa

regularization parameter

n

sample size

Value

list(U = n x d' matrix, R = length d' vector); R has length 0 if no eigenvalue of crossprod(G) clears the kappa threshold (i.e. G carries no retainable rank), which callers must handle explicitly.


Enumerate all paths in a DAG via depth-first search

Description

Takes an adjacency matrix where B[i, j] represents j -> i, and returns all paths from from_index to to_index together with each path effect (the product of the coefficients).

Usage

find_all_paths(adjacency_matrix, from_index, to_index, min_causal_effect = 0)

Arguments

adjacency_matrix

Adjacency matrix (n x n). B[i,j] is the coefficient of j -> i.

from_index

Start index (1-based)

to_index

End index (1-based)

min_causal_effect

Coefficients at or below this threshold are treated as nonexistent edges

Value

list(paths, effects)


Find the most sink-like candidate variable

Description

Faithful port of ⁠_search_causal_order.find_exo_vec()⁠ (original 227-276 lines). For each candidate j in Uc, regresses j on the other candidates (setdiff(Uc, j), not U) and evaluates how independent the residual is from those explanatory variables.

Usage

find_exo_vec(X, Uc, U, independence, Cov)

Arguments

X

data matrix

Uc

candidate variable indices

U

all currently undetermined variable indices

independence

"hsic" or "fcorr"

Cov

precomputed stats::cov(X), since X is invariant across all calls within a single parce_search_causal_order() search

Value

list(m = selected variable index, eval = its evaluation value)


Adaptive LASSO

Description

Adaptive LASSO

Usage

fit_adaptive_lasso(
  y,
  Xp,
  lambda = "BIC",
  gamma_weight = 1,
  init_method = "ols"
)

Arguments

y

response variable

Xp

predictor matrix

lambda

lambda selection method ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle")

gamma_weight

exponent of the weights

init_method

estimation method for the initial weights ("ols" or "ridge")

Value

coefficient vector


LASSO regression (lambda selection by information criterion or CV)

Description

LASSO regression (lambda selection by information criterion or CV)

Usage

fit_lasso(y, Xp, lambda = "BIC")

Arguments

y

response variable

Xp

predictor matrix

lambda

lambda selection method "lambda.min" : minimum CV prediction error "lambda.1se" : CV 1SE rule "AIC" : minimum AIC "BIC" : minimum BIC, default

Value

coefficient vector


OLS regression

Description

OLS regression

Usage

fit_ols(y, Xp)

Arguments

y

response variable (numeric vector)

Xp

predictor matrix

Value

coefficient vector (excluding intercept)


OLS fit for a single predictor, pruned by information criterion

Description

glmnet requires at least two predictor columns, so the penalized methods fall back to OLS when only one predictor remains. Plain OLS never yields an exact zero, which would make single-predictor edges unprunable: the second variable in the causal order always has exactly one predictor, so a spurious edge would survive even for fully independent data. To preserve the sparse behavior of the penalized methods, the OLS coefficient is kept only when adding the predictor improves the information criterion over the intercept-only model; otherwise it is set to exactly zero.

Usage

fit_ols_ic_pruned(y, Xp, lambda)

Arguments

y

response variable (numeric vector)

Xp

single-column predictor matrix

lambda

lambda selection method of the calling fit

Details

The criterion is AIC for lambda = "AIC" and BIC otherwise (the CV / oracle lambdas have no single-predictor counterpart, so the sparsest criterion, BIC, is used for them as well).

Value

length-1 coefficient vector (0 when the predictor is pruned)


Penalized regression via glmnet (IC or CV lambda selection)

Description

Internal helper shared by fit_lasso() and fit_ridge_reg(). Both functions differ only in alpha and lambda_seq; this function encapsulates the duplicated IC / CV branches.

Usage

fit_penalized_regression(y, Xp_mat, alpha, lambda, lambda_seq)

Arguments

y

response variable (numeric vector)

Xp_mat

predictor matrix (already coerced to matrix)

alpha

glmnet mixing parameter: 1 = LASSO, 0 = Ridge

lambda

lambda selection method ("AIC", "BIC", "lambda.min", "lambda.1se")

lambda_seq

numeric vector of (relative) lambda values, scaled internally by lambda_scale_factor() to the response's natural scale before use

Value

coefficient vector (excluding intercept)


Ridge regression (lambda selection by information criterion or CV)

Description

Ridge regression (lambda selection by information criterion or CV)

Usage

fit_ridge_reg(y, Xp, lambda = "BIC")

Arguments

y

response variable

Xp

predictor matrix

lambda

lambda selection method "lambda.min" : minimum CV prediction error "lambda.1se" : CV 1SE rule "AIC" : minimum AIC "BIC" : minimum BIC, default "oracle" is not usable (Adaptive LASSO only).

Value

coefficient vector


Fit a VAR(p) model by OLS (no intercept)

Description

Fit a VAR(p) model by OLS (no intercept)

Usage

fit_var_ols(X, lags)

Arguments

X

numeric matrix (n_samples x n_features), rows ordered in time

lags

lag order (positive integer)

Value

list with coefs (array (lags, n_features, n_features); coefs[k, , ] is M_k such that ⁠X_t = sum_k M_k X_{t-k} + e_t⁠) and residuals (n_samples - lags, n_features)


Generate sample data for LiM (3 mixed variables)

Description

Generates a small dataset with a known causal chain of continuous and binary (0/1) discrete variables: x1 (continuous) -> x2 (discrete) -> x3 (continuous). Continuous variables use Laplace-distributed noise (non-Gaussian, as required by LiNGAM-family methods); the discrete variable is drawn from a Bernoulli distribution whose logit is a linear function of its parent.

Usage

generate_lim_sample(n = 1000L, seed = NULL)

Arguments

n

number of samples (default: 1000)

seed

random seed. If NULL (default), no seed is set and results are not reproducible across calls.

Value

A list with three elements:

Examples

dat <- generate_lim_sample(n = 500, seed = 1)
result <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
result$adjacency_matrix


Generate a challenging sample data for Direct LiNGAM

Description

Generates a dataset with conditions that make causal estimation difficult:

  1. High multicollinearity among predictors

  2. Moderate sample size relative to variables

  3. True coefficients of similar magnitude

Usage

generate_lingam_hard_sample(n = 200L, seed = 42L, collinearity = 0.95)

Arguments

n

number of samples (default: 200)

seed

random seed (default: 42)

collinearity

strength of multicollinearity (0 to 1, default: 0.95)

Details

These conditions destabilize OLS initial estimates in Adaptive LASSO, making Ridge-initialized Adaptive LASSO preferable.

Value

list(data, true_adjacency)

Examples

result <- generate_lingam_hard_sample()
result$true_adjacency
head(result$data)


Generate large-scale sample data to benchmark Direct LiNGAM scalability

Description

Generates a dataset with many variables to demonstrate the computational scalability difference between Direct LiNGAM and ICA-LiNGAM.

Usage

generate_lingam_large_sample(
  p = 20L,
  n = 1000L,
  max_parents = 3L,
  coef_min = 0.5,
  coef_max = 1.5,
  seed = 42L,
  noise_dist = "uniform"
)

Arguments

p

number of variables (default: 20)

n

number of observations (default: 1000)

max_parents

maximum number of parents per node (default: 3). Controls graph density. Each variable xi (i >= 1) receives between 1 and min(max_parents, i) parents drawn from x0, ..., x(i-1).

coef_min

minimum absolute value of edge coefficients (default: 0.5)

coef_max

maximum absolute value of edge coefficients (default: 1.5)

seed

random seed (default: 42)

noise_dist

error term distribution. "uniform" : Uniform(0, 1) - default, non-Gaussian (LiNGAM works well) "gaussian" : Normal(0, 1) - LiNGAM may fail "lognormal" : Log-normal(0, 1) - skewed, non-Gaussian "exponential" : Exponential(1) - skewed, non-Gaussian "t3" : t-distribution (df=3) - heavy tails

Details

Why Direct LiNGAM slows down with large p

At each of its p steps, Direct LiNGAM evaluates an independence measure between every remaining candidate root and every other residual. The total number of evaluations is:

\sum_{k=1}^{p} k(k-1) \approx \frac{p^3}{3}

i.e., O(p^3). Each evaluation is itself O(n), giving O(p^3 n) overall. For p = 10 this is about 330 evaluations; for p = 20 about 2,660; for p = 40 about 21,320 — an 8x increase every time p doubles.

Why ICA-LiNGAM scales better

ICA-LiNGAM applies FastICA once to the whole p x n data matrix. Each FastICA iteration costs O(p^2 n), and the algorithm typically converges in far fewer than p iterations. Additionally, these matrix operations are fully vectorised (BLAS/LAPACK), whereas Direct LiNGAM iterates over pairs in an R loop.

Data-generating process

Variables are topologically ordered as x0, x1, ..., x(p-1). For each i >= 1, the number of parents is sampled uniformly from 1 to min(max_parents, i), and the parents are drawn without replacement from x0, ..., x(i-1). Edge coefficients are drawn uniformly from [-coef_max, -coef_min] U [coef_min, coef_max]. The resulting adjacency matrix is strictly lower-triangular.

Value

A list with three elements:

Examples

# Generate 20-variable data and check its sparsity
dataset <- generate_lingam_large_sample(p = 20, n = 500)
dim(dataset$data)                    # 500 x 20
sum(dataset$true_adjacency != 0)     # number of edges
dataset$true_causal_order            # 0, 1, ..., 19


# As the number of variables grows, Direct LiNGAM's run time increases sharply
t10 <- system.time(lingam_direct(generate_lingam_large_sample(p = 10)$data))
t20 <- system.time(lingam_direct(generate_lingam_large_sample(p = 20)$data))
cat(sprintf("p=10: %.1f sec,  p=20: %.1f sec\n", t10["elapsed"], t20["elapsed"]))



Generate Paradoxical Data Where DirectLiNGAM Struggles

Description

Generates a synthetic dataset designed to favor ICA-LiNGAM (due to standardized scales) while challenging DirectLiNGAM (due to heavy measurement noise on the root variable, which triggers error propagation). The true causal structure is a serial chain: x0 -> x1 -> x2 -> x3 (each coefficient 0.8).

Usage

generate_lingam_paradox_data(n = 2000L, seed = 42L)

Arguments

n

number of samples (default: 2000)

seed

random seed (default: 42)

Details

This function intentionally injects strong measurement error into the root (causal upstream) variable x0. This noise corrupts the independence tests performed at the initial step of DirectLiNGAM, frequently causing it to misidentify the root variable and leading to a cascading failure (error propagation) throughout the causal ordering.

On the other hand, the output data is completely standardized using the scale() function. This eliminates any differences in scale among the variables, thereby neutralizing the major weakness of ICA-LiNGAM (scale-dependence) and allowing it to perform relatively better.

Because the data are standardized and the root carries measurement error, the coefficients estimated by lingam_direct() will not exactly match the 0.8 values stored in true_adjacency.

Value

list(data, true_adjacency)

Examples

# Generate the dataset
paradox <- generate_lingam_paradox_data(n = 1000, seed = 123)

# Verify the dataset
head(paradox$data)
sapply(paradox$data, sd)

# True data-generating structure
paradox$true_adjacency


Generate 10-variable sample data for Direct LiNGAM

Description

Generates a sample dataset with a known causal structure. The true causal structure is: x3 -> x0 (coef = 3.0) x3 -> x2 (coef = 6.0) x3 -> x9 (coef = 7.0) x0 -> x1 (coef = 3.0) x0 -> x5 (coef = 4.0) x0 -> x4 (coef = 8.0) x0 -> x7 (coef = 3.0) x2 -> x1 (coef = 2.0) x2 -> x4 (coef = -1.0) x2 -> x8 (coef = 0.5) x1 -> x6 (coef = 2.0) x5 -> x8 (coef = 2.0) x4 -> x7 (coef = 1.5) x6 -> x9 (coef = 1.0)

Usage

generate_lingam_sample_10(n = 1000L, seed = 42L, noise_dist = "uniform")

Arguments

n

number of samples (default: 1000)

seed

random seed (default: 42)

noise_dist

error term distribution "uniform" : Uniform(0, 1) - default, non-Gaussian (LiNGAM works well) "gaussian" : Normal(0, 1) - LiNGAM may fail "lognormal" : Log-normal(0, 1) - skewed, non-Gaussian "exponential" : Exponential(1) - skewed, non-Gaussian "t3" : t-distribution (df=3) - heavy tails

Value

list(data, true_adjacency)

Examples

# Non-Gaussian (LiNGAM works well)
X_nongauss <- generate_lingam_sample_10(noise_dist = "uniform")
result <- lingam_direct(X_nongauss$data, reg_method = "ols")
result$causal_order

# Gaussian (LiNGAM may fail)
X_gauss <- generate_lingam_sample_10(noise_dist = "gaussian")
result <- lingam_direct(X_gauss$data, reg_method = "ols")
result$causal_order


Generate sample data for Direct LiNGAM (6 variables)

Description

Generates a sample dataset with a known causal structure. The true causal structure is: x3 -> x0 (coef = 3.0) x3 -> x2 (coef = 6.0) x0 -> x1 (coef = 3.0) x2 -> x1 (coef = 2.0) x0 -> x5 (coef = 4.0) x0 -> x4 (coef = 8.0) x2 -> x4 (coef = -1.0)

Usage

generate_lingam_sample_6(n = 1000L, seed = 42L, noise_dist = "uniform")

Arguments

n

number of samples (default: 1000)

seed

random seed (default: 42)

noise_dist

error term distribution "uniform" : Uniform(0, 1) - default, non-Gaussian (LiNGAM works well) "gaussian" : Normal(0, 1) - LiNGAM may fail "lognormal" : Log-normal(0, 1) - skewed, non-Gaussian "exponential" : Exponential(1) - skewed, non-Gaussian "t3" : t-distribution (df=3) - heavy tails

Value

list(data, true_adjacency)

Examples

# Non-Gaussian (LiNGAM works well)
X_nongauss <- generate_lingam_sample_6(noise_dist = "uniform")
result <- lingam_direct(X_nongauss$data, reg_method = "ols")
result$causal_order

# Gaussian (LiNGAM may fail)
X_gauss <- generate_lingam_sample_6(noise_dist = "gaussian")
result <- lingam_direct(X_gauss$data, reg_method = "ols")
result$causal_order


Generate sample data for Multi-Group Direct LiNGAM (2 groups, 6 variables)

Description

Generates two datasets that share the same causal structure as generate_lingam_sample_6() (⁠x3 -> x0, x3 -> x2, x0 -> x1, x2 -> x1, x0 -> x4, x2 -> x4, x0 -> x5⁠) but with different structural coefficients per group, following the multi-dataset tutorial's setup.

Usage

generate_multi_group_sample(n = c(1000, 1000), seed = 42L)

Arguments

n

Numeric vector of length 2: sample size per group (default c(1000, 1000)).

seed

Random seed (default 42). Group 2 uses an internally offset seed so the two groups are independently drawn.

Value

A list with:

Examples

mg <- generate_multi_group_sample()
lapply(mg$data_list, head)
mg$adjacency_matrices$group1

Generate a noise matrix with an independent seed per variable

Description

Column k is generated by noise_fn(n) immediately after set.seed(seed + k - 1). Fixing the seed per variable ensures that the same seed always yields the same noise columns.

Usage

generate_noise_matrix(n, n_vars, seed, noise_fn)

Arguments

n

sample size

n_vars

number of variables (columns)

seed

base seed. Column k uses seed + k - 1

noise_fn

noise generation function of the form ⁠function(n)⁠

Value

noise matrix (n x n_vars)


Generate sample data with a latent confounder (for BottomUpParceLiNGAM)

Description

Generates the 7-variable model used in the ParceLiNGAM tutorial, where x6 is an unobserved (latent) common cause of x2 and x3. Only x0-x5 are returned as observed data; x6 is not included.

Usage

generate_parce_sample(n = 1000L, seed = NULL)

Arguments

n

number of samples (default: 1000)

seed

random seed (default: NULL, i.e. do not reset the RNG state)

Details

The data-generating process (all error terms are Uniform(0, 1)):

x6 (latent) ~ Uniform(0, 1)
x3 = 2.0 * x6 + e
x2 = 2.0 * x6 + e
x0 = 0.5 * x3 + e
x1 = 0.5 * x0 + 0.5 * x2 + e
x5 = 0.5 * x0 + e
x4 = 0.5 * x0 - 0.5 * x2 + e

Value

list with three elements:

Examples

confounded <- generate_parce_sample(n = 500, seed = 42)
head(confounded$data)
confounded$adjacency_matrix
confounded$confounded_pair

Generate sample data with a latent confounder (for RCD)

Description

Generates the 7-variable model used in the RCD tutorial, where x6 is an unobserved (latent) common cause of x2 and x4. Only x0-x5 are returned as observed data; x6 is not included.

Usage

generate_rcd_sample(n = 300L, seed = NULL)

Arguments

n

number of samples (default: 300)

seed

random seed (default: NULL, i.e. do not reset the RNG state)

Details

The data-generating process (all error terms e() are super-Gaussian, rnorm(n, 0, 0.5)^3):

x5 ~ e();  x6 (latent) ~ e()
x1 = 0.6 * x5 + e()
x3 = 0.5 * x5 + e()
x0 = 1.0 * x1 + 1.0 * x3 + e()
x2 = 0.8 * x0 - 0.6 * x6 + e()
x4 = 1.0 * x0 - 0.5 * x6 + e()

Value

list with four elements:

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
head(confounded$data)
confounded$adjacency_matrix
confounded$ancestors_list
confounded$confounded_pair

Generate sample data from a VAR-LiNGAM model

Description

Generates a 3-variable time series following a VAR-LiNGAM model with a strictly acyclic instantaneous structure B0, a lag-1 coefficient matrix M1, and non-Gaussian (uniform) errors.

Usage

generate_varlingam_sample(n = 1000, seed = NULL)

Arguments

n

number of time points to return (after burn-in)

seed

random seed (NULL allowed)

Value

list with data (data frame, n x 3), true_B0 (instantaneous matrix), and true_M1 (lag-1 coefficient matrix)

Examples

sample <- generate_varlingam_sample(n = 500, seed = 1)
head(sample$data)

Create an adjacency matrix of representative causal-effect values from bootstrap results

Description

Create an adjacency matrix of representative causal-effect values from bootstrap results

Usage

get_adjacency_matrix_summary(
  result,
  stat = "median",
  min_causal_effect = NULL,
  min_probability = NULL,
  labels = NULL
)

Arguments

result

BootstrapResult object

stat

Representative statistic ("mean" or "median")

min_causal_effect

Minimum threshold for the causal effect (values at or below this are treated as zero) (NULL = 0)

min_probability

Edges below this probability are set to zero (NULL = 0)

labels

Vector of variable names (NULL allowed)

Value

Adjacency matrix (n_features x n_features). Rule: B[i, j] is the causal coefficient from variable j to variable i (j -> i). Same rule as the adjacency_matrix of lingam_direct().

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)
get_adjacency_matrix_summary(bs_model)

Get counts, proportions, and causal effects of causal directions

Description

Get counts, proportions, and causal effects of causal directions

Usage

get_causal_direction_counts(
  result,
  n_directions = NULL,
  min_causal_effect = NULL,
  split_by_causal_effect_sign = FALSE,
  labels = NULL
)

Arguments

result

BootstrapResult object

n_directions

How many of the top entries to return (NULL = all)

min_causal_effect

Minimum threshold for the causal effect (NULL = 0)

split_by_causal_effect_sign

Whether to split by the sign of the causal effect

labels

Vector of variable names (NULL allowed; if provided, adds from_name and to_name columns)

Value

A data frame containing the following columns:

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)

get_causal_direction_counts(bs_model, labels = names(LiNGAM_sample_1000$data))

Evaluate the stability of the causal order from bootstrap

Description

Aggregates the causal order (causal_order) estimated in each bootstrap sample and quantifies how stable the order is. Returns the rank distribution of each variable, the precedence probabilities for variable pairs, and an overall stability score.

Usage

get_causal_order_stability(result, labels = NULL)

Arguments

result

A BootstrapResult object (run with the current version)

labels

A vector of variable names (if NULL, x0, x1, ... are generated automatically)

Value

A list of class causal_order_stability, containing:

Examples

dat <- generate_lingam_sample_6()
bs <- lingam_direct_bootstrap(dat$data, n_sampling = 30L, reg_method = "ols", seed = 42)
get_causal_order_stability(bs, labels = names(dat$data))

Get DAG counts

Description

Get DAG counts

Usage

get_directed_acyclic_graph_counts(
  result,
  n_dags = NULL,
  min_causal_effect = NULL,
  split_by_causal_effect_sign = FALSE
)

Arguments

result

BootstrapResult object

n_dags

How many of the top entries to return (NULL = all)

min_causal_effect

Minimum threshold for the causal effect (NULL = 0)

split_by_causal_effect_sign

Whether to split by the sign of the causal effect

Value

list(dag = list of data.frames, count = integer vector)

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)

get_directed_acyclic_graph_counts(bs_model)

Compute p-values for the independence test of the errors

Description

Compute p-values for the independence test of the errors

Usage

get_error_independence_p_values(X, lingam_result, method = "spearman")

Arguments

X

original data (matrix or data.frame)

lingam_result

return value of lingam_direct()

method

type of correlation coefficient ("spearman", "pearson", "kendall"). "kendall" uses the O(n^2)-per-pair algorithm in stats::cor.test(); for large n (beyond 5000) this warns, and "spearman" is a much faster alternative with similar rank-based semantics.

Value

matrix of p-values (n_features x n_features)

Examples

# Load the sample data
LiNGAM_sample_1000 <- generate_lingam_sample_6()

# Run Direct LiNGAM
result <- LiNGAM_sample_1000$data |>
  lingam_direct(reg_method = "ols")

# Compute p-values (default: Spearman)
p_vals <- get_error_independence_p_values(LiNGAM_sample_1000$data, result)
round(p_vals, 3)

# Compute with Kendall
p_vals_k <- get_error_independence_p_values(LiNGAM_sample_1000$data, result, method = "kendall")
round(p_vals_k, 3)

Compute p-values for the independence of ParceLiNGAM residuals (HSIC-based)

Description

Analogous to get_error_independence_p_values(), but for lingam_parce() results. Uses the HSIC gamma-approximation test (hsic_test_gamma()) rather than a correlation test, and returns NA for any pair involving a variable whose row or column in the adjacency matrix contains NA (residuals cannot be computed for those variables).

Usage

get_error_independence_p_values_parce(X, parce_result)

Arguments

X

Original data (matrix or data.frame)

parce_result

Return value of lingam_parce()

Value

matrix of p-values (n_features x n_features)

Examples

confounded <- generate_parce_sample(n = 500, seed = 1)
result <- lingam_parce(confounded$data, reg_method = "ols")
round(get_error_independence_p_values_parce(confounded$data, result), 3)

Compute p-values for the independence of RCD residuals (HSIC-based)

Description

Analogous to get_error_independence_p_values_parce(), but for lingam_rcd() results. Returns NA for any pair involving a variable whose row or column in the adjacency matrix contains NA (residuals cannot be computed for those variables).

Usage

get_error_independence_p_values_rcd(X, rcd_result)

Arguments

X

Original data (matrix or data.frame)

rcd_result

Return value of lingam_rcd()

Value

matrix of p-values (n_features x n_features)

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
result <- lingam_rcd(confounded$data)
round(get_error_independence_p_values_rcd(confounded$data, result), 3)

Extract a single group's result from a MultiGroupLingamResult

Description

Returns the adjacency matrix and (shared) causal order of one group as a plain LingamResult, so that the existing single-group functions (estimate_total_effect(), estimate_all_total_effects(), get_error_independence_p_values(), plot_adjacency(), autoplot(), tidy()) can be applied to it directly.

Usage

get_group_result(x, group)

Arguments

x

A MultiGroupLingamResult, as returned by lingam_multi_group().

group

Group name (character) or 1-based group index (integer).

Value

A LingamResult object (list) with adjacency_matrix and causal_order, identical in shape to the return value of lingam_direct().

Examples

mg <- generate_multi_group_sample()
res <- lingam_multi_group(mg$data_list, reg_method = "ols")
g1 <- get_group_result(res, 1)
class(g1)

Get all paths between two specified variables and their bootstrap probabilities

Description

Get all paths between two specified variables and their bootstrap probabilities

Usage

get_paths(result, from_index, to_index, min_causal_effect = NULL)

Arguments

result

BootstrapResult object

from_index

Start index (1-based)

to_index

End index (1-based)

min_causal_effect

Minimum threshold for the causal effect (NULL = 0)

Value

data.frame (path, effect, probability)

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)
get_paths(bs_model, 1, 6)

Get bootstrap probabilities

Description

Get bootstrap probabilities

Usage

get_probabilities(result, min_causal_effect = NULL)

Arguments

result

BootstrapResult object

min_causal_effect

Minimum threshold for the causal effect (NULL = 0)

Value

Probability matrix (n_features x n_features)

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)

get_probabilities(bs_model)

Enumerate conditioning subsets and compute pruning statistics for one candidate variable

Description

Enumerate conditioning subsets and compute pruning statistics for one candidate variable

Usage

get_prune_stats(Y, yty, i, j, K, last_root, condition_set, J)

Arguments

Y

data matrix

yty

cached Gram matrix t(Y) %*% Y

i

candidate variable (scalar, 1-based index)

j

current candidate set (psi; i is removed internally)

K

moment degree

last_root

most recently fixed causal-order variable, or NULL on the first iteration

condition_set

conditioning-set variables (already includes last_root when non-empty)

J

assumed largest in-degree

Value

numeric vector of length ncol(Y)


Get a list of total causal effects

Description

Get a list of total causal effects

Usage

get_total_causal_effects(result, min_causal_effect = NULL)

Arguments

result

BootstrapResult object

min_causal_effect

Minimum threshold for the causal effect (NULL = 0)

Value

data.frame (from, to, effect, probability)

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)

get_total_causal_effects(bs_model)

Get variable names, falling back to x0, x1, ... when colnames is NULL

Description

Get variable names, falling back to x0, x1, ... when colnames is NULL

Usage

get_var_names(x)

Enumerate bootstrap paths between two variables in a VAR-LiNGAM model

Description

Builds the time-expanded graph for every bootstrap sample and enumerates all directed paths from the source (at from_lag) to the destination (at to_lag), reporting each path's bootstrap probability and median effect. Port of the Python reference VARBootstrapResult.get_paths.

Usage

get_var_paths(
  result,
  from_index,
  to_index,
  from_lag = 0,
  to_lag = 0,
  min_causal_effect = NULL
)

Arguments

result

a VARBootstrapResult object

from_index

source variable (1-based)

to_index

destination variable (1-based)

from_lag

lag of the source (default 0)

to_lag

lag of the destination (default 0); must satisfy to_lag <= from_lag

min_causal_effect

minimum |effect| threshold (NULL = 0)

Details

Node indices in the returned path are 1-based positions in the time-expanded graph: column j of block L (lag L) corresponds to index n_features * L + j.

Value

a data frame (path, effect, probability), one row per distinct path

Examples

s <- generate_varlingam_sample(n = 500, seed = 42)
bs <- lingam_var_bootstrap(s$data,
  n_sampling = 10L, criterion = NULL,
  reg_method = "ols", prune = FALSE, seed = 1, verbose = FALSE
)
get_var_paths(bs, from_index = 1, to_index = 3)

Bootstrap probabilities for a VAR-LiNGAM model

Description

Returns, for each entry of the joined adjacency matrix, the fraction of bootstrap samples in which that edge exceeded min_causal_effect.

Usage

get_var_probabilities(result, min_causal_effect = NULL)

Arguments

result

a VARBootstrapResult object

min_causal_effect

minimum |effect| threshold (NULL = 0)

Value

probability matrix (n_features x n_features*(1 + lags)). Columns 1..n_features are the instantaneous block; the next n_features are lag 1; etc. P[i, j] is the probability of the edge j -> i.

Examples

s <- generate_varlingam_sample(n = 500, seed = 42)
bs <- lingam_var_bootstrap(s$data,
  n_sampling = 10L, criterion = NULL,
  reg_method = "ols", prune = FALSE, seed = 1, verbose = FALSE
)
get_var_probabilities(bs)

Get a one-row summary of a LiMResult

Description

Like glance.LingamResult(), with an additional n_discrete column giving the number of discrete variables in the model.

Usage

## S3 method for class 'LiMResult'
glance(x, ...)

Arguments

x

The return value of lingam_lim() (a LiMResult object)

...

Unused

Value

A one-row data.frame(n_variables, n_edges, n_discrete, causal_order)

Examples

set.seed(1)
dat <- generate_lim_sample(n = 300)
model <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
glance(model)

Get a one-row summary of a LingamResult

Description

Summarizes the entire model in a single row. The data X is not required because no residuals are computed. If residual-based diagnostics are needed, use summary_lingam() instead.

Usage

## S3 method for class 'LingamResult'
glance(x, ...)

Arguments

x

The return value of lingam_direct() (a LingamResult object)

...

Unused

Value

A one-row data.frame(n_variables, n_edges, causal_order)

Examples

dat <- generate_lingam_sample_6()
model <- lingam_direct(dat$data, reg_method = "ols")
glance(model)

Get a one-row summary of a MultiGroupLingamResult

Description

Summarizes the joint model in a single row. The causal order is shared across groups; per-group edge counts are available via glance(get_group_result(x, i)).

Usage

## S3 method for class 'MultiGroupLingamResult'
glance(x, ...)

Arguments

x

The return value of lingam_multi_group() (a MultiGroupLingamResult object)

...

Unused

Value

A one-row data.frame(n_groups, n_variables, causal_order)

Examples

mg <- generate_multi_group_sample()
model <- lingam_multi_group(mg$data_list, reg_method = "ols")
glance(model)

Get a one-row summary of a ParceLingamResult

Description

Like glance.LingamResult(). n_edges counts non-NA edges only, and n_na_entries counts the adjacency-matrix entries left NA (unresolved order / suspected latent confounding). Unresolved blocks in the causal order are shown in parentheses, as in the print method.

Usage

## S3 method for class 'ParceLingamResult'
glance(x, ...)

Arguments

x

The return value of lingam_parce() (a ParceLingamResult object)

...

Unused

Value

A one-row data.frame(n_variables, n_edges, n_na_entries, causal_order)

Examples

dat <- generate_parce_sample(n = 500, seed = 42)
model <- lingam_parce(dat$data)
glance(model)

Get a one-row summary of an RCDResult

Description

Like glance.LingamResult(), but without a causal order (RCD does not estimate one). n_edges counts non-NA edges only, and n_confounded_pairs counts the variable pairs whose adjacency-matrix entries are NA (suspected shared latent confounder).

Usage

## S3 method for class 'RCDResult'
glance(x, ...)

Arguments

x

The return value of lingam_rcd() (an RCDResult object)

...

Unused

Value

A one-row data.frame(n_variables, n_edges, n_confounded_pairs)

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
model <- lingam_rcd(confounded$data)
glance(model)

Causal-order search for HighDimDirectLiNGAM

Description

Causal-order search for HighDimDirectLiNGAM

Usage

high_dim_causal_order(X, J, K, alpha)

Arguments

X

data matrix (n_samples x n_features)

J

assumed largest in-degree

K

moment degree

alpha

pruning cutoff coefficient

Value

integer vector, 1-based causal order (upstream-most first)


Gaussian Gram matrix and its double-centered version

Description

Gaussian Gram matrix and its double-centered version

Usage

hsic_gram_matrix(x, width)

Arguments

x

numeric vector

width

kernel width from hsic_kernel_width()

Value

list(K = Gram matrix, Kc = centered Gram matrix)


Median-heuristic kernel width for HSIC

Description

Uses only the first 100 points (not a random subsample) to keep the O(n^2) pairwise-distance computation cheap, matching the upstream implementation exactly.

Usage

hsic_kernel_width(x)

Arguments

x

numeric vector

Value

kernel width (scalar)


HSIC independence test with gamma approximation

Description

Faithful port of hsic_test_gamma() (hsic.py). O(n^2) in the sample size because it forms the full n x n Gram matrices; not recommended for n in the thousands.

Usage

hsic_test_gamma(X, Y)

Arguments

X

numeric vector

Y

numeric vector (same length as X)

Details

The gamma-approximation variance estimator is only defined for n >= 6 (its closed form divides by (n-1)(n-2)(n-3)); below that this errors instead of silently returning a NaN p-value that would otherwise propagate into NA-valued rejection decisions in callers. A constant input (zero variance) carries no dependence information, so it is treated as trivially independent (p = 1) rather than routed through the degenerate kernel-width / centered-Gram-matrix computation.

Value

list(stat = HSIC test statistic, p = gamma-approximated p-value)


Select lambda by information criterion

Description

Select lambda by information criterion

Usage

ic_glmnet(glmnet_model)

Arguments

glmnet_model

a glmnet model object

Value

list with lambda_AIC_best, lambda_BIC_best, idx_AIC_best, idx_BIC_best, ic_table


Pivoted incomplete Cholesky decomposition of a Gaussian kernel matrix, as used by f_correlation()

Description

Same greedy pivoted algorithm as incomplete_cholesky_gauss() (search_causal_order.r), but with the stopping rule used by the upstream ⁠_f_correlation.py⁠: continue while the sum of the remaining diagonal residuals exceeds tol (no rank cap), rather than stopping once the single largest residual drops below a fixed tolerance.

Usage

incomplete_cholesky_fcorr(x, sigma, tol)

Arguments

x

input vector (length n)

sigma

width of the Gaussian kernel

tol

stop once the sum of the remaining diagonal residuals is at or below this

Value

n x d matrix G with ⁠tcrossprod(G) ~= K⁠


Gaussian kernel via pivoted incomplete Cholesky

Description

Low-rank approximation G (n x d) with ⁠tcrossprod(G) ~= K⁠, where K[i, j] = exp(-(x[i] - x[j])^2 / (2*sigma^2)), via the greedy pivoted incomplete Cholesky of Fine & Scheinberg (2001) / Bach & Jordan (2002, kernel-ICA). Each step picks the index with the largest diagonal residual and computes only the kernel column for that pivot, so the full n x n Gram matrix is never formed. The Gaussian kernel's diagonal is 1, so residuals start at 1 without evaluating K.

Usage

incomplete_cholesky_gauss(
  x,
  sigma,
  tol = 1e-04,
  max_rank = min(length(x), 200)
)

Arguments

x

Input vector (length n)

sigma

Width of the Gaussian kernel

tol

Stop once the largest remaining diagonal residual is at or below this

max_rank

Upper bound on the approximation rank

Value

n x d matrix G with ⁠tcrossprod(G) ~= K⁠


Whether the OLS (or MLHSICR) residual of xi on xj_list is independent of every xj

Description

Faithful port of rcd.py's is_independent() helper (original 226-252 lines).

Usage

is_independent_of_resid(
  Y,
  xi,
  xj_list,
  MLHSICR,
  independence,
  ind_alpha,
  ind_corr
)

Arguments

Y

residual matrix (from extract_ancestors())

xi

candidate sink variable

xj_list

explanatory-variable indices

MLHSICR

whether to retry with mlhsicr_regression() on failure

independence

"hsic" or "fcorr"

ind_alpha

significance level (hsic only)

ind_corr

rejection threshold (fcorr only)

Value

TRUE if independent


Kernel-based mutual information: core

Description

The target quantity is the difference of logdets of 2n x 2n matrices, but via the block structure and the Schur complement it can be computed equivalently using only an n x n Cholesky decomposition: ⁠MI = -1/2 * (logdet(tmp2^2 - K2 K1 tmp1^-2 K1 K2) - logdet(tmp2^2))⁠

Usage

kernel_mi_core(E1, x2, kappa, sigma)

Arguments

E1

Variable-1 matrix precomputed by kernel_mi_prepare()

x2

Vector of variable 2

kappa

Regularization parameter

sigma

Width of the Gaussian kernel

Value

Mutual information


Kernel-based mutual information: low-rank core

Description

Low-rank counterpart of kernel_mi_core(). With ⁠K2 ~= G2 %*% t(G2)⁠, both S = tmp2^2 - t(W) %*% W and tmp2^2 reduce to c0^2*I + G2 %*% C %*% t(G2) for a d2 x d2 matrix C, via the Woodbury identity on W and the matrix determinant lemma on the resulting rank-d2 update. The n*log(c0) terms in logdet(S) and logdet(tmp2^2) cancel in their difference, so only d2 x d2 matrices remain.

Usage

kernel_mi_core_lowrank(prep1, x2, kappa, sigma)

Arguments

prep1

Output of kernel_mi_prepare_lowrank() for variable 1

x2

Vector of variable 2

kappa

Regularization parameter

sigma

Width of the Gaussian kernel

Value

Mutual information


Kernel-based mutual information: precomputation for variable 1

Description

Computes the matrix ⁠E1 = tmp1^-1 K1⁠ (tmp1 = K1 + n*kappa/2 * I) used in kernel_mi_core(). It only needs to be called once per candidate variable, avoiding per-pair recomputation.

Usage

kernel_mi_prepare(x, kappa, sigma)

Arguments

x

Vector of variable 1

kappa

Regularization parameter

sigma

Width of the Gaussian kernel

Value

Matrix E1 (n x n)


Kernel-based mutual information: low-rank precomputation for variable 1

Description

Low-rank counterpart of kernel_mi_prepare(). Via the Woodbury identity, ⁠E1 = tmp1^-1 K1⁠ collapses to G1 %*% M1^-1 %*% t(G1) where M1 = c0*I + t(G1) %*% G1, so the n x n matrix E1 never needs to be formed; only the d x d inverse M1^-1 does.

Usage

kernel_mi_prepare_lowrank(x, kappa, sigma)

Arguments

x

Vector of variable 1

kappa

Regularization parameter

sigma

Width of the Gaussian kernel

Value

list(G, Minv, A, c0) describing E1 in factored form


Kurtosis (divided by n; excess kurtosis, which is 0 for a normal distribution)

Description

Kurtosis (divided by n; excess kurtosis, which is 0 for a normal distribution)

Usage

kurtosis_pop(x)

Arguments

x

numeric vector


Scale factor used to make the (otherwise fixed, absolute) lambda search grids adapt to the response's natural scale.

Description

lasso_lambda_seq / ridge_lambda_seq are fixed absolute grids. Because glmnet's standardize = TRUE only standardizes the predictors (not the response y), the penalty strength needed for meaningful shrinkage scales with the magnitude of y. Without this scaling, multiplying the whole input data by a constant changes which edges the default adaptive_lasso + lambda = "BIC"/"AIC" pipeline selects, even though the underlying relationships are identical up to that constant.

Usage

lambda_scale_factor(y)

Arguments

y

response variable (numeric vector)

Value

a positive scale factor


Map lavaan fitMeasures() to the semopy-style column set

Description

Map lavaan fitMeasures() to the semopy-style column set

Usage

lavaan_fit_measures_to_df(fit)

Convert the doubled parameter vector (length 2dd) into a d x d matrix W

Description

Mirrors Python's ⁠w[:d*d].reshape([d, d])⁠ (row-major reshape), so w and the reverse operation lim_flatten_rowmajor() must stay consistent.

Usage

lim_adj(w, d)

BIC-penalized DAG score (sign-flipped, i.e. a "loss") used during the local search phase. W is interpreted as a 0/1 skeleton in the i -> j orientation (parents of j are the nonzero rows of column j).

Description

BIC-penalized DAG score (sign-flipped, i.e. a "loss") used during the local search phase. W is interpreted as a 0/1 skeleton in the i -> j orientation (parents of j are the nonzero rows of column j).

Usage

lim_bic_loss(W, X, is_continuous)

Flatten a matrix in row-major (numpy "C") order

Description

Flatten a matrix in row-major (numpy "C") order

Usage

lim_flatten_rowmajor(M)

Global (NOTEARS-style) optimization phase: augmented-Lagrangian outer loop with L-BFGS-B inner solves. Returns the thresholded W (i -> j orientation).

Description

Global (NOTEARS-style) optimization phase: augmented-Lagrangian outer loop with L-BFGS-B inner solves. Returns the thresholded W (i -> j orientation).

Usage

lim_global_optimize(X, con, lambda1, max_iter, h_tol, rho_max, w_threshold)

Acyclicity constraint h(W) and the matrix power term used in its gradient (Yu et al. 2019 formulation, as used by the Python source)

Description

Acyclicity constraint h(W) and the matrix power term used in its gradient (Yu et al. 2019 formulation, as used by the Python source)

Usage

lim_h(W, d)

Local log-likelihood of continuous component i (super-Gaussian disturbance)

Description

Direct port of likelihood_i/log_p_super_gaussian/variance_i from ⁠lingam/utils/__init__.py⁠ (lines 866-939 of the Python source).

Usage

lim_likelihood_i(X, i, b_full, b0)

Details

A (near-)zero residual variance means component i is fit deterministically by its parents; -n * log(sqrt(var_i)) would then diverge to Inf and make this candidate model look artificially superior. Such candidates are instead scored with a large finite penalty so they lose every BIC comparison in lim_bic_loss()/lim_local_search() without introducing Inf/NaN into the running score.


Description

Local search phase: direction reversal, pruning, and edge addition (Python source lines 324-397). Returns W in the i -> j orientation.

Usage

lim_local_search(W_est, X, con, is_continuous, d, h_tol)

Numerically stable log(1 + exp(M)) (elementwise)

Description

Numerically stable log(1 + exp(M)) (elementwise)

Usage

lim_log1pexp(M)

Numerically stable log(cosh(r)) (elementwise)

Description

Numerically stable log(cosh(r)) (elementwise)

Usage

lim_logcosh(r)

Mixed loss (logistic for discrete columns, log-cosh/Laplace for continuous columns) and its gradient. con is a length-d vector, 1 = continuous, 0 = discrete. W_dis_mask / W_con_mask are precomputed d x d 0/1 masks.

Description

Mixed loss (logistic for discrete columns, log-cosh/Laplace for continuous columns) and its gradient. con is a length-d vector, 1 = continuous, 0 = discrete. W_dis_mask / W_con_mask are precomputed d x d 0/1 masks.

Usage

lim_loss_mixed(W, X, con, W_dis_mask, W_con_mask)

Value and gradient of the augmented-Lagrangian objective for the doubled parameter vector w (length 2dd)

Description

Value and gradient of the augmented-Lagrangian objective for the doubled parameter vector w (length 2dd)

Usage

lim_obj_grad(w, d, X, con, W_dis_mask, W_con_mask, rho, alpha, lambda1)

Topological order (Kahn's algorithm) from a lingamr-convention adjacency matrix B (B[i, j] = j -> i, i.e. row i's nonzero columns are its parents)

Description

Topological order (Kahn's algorithm) from a lingamr-convention adjacency matrix B (B[i, j] = j -> i, i.e. row i's nonzero columns are its parents)

Usage

lim_topological_order(B)

Direct LiNGAM

Description

Direct LiNGAM

Usage

lingam_direct(
  X,
  prior_knowledge = NULL,
  apply_prior_knowledge_softly = FALSE,
  measure = "pwling",
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Numeric matrix (n_samples x n_features), data frame or matrix

prior_knowledge

Prior knowledge matrix (n_features x n_features) or NULL. 0: no directed path from x_i to x_j 1: directed path from x_i to x_j -1: unknown

apply_prior_knowledge_softly

Whether to apply prior knowledge softly (logical)

measure

Independence evaluation measure ("pwling" or "kernel")

reg_method

Regression method for adjacency matrix estimation. "ols": ordinary least squares, "lasso": LASSO regression, "adaptive_lasso": adaptive LASSO regression (default), "ridge": Ridge regression (robust to multicollinearity; does not perform sparse estimation).

lambda

LASSO penalty (lambda) selection. "lambda.min" : minimum CV prediction error, prioritizes prediction accuracy. "lambda.1se" : CV 1SE rule, robust and less prone to overfitting. "AIC": minimum AIC. Fast. "BIC": minimum BIC. Fast, sparsest. Default. "oracle" : adaptive LASSO regression only. Selects a lambda that guarantees the oracle property. Fast.

init_method

Method for estimating the initial weights of adaptive LASSO regression. "ols": ordinary least squares (default), "ridge": Ridge regression. Ridge regression is recommended when multicollinearity is suspected.

Value

A LingamResult object (list) containing the following elements:

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

# OLS (no additional packages required)
result <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")
round(result$adjacency_matrix, 3)


# LASSO (requires glmnet)
result_lasso <- lingam_direct(LiNGAM_sample_1000$data)
round(result_lasso$adjacency_matrix, 3)


Bootstrap for Direct LiNGAM

Description

Bootstrap for Direct LiNGAM

Usage

lingam_direct_bootstrap(
  X,
  n_sampling,
  prior_knowledge = NULL,
  apply_prior_knowledge_softly = FALSE,
  measure = "pwling",
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols",
  seed = NULL,
  verbose = TRUE,
  parallel = FALSE,
  n_cores = NULL,
  compute_total_effects = TRUE
)

Arguments

X

Numeric matrix (n_samples x n_features)

n_sampling

Number of bootstrap iterations

prior_knowledge

Prior knowledge matrix (NULL allowed)

apply_prior_knowledge_softly

Apply prior knowledge softly (logical)

measure

Independence measure ("pwling" or "kernel")

reg_method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge")

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC","oracle")

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge"). Same as the argument of the same name in lingam_direct().

seed

Random seed (NULL allowed)

verbose

Whether to display progress (logical)

parallel

Whether to use parallel processing (logical). When TRUE, each bootstrap iteration is distributed across multiple cores.

n_cores

Number of cores to use (integer, NULL allowed). When NULL, the number of cores is limited to a maximum of 2 for safety. Ignored when parallel = FALSE.

compute_total_effects

Whether to also estimate total causal effects for every variable pair on each bootstrap iteration (logical, default TRUE). For the lasso-family regression methods this roughly doubles iteration cost (an additional regression per downstream variable beyond the adjacency-matrix fit). Set to FALSE to skip it when only edge/order stability is needed (get_probabilities(), get_causal_direction_counts(), get_directed_acyclic_graph_counts(), get_causal_order_stability()); in that case get_total_causal_effects() errors if called on the result.

Details

When parallel = TRUE is specified, iterations are distributed across a socket cluster created by parallel::makePSOCKcluster(). The cluster is always released via on.exit(), whether the process finishes normally or an error occurs.

On iteration failures: each bootstrap iteration is run inside a tryCatch(). If an iteration errors (e.g. a resample produces near-singular columns), a warning identifying the failed iteration is issued and that iteration is excluded from the result instead of aborting the entire run. The returned BootstrapResult reflects however many iterations actually succeeded; an error is raised only if every iteration fails.

On reproducibility: During parallel execution, L'Ecuyer parallel random number streams via parallel::clusterSetRNGStream() are used. Results are reproducible given the same seed and same n_cores, but they do not numerically match the results of sequential execution (parallel = FALSE). If you need results that exactly match the sequential version, use parallel = FALSE.

Value

BootstrapResult (list)

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

# Fast example with OLS
bs <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 10L,
  reg_method = "ols",
  seed = 42
)
get_probabilities(bs)


# With LASSO (requires glmnet)
bs_lasso <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L,
  seed = 42
)

# Parallel execution on 2 cores
bs_par <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L,
  seed = 42,
  parallel = TRUE,
  n_cores = 2L
)


High-Dimensional Direct LiNGAM

Description

A variant of Direct LiNGAM for high-dimensional data (large p, or p > n). Causal order search is based on moment statistics of non-Gaussianity rather than pairwise independence measures, which is considerably faster for many variables. Unlike lingam_direct(), the algorithm is deterministic (no random restarts).

Usage

lingam_high_dim(X, J = 3L, K = 4L, alpha = 0.5, estimate_adj_mat = TRUE)

Arguments

X

Numeric matrix (n_samples x n_features), data frame or matrix

J

Assumed largest in-degree (single integer, must be >= 3)

K

Degree of the moment used to measure non-Gaussianity (single integer, must be >= 1)

alpha

Cutoff coefficient for pruning away false parents (single numeric value in ⁠[0, 1]⁠)

estimate_adj_mat

Whether to estimate the adjacency matrix (single logical value). If FALSE, causal-order search still runs but adjacency_matrix is returned as an NA-filled matrix (not NULL, so downstream S3 methods keep working).

Details

When n_samples <= n_features, the adjacency matrix cannot be estimated with the usual BIC-based Adaptive LASSO, so this function falls back to a cross-validated LASSO (glmnet::cv.glmnet) after emitting a warning. The upstream Python implementation uses LassoLarsCV for this fallback; cv.glmnet follows the same cross-validation design but is not numerically identical (different solver: coordinate descent vs. LARS).

The pruning statistic used during causal-order search (Wang & Drton 2020) is the minimum of a conditional non-Gaussianity statistic over every size-appropriate conditioning subset. The upstream Python implementation (cdt15/lingam) has a return statement mis-indented inside the loop over conditioning subsets, causing it to only ever evaluate the first subset. This R implementation intentionally does not replicate that bug and evaluates every subset, so causal_order and adjacency_matrix are not numerically identical to the upstream Python package.

Value

A LingamResult object (list), the same class returned by lingam_direct(), containing:

References

Wang, Y. S. and Drton, M. (2020). High-dimensional causal discovery under non-Gaussianity. Biometrika, 107(1), 41-59.

Examples

sample <- generate_lingam_sample_6(n = 300, seed = 1)
result <- lingam_high_dim(sample$data)
result$causal_order
round(result$adjacency_matrix, 3)


if (requireNamespace("glmnet", quietly = TRUE)) {
  # n <= p: falls back to cross-validated LASSO with a warning
  wide_sample <- generate_lingam_large_sample(p = 30, n = 25, seed = 1)
  wide_result <- lingam_high_dim(wide_sample$data)
  wide_result$causal_order
}


LiM: LiNGAM for Mixed Data

Description

Estimates a causal structure from data containing a mixture of continuous and binary (0/1) discrete variables, following Zeng et al. (2022). The method combines a NOTEARS-style continuous optimization (global phase) with a combinatorial local search over edge directions, pruning, and edge addition.

Usage

lingam_lim(
  X,
  is_continuous,
  lambda1 = 0.1,
  max_iter = 150L,
  h_tol = 1e-08,
  rho_max = 1e+16,
  w_threshold = 0.1,
  only_global = FALSE
)

Arguments

X

Numeric matrix (n_samples x n_features) or data frame

is_continuous

Logical vector of length ncol(X). TRUE marks a continuous variable, FALSE marks a discrete (binary 0/1) variable.

lambda1

L1 penalty parameter (default: 0.1)

max_iter

Maximum number of dual ascent (outer loop) steps (default: 150)

h_tol

Tolerance for the acyclicity constraint h(W) (default: 1e-8)

rho_max

Maximum value of the augmented-Lagrangian penalty rho (default: 1e16)

w_threshold

Edges with |weight| below this value are dropped after the global optimization phase (default: 0.1)

only_global

If TRUE, skip the combinatorial local search phase and return the thresholded global-optimization result directly (default: FALSE)

Details

Only binary (0/1) discrete variables are supported; count/Poisson-type discrete variables (the Python source's loss_type = "poisson" path) are not implemented.

The Python implementation's adjacency_matrix_ uses the opposite convention (W[i, j] = i -> j). This R implementation transposes the internal result so that adjacency_matrix follows the lingamr convention (B[i, j] = j -> i), consistent with lingam_direct().

In the local search phase, edges that are reversed or newly added are assigned a weight of exactly 1 rather than a re-estimated coefficient (this matches the original Python implementation). As a result, non-zero entries of adjacency_matrix are a mix of global-phase estimated coefficients and local-phase placeholder weights of 1.

The local search's BIC score for discrete variables with parents uses R's glm(family = binomial()), an unregularized maximum-likelihood fit. The Python implementation uses scikit-learn's LogisticRegression, which applies L2 regularization by default; consequently, numeric results will not exactly match the Python implementation.

Value

A LiMResult object (list) containing the following elements:

References

Zeng Y, Shimizu S, Matsui H, Sun F. Causal discovery for linear mixed data. In: Proceedings of the First Conference on Causal Learning and Reasoning (CLeaR 2022). PMLR 177, pp. 994-1009, 2022.

Examples

# Reproducibility requires set.seed(), since the optimization starts from
# a random initial point.
set.seed(1)
dat <- generate_lim_sample(n = 300)
result <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
print(result)

Multi-Group Direct LiNGAM

Description

Jointly estimates a Direct LiNGAM model from multiple datasets ("groups") that are assumed to share a common causal order but may have different structural coefficients (Shimizu 2012).

Usage

lingam_multi_group(
  X_list,
  prior_knowledge = NULL,
  apply_prior_knowledge_softly = FALSE,
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X_list

A list of numeric matrices or data frames (length >= 2), one per group. Each element must have n_d rows (sample size may differ by group) and the same number of columns p across all groups.

prior_knowledge

Prior knowledge matrix (n_features x n_features) or NULL. Applied identically to every group. Same encoding as lingam_direct(): 0: no directed path from x_i to x_j 1: directed path from x_i to x_j -1: unknown

apply_prior_knowledge_softly

Whether to apply prior knowledge softly (logical)

reg_method

Regression method for adjacency matrix estimation. "ols": ordinary least squares, "lasso": LASSO regression, "adaptive_lasso": adaptive LASSO regression (default), "ridge": Ridge regression (robust to multicollinearity; does not perform sparse estimation).

lambda

LASSO penalty (lambda) selection. Same choices as lingam_direct().

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" (default) or "ridge").

Details

Unlike lingam_direct(), this function has no measure argument: the multi-group causal-order search only supports the pwling (pairwise likelihood / entropy approximation) objective, matching the upstream Python MultiGroupDirectLiNGAM, which does not offer a kernel-based multi-group search.

For downstream analysis of a single group (total causal effects, independence tests of residuals, plotting), extract that group as a plain LingamResult with get_group_result() and pass it to the existing single-group functions (estimate_total_effect(), estimate_all_total_effects(), get_error_independence_p_values(), plot_adjacency(), autoplot(), tidy()); no multi-group-specific wrappers are provided for these.

Value

A MultiGroupLingamResult object (list) containing:

References

S. Shimizu. Joint estimation of linear non-Gaussian acyclic models. Neurocomputing, 81: 104-107, 2012.

Examples

mg <- generate_multi_group_sample()
res <- lingam_multi_group(mg$data_list, reg_method = "ols")
print(res)

# Analyze group 1 with the existing single-group tooling
g1 <- get_group_result(res, 1)
estimate_all_total_effects(mg$data_list[[1]], g1, method = "ols")

Bootstrap for Multi-Group Direct LiNGAM

Description

Bootstrap for Multi-Group Direct LiNGAM

Usage

lingam_multi_group_bootstrap(
  X_list,
  n_sampling,
  prior_knowledge = NULL,
  apply_prior_knowledge_softly = FALSE,
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols",
  seed = NULL,
  verbose = TRUE,
  parallel = FALSE,
  n_cores = NULL,
  compute_total_effects = TRUE
)

Arguments

X_list

A list of numeric matrices or data frames (length >= 2), one per group. Same requirements as lingam_multi_group().

n_sampling

Number of bootstrap iterations

prior_knowledge

Prior knowledge matrix (NULL allowed). Applied to every group, same as lingam_multi_group().

apply_prior_knowledge_softly

Apply prior knowledge softly (logical)

reg_method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge")

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle")

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

seed

Random seed (NULL allowed)

verbose

Whether to display progress (logical)

parallel

Whether to use parallel processing (logical)

n_cores

Number of cores to use (integer, NULL allowed). When NULL, the number of cores is limited to a maximum of 2 for safety. Ignored when parallel = FALSE.

compute_total_effects

Whether to also compute total causal effects for every variable pair on each bootstrap iteration (logical, default TRUE). Set to FALSE to skip it when only edge/order stability is needed.

Details

Each element of the returned list is a regular BootstrapResult, so the existing single-group bootstrap functions (get_probabilities(), get_causal_direction_counts(), get_directed_acyclic_graph_counts(), get_total_causal_effects(), get_causal_order_stability(), plot_bootstrap_probabilities(), tidy()) all work by extracting a group with result[[group_name]] or result[[i]], mirroring the upstream Python API (which returns a list of BootstrapResult per group).

Total effects use path products, not regression. Each bootstrap iteration's total-effect matrix is the sum of path-coefficient products over the DAG defined by that iteration's adjacency matrix (matching the upstream Python MultiGroup bootstrap), which is a different method from lingam_direct_bootstrap()'s regression-based estimate_all_total_effects().

On iteration failures: as in lingam_direct_bootstrap(), each iteration is wrapped in tryCatch(); a failing iteration is skipped with a warning, and only if every iteration fails is an error raised.

On reproducibility: same policy as lingam_direct_bootstrap(). During parallel execution, L'Ecuyer parallel random number streams via parallel::clusterSetRNGStream() are used. Results are reproducible given the same seed and same n_cores, but they do not numerically match the results of sequential execution (parallel = FALSE). If you need results that exactly match the sequential version, use parallel = FALSE.

Value

A MultiGroupBootstrapResult: a named list (one element per group) of BootstrapResult objects (see lingam_direct_bootstrap()), with class "MultiGroupBootstrapResult".

Examples

mg <- generate_multi_group_sample()

bs <- lingam_multi_group_bootstrap(mg$data_list,
  n_sampling = 10L,
  reg_method = "ols",
  seed = 42
)
get_probabilities(bs[[1]])


bs_par <- lingam_multi_group_bootstrap(mg$data_list,
  n_sampling = 30L,
  reg_method = "ols",
  seed = 42,
  parallel = TRUE,
  n_cores = 2L
)


Bottom-Up ParceLiNGAM

Description

A causal ordering method robust against latent confounders. Unlike lingam_direct(), which always returns a full causal order, this algorithm searches from the sink (most downstream) side and stops as soon as an independence test is rejected. Variables it could not order are returned together as a single "unresolved block" (suspected to share a latent confounder), and the corresponding entries of the adjacency matrix are set to NA rather than estimated.

Usage

lingam_parce(
  X,
  alpha = 0.1,
  prior_knowledge = NULL,
  independence = "hsic",
  ind_corr = 0.5,
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols"
)

Arguments

X

Numeric matrix (n_samples x n_features), data frame or matrix

alpha

Significance level for the independence test. alpha = 0 disables rejection entirely, so a full causal order is always returned (equivalent in spirit to lingam_direct(), but using the ParceLiNGAM sink-search direction and regression). Must be non-negative.

prior_knowledge

Prior knowledge matrix (n_features x n_features) or NULL. 0: no directed path from x_i to x_j 1: directed path from x_i to x_j -1: unknown

independence

Independence measure used for the ordering search: "hsic" (default) uses the HSIC gamma-approximation test combined across explanatory variables via Fisher's method; "fcorr" uses the F-correlation (kernel canonical correlation) and rejects based on ind_corr instead of a p-value.

ind_corr

Threshold on the F-correlation value used only when independence = "fcorr": a candidate is rejected once the largest F-correlation against any explanatory variable is at or above this value. Must be non-negative. Ignored when independence = "hsic".

reg_method

Regression method for adjacency matrix estimation. "ols": ordinary least squares, "lasso": LASSO regression, "adaptive_lasso": adaptive LASSO regression (default, matches the upstream Python implementation's predict_adaptive_lasso), "ridge": Ridge regression.

lambda

LASSO penalty (lambda) selection. Same options as lingam_direct(): "lambda.min", "lambda.1se", "AIC", "BIC" (default), "oracle" (adaptive LASSO only).

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" (default) or "ridge").

Details

Because HSIC forms full n x n Gram matrices, it is O(n^2) per test; avoid very large n (beyond a few thousand) with independence = "hsic".

independence = "fcorr" rejects based on the raw F-correlation value (ind_corr), not a p-value, so it is not directly comparable to alpha.

get_error_independence_p_values_parce() uses the HSIC test rather than the correlation-based test used by get_error_independence_p_values() for LingamResult objects.

lingam_parce_bootstrap() treats NA (unresolved) edges as absent when aggregating, and does not support get_causal_order_stability() (see its documentation for details). This function does not expose a regressor or bw_method argument, unlike the upstream Python implementation.

Value

A ParceLingamResult object (list) containing:

References

Tashiro, T., Shimizu, S., Hyvarinen, A., and Washio, T. (2014). ParceLiNGAM: a causal ordering method robust against latent confounders. Neural Computation, 26(1), 57-83.

Examples

confounded <- generate_parce_sample(n = 500, seed = 1)

result <- lingam_parce(confounded$data, reg_method = "ols")
print(result)

# The variable pair sharing the latent confounder is left unresolved (NA)
result$adjacency_matrix[confounded$confounded_pair, confounded$confounded_pair]

# Total effect estimation warns and returns NA for confounded variables
estimate_total_effect_parce(confounded$data, result,
  from_index = confounded$confounded_pair[1], to_index = 1
)

Bootstrap for Bottom-Up ParceLiNGAM

Description

Bootstrap for Bottom-Up ParceLiNGAM

Usage

lingam_parce_bootstrap(
  X,
  n_sampling,
  prior_knowledge = NULL,
  alpha = 0.1,
  independence = "hsic",
  ind_corr = 0.5,
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols",
  seed = NULL,
  verbose = TRUE,
  parallel = FALSE,
  n_cores = NULL,
  compute_total_effects = TRUE
)

Arguments

X

Numeric matrix (n_samples x n_features)

n_sampling

Number of bootstrap iterations

prior_knowledge

Prior knowledge matrix (NULL allowed)

alpha

Significance level, passed to lingam_parce()

independence

Independence measure, passed to lingam_parce()

ind_corr

F-correlation rejection threshold, passed to lingam_parce()

reg_method

Regression method ("ols", "lasso", "adaptive_lasso", "ridge")

lambda

Lambda selection ("lambda.min", "lambda.1se", "AIC", "BIC", "oracle")

init_method

Method for estimating the initial weights of adaptive LASSO regression ("ols" or "ridge")

seed

Random seed (NULL allowed)

verbose

Whether to display progress (logical)

parallel

Whether to use parallel processing (logical)

n_cores

Number of cores to use (integer, NULL allowed)

compute_total_effects

Whether to also estimate total causal effects for every variable pair on each bootstrap iteration (logical, default TRUE).

Details

Total effects are path sums, not regression estimates. Each iteration's total-effect matrix is built from calculate_total_effect() (summing products of adjacency-matrix coefficients along every directed path), matching the upstream Python implementation's bootstrap method (estimate_total_effect2). If a variable's row in the adjacency matrix contains NA (it is part of an unresolved block), all of its outgoing total effects are set to NA for that iteration, since its causal parents cannot be identified.

NA (unresolved) edges are treated as absent when aggregating. Both the adjacency matrix and the total-effect matrix have NA replaced by 0 before being stored in the returned BootstrapResult, matching the numpy comparison semantics used by the upstream implementation (where np.abs(nan) > threshold evaluates to FALSE). This means, for example, get_probabilities() reports the confounded pair's edge probability as the fraction of resamples in which the order happened to resolve, not as NA.

causal_orders is not populated (unlike lingam_direct_bootstrap()): ParceLiNGAM's causal order can include an unresolved block, which does not fit the fixed-length integer-vector format causal_orders requires. As a result, get_causal_order_stability() cannot be used with a BootstrapResult returned by this function.

Value

A BootstrapResult (list); see lingam_direct_bootstrap() for the query helpers that operate on it (get_probabilities(), get_causal_direction_counts(), get_directed_acyclic_graph_counts(), get_total_causal_effects()).

Examples


confounded <- generate_parce_sample(n = 500, seed = 1)

bs <- lingam_parce_bootstrap(confounded$data,
  n_sampling = 10L,
  reg_method = "ols",
  seed = 42
)
get_probabilities(bs)


RCD (Repetitive Causal Discovery)

Description

A causal discovery method robust against latent confounders. Unlike lingam_direct() or lingam_parce(), RCD does not attempt to recover a full or partial causal order. Instead, it repeatedly extracts each variable's ancestor set by scanning variable subsets of increasing size (extract_ancestors()), narrows each ancestor set down to direct parents (extract_parents()), and finally tests remaining parent-free pairs for a shared latent confounder (extract_vars_sharing_confounders()). Pairs found to share a latent confounder are marked NA in the adjacency matrix rather than estimated.

Usage

lingam_rcd(
  X,
  max_explanatory_num = 2L,
  cor_alpha = 0.01,
  ind_alpha = 0.01,
  shapiro_alpha = 0.01,
  MLHSICR = FALSE,
  independence = "hsic",
  ind_corr = 0.5
)

Arguments

X

Numeric matrix (n_samples x n_features), data frame or matrix

max_explanatory_num

Maximum number of explanatory variables considered when searching for ancestors (i.e. the search scans variable subsets of size up to max_explanatory_num + 1). Larger values increase statistical power but grow combinatorially in cost. Must be an integer of 1 or more.

cor_alpha

Significance level for the Pearson correlation tests used throughout the algorithm (ancestor-subset screening, parent extraction, confounder-pair detection). Must be non-negative.

ind_alpha

Significance level for the HSIC independence test (used when independence = "hsic"). Must be non-negative.

shapiro_alpha

Significance level for the Shapiro-Wilk non-Gaussianity test used when screening candidate ancestor subsets. Must be non-negative.

MLHSICR

If TRUE, falls back to HSIC-sum-minimizing regression (instead of OLS) when the OLS residual is not independent of the explanatory variables and more than one explanatory variable is present. Substantially increases computation time.

independence

Independence measure used for the sink search: "hsic" (default) uses the HSIC gamma-approximation test; "fcorr" uses the F-correlation (kernel canonical correlation) and rejects based on ind_corr instead of a p-value.

ind_corr

Threshold on the F-correlation value, used only when independence = "fcorr". Must be non-negative. Ignored when independence = "hsic".

Details

The algorithm has three stages: (1) extract_ancestors() grows each variable's ancestor set by repeatedly scanning variable subsets; (2) extract_parents() narrows ancestor sets down to direct parents; (3) extract_vars_sharing_confounders() tests remaining parent-free pairs for a shared latent confounder. NA entries in adjacency_matrix mean the corresponding pair is suspected to share a latent confounder, not that no relationship was estimated.

max_explanatory_num controls both statistical power and computational cost: stage 1 scans choose(n_features, k) subsets for each subset size k up to max_explanatory_num + 1, and each subset requires several HSIC tests (each O(n^2) in the sample size when independence = "hsic"). Cost grows quickly with both the number of variables and n.

MLHSICR = TRUE replaces the OLS residual in the independence check with a residual obtained by directly minimizing the sum of HSIC statistics between the residual and each explanatory variable via numerical optimization (stats::optim(method = "L-BFGS-B")). This can recover independence in cases where OLS cannot, but requires re-optimizing for every candidate subset where the OLS residual fails, and is therefore substantially slower.

The Shapiro-Wilk test (stats::shapiro.test()) used for the non-Gaussianity check is limited to n between 3 and 5000. For n above 5000, a deterministic evenly-spaced subsample of 5000 observations is tested instead (same policy as test_residual_normality()), so results remain reproducible without touching the RNG state. This subsampling has no effect when n <= 5000.

This function does not expose a bw_method argument (kernel widths are always the median heuristic; see hsic_kernel_width()), unlike some upstream implementations. lingam_rcd_bootstrap() does not support get_causal_order_stability(), since RCD has no causal order.

Value

An RCDResult object (list) containing:

References

Maeda, T. N. and Shimizu, S. (2020). RCD: Repetitive causal discovery of linear non-Gaussian acyclic models with latent confounders. AISTATS 2020, PMLR 108: 735-745.

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)

result <- lingam_rcd(confounded$data)
print(result)

# The variable pair sharing the latent confounder is left NA
result$adjacency_matrix[confounded$confounded_pair, confounded$confounded_pair]

# Total effect estimation warns and returns NA for confounded variables
estimate_total_effect_rcd(confounded$data, result,
  from_index = confounded$confounded_pair[1], to_index = 1
)

Bootstrap for RCD

Description

Bootstrap for RCD

Usage

lingam_rcd_bootstrap(
  X,
  n_sampling,
  max_explanatory_num = 2L,
  cor_alpha = 0.01,
  ind_alpha = 0.01,
  shapiro_alpha = 0.01,
  MLHSICR = FALSE,
  independence = "hsic",
  ind_corr = 0.5,
  seed = NULL,
  verbose = TRUE,
  parallel = FALSE,
  n_cores = NULL,
  compute_total_effects = TRUE
)

Arguments

X

Numeric matrix (n_samples x n_features)

n_sampling

Number of bootstrap iterations

max_explanatory_num

Maximum number of explanatory variables, passed to lingam_rcd()

cor_alpha

Significance level for correlation tests, passed to lingam_rcd()

ind_alpha

Significance level for the HSIC independence test, passed to lingam_rcd()

shapiro_alpha

Significance level for the non-Gaussianity test, passed to lingam_rcd()

MLHSICR

Whether to use MLHSICR regression, passed to lingam_rcd()

independence

Independence measure, passed to lingam_rcd()

ind_corr

F-correlation rejection threshold, passed to lingam_rcd()

seed

Random seed (NULL allowed)

verbose

Whether to display progress (logical)

parallel

Whether to use parallel processing (logical)

n_cores

Number of cores to use (integer, NULL allowed)

compute_total_effects

Whether to also estimate total causal effects for every ancestor pair on each bootstrap iteration (logical, default TRUE).

Details

Total effects are computed only for ancestor pairs, driven by each iteration's ancestors_list (unlike lingam_direct_bootstrap() and lingam_parce_bootstrap(), which loop over all variable pairs). For a pair ⁠(from, to)⁠ with from in to's ancestor set, the total effect is obtained via calculate_total_effect() (summing products of adjacency-matrix coefficients along every directed path). If from's row in the adjacency matrix contains NA (it shares a latent confounder with some other variable), the effect is set to NA for that iteration.

NA (confounded) edges are treated as absent when aggregating. Both the adjacency matrix and the total-effect matrix have NA replaced by 0 before being stored in the returned BootstrapResult, matching the policy used by lingam_parce_bootstrap().

causal_orders is not populated: RCD has no causal order (see lingam_rcd()). As a result, get_causal_order_stability() cannot be used with a BootstrapResult returned by this function.

RCD's fit step is HSIC-heavy and can be slow per iteration, especially with MLHSICR = TRUE; keep n_sampling modest in examples.

Value

A BootstrapResult (list); see lingam_direct_bootstrap() for the query helpers that operate on it (get_probabilities(), get_causal_direction_counts(), get_directed_acyclic_graph_counts(), get_total_causal_effects()).

Examples


confounded <- generate_rcd_sample(n = 300, seed = 1)

bs <- lingam_rcd_bootstrap(confounded$data,
  n_sampling = 5L,
  seed = 42
)
get_probabilities(bs)


Compute residuals (error terms) of a LiNGAM model

Description

After validating the inputs (that lingam_result is a LingamResult, that X is numeric, and that the dimensions match), returns ⁠E = X - X B^T⁠. Shared by the residual-based diagnostic functions.

Usage

lingam_residuals(X, lingam_result)

Arguments

X

original data (matrix or data.frame)

lingam_result

return value of lingam_direct()

Value

residual matrix (n_samples x n_features). Preserves the column names of X.


VAR-LiNGAM for time series causal discovery

Description

Fits a vector autoregressive (VAR) model to time series data and applies Direct LiNGAM to the residuals to recover the instantaneous (lag-0) causal structure. The lagged causal matrices are then derived from the VAR coefficients and the instantaneous structure.

Usage

lingam_var(
  X,
  lags = 1L,
  criterion = "bic",
  measure = "pwling",
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols",
  prune = TRUE
)

Arguments

X

numeric matrix or data frame (n_samples x n_features). Rows are ordered in time (earliest first).

lags

maximum lag order. When criterion is not NULL, the best lag in 1:lags is selected by the information criterion; otherwise lags is used directly.

criterion

lag-selection criterion ("bic", "aic", "hqic", or "fpe"), or NULL to use lags directly without selection.

measure

independence measure passed to lingam_direct() ("pwling" or "kernel").

reg_method

regression method for the instantaneous adjacency matrix: "adaptive_lasso" (default), "lasso", "ols", or "ridge" (see lingam_direct()).

lambda

penalty (lambda) selection for the instantaneous matrix: "BIC" (default), "AIC", "lambda.min", "lambda.1se", or "oracle" (see lingam_direct()).

init_method

initial-weight method for adaptive LASSO (see lingam_direct()).

prune

logical; if TRUE (default, matching the Python reference), all adjacency matrices (instantaneous B0 and the lagged B_k) are refined together by adaptive LASSO so weak edges are shrunk toward zero. Requires the glmnet package. Set FALSE to keep the raw ⁠B_k = (I - B0) M_k⁠ matrices (no glmnet needed when reg_method = "ols").

Details

The model is ⁠X_t = B0 X_t + sum_{k=1}^{p} B_k X_{t-k} + e_t⁠, where B0 is the instantaneous effect matrix (strictly acyclic) and e_t are mutually independent non-Gaussian errors. VAR coefficients M_k are estimated by ordinary least squares (no intercept); residuals ⁠e_t = X_t - sum M_k X_{t-k}⁠ are passed to lingam_direct() to obtain B0, and the lagged matrices follow ⁠B_k = (I - B0) M_k⁠.

Value

A VARLiNGAMResult object (list) containing:

References

Hyvärinen, A., Zhang, K., Shimizu, S., & Hoyer, P. O. (2010). Estimation of a structural vector autoregression model using non-Gaussianity. Journal of Machine Learning Research, 11, 1709-1731. Ported from the Python implementation cdt15/lingam (https://github.com/cdt15/lingam). See also the VARLiNGAM R code of Moneta et al. (https://sites.google.com/site/dorisentner/publications/VARLiNGAM).

Examples

sample <- generate_varlingam_sample(n = 500, seed = 42)

# OLS instantaneous structure without pruning (no extra packages required)
model <- lingam_var(sample$data, lags = 1, reg_method = "ols", prune = FALSE)
round(model$adjacency_matrices[1, , ], 2)  # instantaneous B0

Bootstrap for VAR-LiNGAM

Description

Evaluates the statistical reliability of the estimated time-series DAG by resampling. Unlike the i.i.d. row resampling used for Direct LiNGAM, this uses a residual bootstrap: the VAR is fitted once on the original data, the residuals are resampled with replacement, and a new series is rebuilt by the VAR recursion before re-estimating VAR-LiNGAM on it (this preserves the autoregressive structure). Port of the Python reference VARLiNGAM.bootstrap.

Usage

lingam_var_bootstrap(
  X,
  n_sampling,
  lags = 1L,
  criterion = "bic",
  measure = "pwling",
  reg_method = "adaptive_lasso",
  lambda = "BIC",
  init_method = "ols",
  prune = TRUE,
  seed = NULL,
  verbose = TRUE,
  parallel = FALSE,
  n_cores = NULL
)

Arguments

X

numeric matrix or data frame (n_samples x n_features), rows ordered in time.

n_sampling

number of bootstrap iterations (positive integer).

lags

maximum lag order. When criterion is not NULL, the lag is selected once on the original data and then fixed across all iterations.

criterion

lag-selection criterion ("bic", "aic", "hqic", "fpe") or NULL to use lags directly.

measure

independence measure for lingam_direct() ("pwling"/"kernel").

reg_method

regression method for the instantaneous matrix.

lambda

penalty selection (see lingam_direct()).

init_method

initial-weight method for adaptive LASSO.

prune

logical; passed to lingam_var() on each iteration (default TRUE).

seed

random seed (NULL allowed).

verbose

whether to print progress (logical).

parallel

whether to distribute iterations across cores (logical).

n_cores

number of cores (integer or NULL; NULL caps at 2 for safety).

Details

Reproducibility follows the same rules as lingam_direct_bootstrap(): with parallel = TRUE, L'Ecuyer streams via parallel::clusterSetRNGStream() make results reproducible for a given seed and n_cores, but they do not match the sequential (parallel = FALSE) results.

On iteration failures: as in lingam_direct_bootstrap(), each iteration runs inside a tryCatch(); a failing iteration is reported as a warning and excluded from the result instead of aborting the run. An error is raised only if every iteration fails.

Value

a VARBootstrapResult object.

Examples

s <- generate_varlingam_sample(n = 500, seed = 42)

# Fast example: OLS instantaneous structure, no pruning (no glmnet needed)
bs <- lingam_var_bootstrap(s$data,
  n_sampling = 10L, lags = 1, criterion = NULL,
  reg_method = "ols", prune = FALSE, seed = 1, verbose = FALSE
)
get_var_probabilities(bs)

Create noise generation function

Description

Internal helper to create a noise function for the specified distribution.

Usage

make_noise_fn(noise_dist)

Arguments

noise_dist

distribution name "uniform" : Uniform(0, 1) - non-Gaussian (LiNGAM works well) "gaussian" : Normal(0, 1) - LiNGAM may fail "lognormal" : Log-normal(0, 1) - skewed, non-Gaussian "exponential" : Exponential(1) - skewed, non-Gaussian "t3" : t-distribution (df=3) - heavy tails

Value

function(n) that generates n random numbers


Create a prior knowledge matrix

Description

Create a prior knowledge matrix

Usage

make_prior_knowledge(
  n_variables,
  exogenous_variables = NULL,
  sink_variables = NULL,
  paths = NULL,
  no_paths = NULL,
  labels = NULL
)

Arguments

n_variables

Number of variables

exogenous_variables

Exogenous variables (1-based index or variable name, NULL allowed) The specified variables are assumed not to be influenced by any other variable

sink_variables

Sink variables (1-based index or variable name, NULL allowed) The specified variables are assumed not to influence any other variable

paths

Variable pairs that have a directed path (NULL allowed) Of the form list(c(from, to), ...). Specified by index or variable name

no_paths

Variable pairs that have no directed path (NULL allowed) Of the form list(c(from, to), ...). Specified by index or variable name

labels

Vector of variable names (NULL allowed) Required when specifying by variable name. Pass e.g. colnames() of a data.frame

Value

Prior knowledge matrix (n_variables x n_variables) -1: unknown, 0: no path, 1: path exists

Examples

# Specify by index
pk <- make_prior_knowledge(6, exogenous_variables = c(4))

# Specify by variable name
pk <- make_prior_knowledge(6,
  exogenous_variables = "x3",
  sink_variables = c("x1", "x4"),
  paths = list(c("x3", "x0"), c("x3", "x2")),
  no_paths = list(c("x5", "x2")),
  labels = c("x0", "x1", "x2", "x3", "x4", "x5")
)

HSIC-sum-minimizing ("MLHSICR") regression

Description

Regresses Y[, xi] on Y[, xj_list] (no intercept) by minimizing the sum of the empirical HSIC statistics between the residual and each explanatory variable, instead of ordinary least squares. Used as a fallback when the OLS residual is not independent of the explanatory variables.

Usage

mlhsicr_regression(Y, xi, xj_list)

Arguments

Y

data matrix (residualized already, if applicable)

xi

target column index

xj_list

explanatory column indices (length >= 2)

Details

The kernel width used to build the residual's Gram matrix is itself a linear combination of the explanatory variables' kernel widths (faithful to the upstream implementation; see original 207-208 lines). This is an unusual design choice but is deliberately preserved as-is.

Value

list(resid = residual vector, coef = coefficient vector)


Compute a total-effect matrix from an adjacency matrix via path products

Description

Unlike estimate_all_total_effects() (regression-based), this sums path products over the DAG defined by B, matching the upstream Python MultiGroup bootstrap's calculate_total_effect().

Usage

multi_group_total_effect_matrix(B, causal_order)

Arguments

B

adjacency matrix (n_features x n_features), B[i,j] = j -> i

causal_order

causal order (1-based indices)

Value

total-effect matrix (n_features x n_features)


Kernel-based mutual information

Description

Dispatches to the incomplete-Cholesky low-rank path for n above the low-rank threshold (matching the kappa/sigma switch in search_causal_order_kernel()); below the threshold it calls the exact path unchanged.

Usage

mutual_information_kernel(x1, x2, param)

Arguments

x1

Variable 1

x2

Variable 2

param

Parameter vector (kappa, sigma)

Value

Mutual information


Evaluate the independence of a residual against a fixed set of predictors

Description

Used for the length(Uc) == 1 special case in find_exo_vec(), where there is nothing left to compare against.

Usage

parce_eval_independence(X, predictors, R, independence)

Arguments

X

data matrix

predictors

predictor indices (may be empty)

R

residual vector

independence

"hsic" or "fcorr"

Value

evaluation value (Fisher-combined p-value for hsic, max F-correlation for fcorr)


Find the position (rank) of a variable within a ParceLiNGAM causal order

Description

All members of the unresolved block (if any) share the same rank (1).

Usage

parce_order_rank(causal_order, idx)

Arguments

causal_order

list as produced by lingam_parce()

idx

1-based variable index

Value

integer rank, or NA if not found


Residual of X[, j] regressed on X[, xi_index] via the pseudo-inverse of the covariance matrix

Description

Residual of X[, j] regressed on X[, xi_index] via the pseudo-inverse of the covariance matrix

Usage

parce_residual(X, xi_index, j, Cov)

Arguments

X

data matrix

xi_index

explanatory-variable indices (may be empty)

j

target variable index

Cov

precomputed stats::cov(X), since X is invariant across all calls within a single parce_search_causal_order() search

Value

residual vector


Candidate sink variables under prior knowledge (ParceLiNGAM direction)

Description

Unlike search_candidate() (used by top-down DirectLiNGAM), ParceLiNGAM searches from the sink side, so the filter is simply "exclude variables that appear as the 'from' side of a known partial order" (they cannot be a sink because something is known to cause a variable through them... more precisely: a variable known to cause another remaining variable cannot itself be the next sink).

Usage

parce_search_candidate(U, partial_orders)

Arguments

U

set of currently undetermined variables

partial_orders

matrix of (from, to) pairs from extract_partial_orders()

Value

candidate index vector (subset of U, or U itself if no candidates remain)


Bottom-up causal order search

Description

Faithful port of ⁠_search_causal_order()⁠ (original 188-225 lines). Repeatedly finds the most sink-like remaining variable and appends it to the front of K_bttm (bottom-up, so more recently placed variables are more upstream). Stops as soon as a candidate is rejected by the independence test; the remaining undetermined variables are returned as U_res.

Usage

parce_search_causal_order(
  X,
  U,
  partial_orders,
  independence,
  thresh_p,
  ind_corr
)

Arguments

X

(centered) data matrix

U

all variable indices

partial_orders

matrix of (from, to) pairs, or NULL

independence

"hsic" or "fcorr"

thresh_p

Bonferroni-corrected significance threshold (hsic only)

ind_corr

F-correlation rejection threshold (fcorr only)

Value

list(K_bttm = integer vector, p_bttm = numeric vector, U_res = integer vector)


Moore-Penrose pseudo-inverse via SVD

Description

Internal replacement for numpy.linalg.pinv, used to solve the conditional regression coefficients from Gram-matrix submatrices in lingam_high_dim(). Implemented in base R to avoid a new dependency.

Usage

pinv(A, tol = max(dim(A)) * .Machine$double.eps)

Arguments

A

numeric matrix

tol

singular-value cutoff, relative to the largest singular value

Value

the pseudo-inverse of A


Plot a causal graph from an adjacency matrix with DiagrammeR

Description

Plot a causal graph from an adjacency matrix with DiagrammeR

Usage

plot_adjacency(
  B,
  labels = NULL,
  threshold = 0,
  rankdir = "TB",
  title = "Estimated Causal Structure",
  shape = "circle",
  fillcolor = "lightyellow",
  bordercolor = "black",
  fontsize_node = 14,
  fontsize_edge = 10,
  edge_color = "gray40",
  edge_label_color = "red",
  true_B = NULL,
  color_tp = "forestgreen",
  color_fp = "firebrick",
  color_fn = "darkorange",
  debug = FALSE
)

Arguments

B

Adjacency matrix (n_features x n_features). Convention: B[i, j] is the causal coefficient from variable j to variable i (j -> i). The adjacency_matrix from lingam_direct() can be passed directly.

labels

Vector of variable names (if NULL, x0, x1, ... are generated automatically)

threshold

Minimum absolute coefficient value to display (default: 0)

rankdir

Layout direction (default: "LR") "LR" = left -> right, "RL" = right -> left, "TB" = top -> bottom, "BT" = bottom -> top

title

Graph title (default: "Estimated Causal Structure")

shape

Node shape (default: "circle") "circle", "box", "ellipse", "diamond", "plaintext", "square", "triangle", "hexagon", "octagon", etc.

fillcolor

Node fill color (default: "lightyellow")

bordercolor

Border color

fontsize_node

Node font size (default: 14)

fontsize_edge

Edge label font size (default: 10)

edge_color

Edge color (default: "gray40"). Unused when true_B is specified.

edge_label_color

Edge label color (default: "red"). Unused when true_B is specified.

true_B

True adjacency matrix (may be NULL). When specified, edges are classified into three colors:

  • Correct edges (estimated and true): solid line in color_tp

  • False positives (estimated but not true): solid line in color_fp

  • Missed edges (not estimated but true): dashed line in color_fn (showing the true coefficient)

color_tp

Color for correct edges (default: "forestgreen")

color_fp

Color for false-positive edges (default: "firebrick")

color_fn

Color for missed edges (default: "darkorange")

debug

Enable debug mode (logical)

Value

A grViz object (when DiagrammeR is available)

Examples

if (requireNamespace("DiagrammeR", quietly = TRUE)) {
  LiNGAM_sample_1000 <- generate_lingam_sample_6()

  LiNGAM_sample_1000$true_adjacency |>
    plot_adjacency(title = "True Causal Structure")

  model <- LiNGAM_sample_1000$data |>
    lingam_direct(reg_method = "ols")

  model$adjacency_matrix |>
    plot_adjacency()

  
  # Compare with the true structure
  # (correct = green, false positive = red, missed = orange dashed)
  model$adjacency_matrix |>
    plot_adjacency(true_B = LiNGAM_sample_1000$true_adjacency)
  
}

Draw bootstrap probabilities with DiagrammeR

Description

Draw bootstrap probabilities with DiagrammeR

Usage

plot_bootstrap_probabilities(
  result,
  labels = NULL,
  min_causal_effect = NULL,
  min_probability = 0.5,
  rankdir = "TB",
  shape = "circle"
)

Arguments

result

BootstrapResult object

labels

Vector of variable names (NULL allowed)

min_causal_effect

Minimum causal effect to display

min_probability

Minimum probability to display

rankdir

Layout direction

shape

Node shape

Value

grViz object

Examples

if (requireNamespace("DiagrammeR", quietly = TRUE)) {
  LiNGAM_sample_1000 <- generate_lingam_sample_6()

  bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
    n_sampling = 30L, reg_method = "ols", seed = 42
  )
  plot_bootstrap_probabilities(bs_model)
}

plot QQ

Description

plot QQ

Usage

plot_residual_qq(X, lingam_result, ncol = 3, nrow = NULL)

Arguments

X

original data (matrix or data.frame)

lingam_result

return value of lingam_direct()

ncol

Number of columns.

nrow

Number of rows.

Value

A ggplot2::ggplot object with QQ plots of residuals.

Examples

if (requireNamespace("ggplot2", quietly = TRUE)) {
  # Load the sample data
  LiNGAM_sample_1000 <- generate_lingam_sample_6()

  # Run Direct LiNGAM
  result <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")

  plot_residual_qq(LiNGAM_sample_1000$data, result)
}

Q-Q plots of VAR-LiNGAM residuals

Description

Draws per-variable normal Q-Q plots of the residuals (analogous to the Moneta Gauss_Stats visual check). Deviations from the reference line indicate non-Gaussianity, which supports the LiNGAM assumption. Requires ggplot2.

Usage

plot_varlingam_residual_qq(
  result,
  on = c("innovations", "var"),
  ncol = 3,
  nrow = NULL
)

Arguments

result

a VARLiNGAMResult from lingam_var()

on

which series to plot: "innovations" (default) or "var"

ncol

number of facet columns

nrow

number of facet rows (NULL = automatic)

Value

a ggplot object

References

Analogous to the residual visual check (Gauss_Stats) in the VARLiNGAM R code of Moneta, A., Entner, D., Hoyer, P. O., & Coad, A. (2013), Oxford Bulletin of Economics and Statistics, 75(5), 705-730. https://sites.google.com/site/dorisentner/publications/VARLiNGAM

Examples

s <- generate_varlingam_sample(n = 1000, seed = 42)
m <- lingam_var(s$data, lags = 1, reg_method = "ols", prune = FALSE)

plot_varlingam_residual_qq(m)


Adaptive LASSO with CV-selected lambda (n <= p route)

Description

Replicates upstream ⁠_predict_adaptive_lasso⁠ (StandardScaler + OLS weights + LassoLarsCV), substituting glmnet::cv.glmnet(alpha = 1) for LassoLarsCV (see lingam_high_dim() Details for the rationale).

Usage

predict_adaptive_lasso_cv(X, predictors, target, gamma = 1)

Arguments

X

original-scale data matrix

predictors

indices of predictor variables (1-based)

target

index of the target variable (1-based)

gamma

exponent of the adaptive weights (fixed at 1.0 upstream)

Value

coefficient vector, same length and order as predictors


Display the contents of a BootstrapResult

Description

Display the contents of a BootstrapResult

Usage

## S3 method for class 'BootstrapResult'
print(x, ...)

Arguments

x

BootstrapResult object

...

Additional arguments (for S3 method compatibility)

Value

The input object x, invisibly.

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

bs_model <- lingam_direct_bootstrap(LiNGAM_sample_1000$data,
  n_sampling = 30L, reg_method = "ols", seed = 42
)

print(bs_model)

Print method for ImputationBootstrapResult

Description

Print method for ImputationBootstrapResult

Usage

## S3 method for class 'ImputationBootstrapResult'
print(x, ...)

Arguments

x

ImputationBootstrapResult object

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

set.seed(1)
sample6 <- generate_lingam_sample_6(n = 300, seed = 1)
X <- sample6$data
X$x5[sample.int(nrow(X), size = 30)] <- NA

if (requireNamespace("mice", quietly = TRUE)) {
  res <- bootstrap_with_imputation(X,
    n_sampling = 5L, n_repeats = 3L, seed = 42, verbose = FALSE
  )
  print(res)
}

Print method for LiMResult

Description

Print method for LiMResult

Usage

## S3 method for class 'LiMResult'
print(x, digits = 3, ...)

Arguments

x

LiMResult object

digits

Number of digits to display

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

set.seed(1)
dat <- generate_lim_sample(n = 300)
result <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
print(result)

Print method for LingamResult

Description

Print method for LingamResult

Usage

## S3 method for class 'LingamResult'
print(x, digits = 3, ...)

Arguments

x

LingamResult object

digits

Number of digits to display

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()
result <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")
print(result)

Print method for MultiGroupBootstrapResult

Description

Print method for MultiGroupBootstrapResult

Usage

## S3 method for class 'MultiGroupBootstrapResult'
print(x, ...)

Arguments

x

MultiGroupBootstrapResult object

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

mg <- generate_multi_group_sample()
bs <- lingam_multi_group_bootstrap(mg$data_list,
  n_sampling = 10L, reg_method = "ols", seed = 42
)
print(bs)

Print method for MultiGroupLingamResult

Description

Print method for MultiGroupLingamResult

Usage

## S3 method for class 'MultiGroupLingamResult'
print(x, digits = 3, ...)

Arguments

x

MultiGroupLingamResult object

digits

Number of digits to display

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

mg <- generate_multi_group_sample()
res <- lingam_multi_group(mg$data_list, reg_method = "ols")
print(res)

Print method for ParceLingamResult

Description

Print method for ParceLingamResult

Usage

## S3 method for class 'ParceLingamResult'
print(x, digits = 3, ...)

Arguments

x

ParceLingamResult object

digits

Number of digits to display

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

confounded <- generate_parce_sample(n = 300, seed = 42)
result <- lingam_parce(confounded$data, reg_method = "ols")
print(result)

Print method for RCDResult

Description

Print method for RCDResult

Usage

## S3 method for class 'RCDResult'
print(x, digits = 3, ...)

Arguments

x

RCDResult object

digits

Number of digits to display

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
result <- lingam_rcd(confounded$data)
print(result)

Print a VARBootstrapResult

Description

Print a VARBootstrapResult

Usage

## S3 method for class 'VARBootstrapResult'
print(x, ...)

Arguments

x

a VARBootstrapResult object

...

additional arguments (unused)

Value

The input object x, invisibly.

Examples

s <- generate_varlingam_sample(n = 500, seed = 42)
bs <- lingam_var_bootstrap(s$data,
  n_sampling = 10L, lags = 1, criterion = NULL,
  reg_method = "ols", prune = FALSE, seed = 1, verbose = FALSE
)
print(bs)

Print method for VARLiNGAMResult

Description

Print method for VARLiNGAMResult

Usage

## S3 method for class 'VARLiNGAMResult'
print(x, digits = 3, ...)

Arguments

x

VARLiNGAMResult object

digits

number of digits to display

...

additional arguments (unused)

Value

The input object x, invisibly.

Examples

sample <- generate_varlingam_sample(n = 500, seed = 42)
model <- lingam_var(sample$data, lags = 1, reg_method = "ols", prune = FALSE)
print(model)

print method for causal_order_stability

Description

print method for causal_order_stability

Usage

## S3 method for class 'causal_order_stability'
print(x, ...)

Arguments

x

A causal_order_stability object

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

dat <- generate_lingam_sample_6()
bs <- lingam_direct_bootstrap(dat$data, n_sampling = 30L, reg_method = "ols", seed = 42)
print(get_causal_order_stability(bs, labels = names(dat$data)))

Print method for lingam_normality_test

Description

Print method for lingam_normality_test

Usage

## S3 method for class 'lingam_normality_test'
print(x, ...)

Arguments

x

lingam_normality_test object

...

additional arguments

Value

The input object x, invisibly.

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()
result <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")
print(test_residual_normality(LiNGAM_sample_1000$data, result))

print method for lingam_summary

Description

print method for lingam_summary

Usage

## S3 method for class 'lingam_summary'
print(x, ...)

Arguments

x

A lingam_summary object

...

Additional arguments (unused)

Value

The input object x, invisibly.

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()
model <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")
print(summary_lingam(LiNGAM_sample_1000$data, model))

Print method for var_stationarity

Description

Print method for var_stationarity

Usage

## S3 method for class 'var_stationarity'
print(x, ...)

Arguments

x

a var_stationarity object

...

additional arguments (unused)

Value

The input object x, invisibly.

Examples

s <- generate_varlingam_sample(n = 1000, seed = 42)
m <- lingam_var(s$data, lags = 1, reg_method = "ols", prune = FALSE)
print(check_var_stationarity(m))

Prune VAR-LiNGAM adjacency matrices by adaptive LASSO

Description

Re-estimates the instantaneous matrix B0 and every lagged matrix B_k jointly, shrinking weak edges to zero. Port of the Python reference ⁠_pruning⁠. For each target variable, the predictors are its contemporaneous ancestors (those preceding it in causal_order) plus all variables at lags 1..lags; the coefficients are fitted by adaptive LASSO and written back into B.

Usage

prune_var_lingam(X, causal_order, lags, lambda = "BIC", init_method = "ols")

Arguments

X

numeric matrix (n_samples x n_features), rows ordered in time

causal_order

instantaneous causal order (1-based indices)

lags

lag order

lambda

lambda selection passed to fit_adaptive_lasso()

init_method

initial-weight method for adaptive LASSO

Value

array (lags + 1, n_features, n_features); slice 1 is B0, slice k+1 is B_k


Pearson correlation test used throughout RCD

Description

Pearson correlation test used throughout RCD

Usage

rcd_is_correlated(a, b, cor_alpha)

Arguments

a

numeric vector

b

numeric vector

cor_alpha

significance level

Value

TRUE if correlated (p-value < cor_alpha)


Independence judgment used throughout RCD (hsic or fcorr)

Description

Independence judgment used throughout RCD (hsic or fcorr)

Usage

rcd_is_independent(a, b, independence, ind_alpha, ind_corr)

Arguments

a

numeric vector

b

numeric vector

independence

"hsic" or "fcorr"

ind_alpha

significance level (hsic only)

ind_corr

rejection threshold (fcorr only)

Value

TRUE if independent


Non-Gaussianity judgment (Shapiro-Wilk) for a set of columns

Description

When n > SHAPIRO_MAX_N, stats::shapiro.test() cannot be used directly (hard cap at 5000), so the deterministic evenly-spaced subsample from shapiro_subsample() (defined in R/get_error_independence_p_values.r) is tested instead, matching the behavior of test_residual_normality(). The deterministic thinning keeps results reproducible across calls and leaves the caller's RNG stream untouched.

Usage

rcd_is_non_gaussian_all(Y, cols, shapiro_alpha)

Arguments

Y

data matrix

cols

column indices to test

shapiro_alpha

significance level

Value

TRUE if all columns reject normality (p <= shapiro_alpha)


OLS residual and coefficients (with intercept)

Description

OLS residual and coefficients (with intercept)

Usage

rcd_ols_resid_coef(y, X_exog)

Arguments

y

response vector

X_exog

explanatory-variable matrix (may have 0 columns)

Value

list(resid = residual vector, coef = coefficient vector excluding intercept)


Resolve a variable index or name to a 1-based integer index

Description

Resolve a variable index or name to a 1-based integer index

Usage

rcd_resolve_index(idx, arg_name, n_features, col_names)

Objects exported from other packages

Description

These objects are imported from other packages. Follow the links below to see their documentation.

generics

glance(), tidy()


Residual (residual when xi is regressed on xj) Compute the residual vector

Description

Residual (residual when xi is regressed on xj) Compute the residual vector

Usage

residual_vec(xi, xj)

Arguments

xi

Target variable vector

xj

Explanatory variable vector

Value

Residual vector after regression


Resolve a variable identifier to a 1-based integer index

Description

Shared by estimate_var_total_effect() and estimate_total_effect().

Usage

resolve_var_index(idx, arg_name, col_names, n_features)

Roll matrix rows (numpy np.roll equivalent, axis = 0)

Description

Shifts the rows of M downward by shift, wrapping the last shift rows around to the top. Used to build the lagged design for total-effect regression. The wrap-around contaminates the first shift rows, matching the Python reference (the effect is negligible for long series).

Usage

roll_rows(M, shift)

Arguments

M

numeric matrix

shift

non-negative integer number of rows to shift down

Value

matrix with rolled rows


Population standard deviation (divided by n)

Description

Population standard deviation (divided by n)

Usage

sd_pop(x)

Search for candidate variables

Description

Search for candidate variables

Usage

search_candidate(U, Aknw, apply_prior_knowledge_softly, partial_orders)

Arguments

U

Set of currently undetermined variables

Aknw

Prior knowledge matrix

apply_prior_knowledge_softly

Whether to apply prior knowledge softly

partial_orders

Extracted partial orders

Value

list(Uc, Vj)


Causal order search via the kernel method

Description

Causal order search via the kernel method

Usage

search_causal_order_kernel(X, U, Uc, Vj)

Arguments

X

Data matrix

U

All variables

Uc

Candidate variables

Vj

Prior knowledge set

Value

Index of the selected variable


Causal order search via pwling

Description

Causal order search via pwling

Usage

search_causal_order_pwling(X, U, Uc, Vj)

Arguments

X

Data matrix

U

Indices of all variables

Uc

Indices of candidate variables

Vj

Variable set based on prior knowledge

Value

Index of the selected variable


Causal order search via pwling, jointly across multiple groups

Description

Sample-size-weighted sum of the single-group pwling objective (search_causal_order_pwling()) across all groups in X_list, following the joint estimation objective of Shimizu (2012). Reuses the same standardize-once / correlation-matrix / antisymmetry optimizations as search_causal_order_pwling(), applied independently within each group before the weighted sum.

Usage

search_causal_order_pwling_multi(X_list, U, Uc, Vj)

Arguments

X_list

List of per-group data matrices (residualized so far), one per group. All must have the same number of columns.

U

Indices of all currently undetermined variables (shared across groups)

Uc

Indices of candidate variables (shared across groups)

Vj

Variable set based on prior knowledge (shared across groups)

Value

Index of the selected variable


Select the VAR lag order by information criterion

Description

All candidate lag orders are compared on a common sample: the first max_lag observations are dropped for every candidate so that each VAR(lag) is estimated over the same time window (t = max_lag + 1 .. n). This mirrors statsmodels' VAR.select_order and makes the criteria comparable across lags (otherwise a longer lag would be scored on fewer observations).

Usage

select_var_lag(X, max_lag, criterion = "bic")

Arguments

X

numeric matrix (n_samples x n_features)

max_lag

maximum lag order to consider

criterion

"bic", "aic", "hqic", or "fpe"

Value

the selected lag order (integer)


Make this package's functions available on parallel cluster workers

Description

Used by all ⁠*_bootstrap()⁠ functions before dispatching iterations via parallel::parLapply(). Tries to have each worker library() the installed package; if that is not possible (e.g. during devtools::load_all() development, where the package is not installed), falls back to exporting every object in the namespace environment of a representative function from the algorithm being bootstrapped.

Usage

setup_cluster_worker(cl, fun)

Arguments

cl

A parallel cluster object (from parallel::makePSOCKcluster()).

fun

A function belonging to the package whose namespace environment should be used as the fallback export source (e.g. lingam_direct, lingam_rcd, lingam_parce, lingam_multi_group).

Value

NULL, invisibly. Called for the side effect of preparing cl.


Deterministic subsample for the Shapiro-Wilk test

Description

stats::shapiro.test() has a hard cap of 5000 observations, so larger inputs are thinned to SHAPIRO_MAX_N evenly spaced values. The thinning is deterministic on purpose: a random subsample would make the reported p-values change between calls and silently consume the caller's RNG stream (breaking downstream reproducibility). Even spacing over the input order does not distort the marginal distribution being tested.

Usage

shapiro_subsample(x)

Arguments

x

numeric vector

Value

x itself when length(x) <= SHAPIRO_MAX_N, otherwise a deterministic subsample of length SHAPIRO_MAX_N


Skewness (divided by n)

Description

Skewness (divided by n)

Usage

skewness_pop(x)

Arguments

x

numeric vector


Summarize the goodness-of-fit of a Direct LiNGAM model at once

Description

For a fitted Direct LiNGAM model, this verifies how well the two main assumptions on which LiNGAM relies (mutual independence of residuals and non-Gaussianity of residuals) hold, all at once, and displays the results together. Internally it calls get_error_independence_p_values() and test_residual_normality().

Usage

summary_lingam(
  X,
  lingam_result,
  independence_method = "spearman",
  normality_method = "shapiro",
  alpha = 0.05
)

Arguments

X

The original data (matrix or data.frame), the one used to estimate lingam_result.

lingam_result

The return value of lingam_direct() (a LingamResult object)

independence_method

The type of correlation coefficient used in the residual independence test ("spearman", "pearson", "kendall"). Passed to get_error_independence_p_values().

normality_method

The method for the residual normality test ("shapiro", "ks", "ad", "lillie", "jb"). Passed to test_residual_normality().

alpha

Significance level (default: 0.05)

Details

Gaussian-likelihood-based criteria such as BIC/AIC are not included because they are theoretically inconsistent with LiNGAM's assumption that "the errors are non-Gaussian". Instead, the verification results of the assumptions themselves are summarized.

Value

A list of class lingam_summary, containing the following elements:

Examples

LiNGAM_sample_1000 <- generate_lingam_sample_6()

model <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")

summary_lingam(LiNGAM_sample_1000$data, model)

Test normality of residuals from Direct LiNGAM

Description

Calculate residuals (error terms) from the estimated adjacency matrix and test their normality. Since LiNGAM assumes non-Gaussian errors, rejecting normality (small p-value) supports the LiNGAM model assumption.

Usage

test_residual_normality(X, lingam_result, method = "shapiro", alpha = 0.05)

Arguments

X

original data matrix or data.frame

lingam_result

result from lingam_direct()

method

normality test method "shapiro" : Shapiro-Wilk test (default, n <= 5000) "ks" : Kolmogorov-Smirnov test (n > 5000) "ad" : Anderson-Darling test (requires nortest package) "lillie" : Lilliefors test (requires nortest package) "jb" : Jarque-Bera test (requires tseries package)

alpha

significance level (default: 0.05)

Value

data.frame with test results for each variable

Examples

# Load the sample data
LiNGAM_sample_1000 <- generate_lingam_sample_6()

# Run Direct LiNGAM
result <- lingam_direct(LiNGAM_sample_1000$data, reg_method = "ols")

# Shapiro-Wilk (default)
test_residual_normality(LiNGAM_sample_1000$data, result)

Test the non-Gaussianity of VAR-LiNGAM residuals

Description

LiNGAM assumes the error terms are non-Gaussian, so rejecting normality (small p-value) supports the model assumption. By default the test is run on the LiNGAM innovations ⁠e_t = (I - B0) n_t⁠ (the independent errors the model assumes), where n_t are the stored VAR residuals; set on = "var" to test the reduced-form VAR residuals n_t directly instead.

Usage

test_varlingam_residual_normality(
  result,
  method = "shapiro",
  alpha = 0.05,
  on = c("innovations", "var")
)

Arguments

result

a VARLiNGAMResult from lingam_var()

method

normality test ("shapiro", "ks", "ad", "lillie", "jb"); see test_residual_normality() for package requirements

alpha

significance level (default 0.05)

on

which series to test: "innovations" (default, ⁠e_t = (I - B0) n_t⁠) or "var" (the reduced-form VAR residuals n_t)

Value

a lingam_normality_test data frame (one row per variable), printed via print.lingam_normality_test().

References

Residual non-Gaussianity diagnostics inspired by the VARLiNGAM R code (Gauss_Tests) of Moneta, A., Entner, D., Hoyer, P. O., & Coad, A. (2013), Oxford Bulletin of Economics and Statistics, 75(5), 705-730. https://sites.google.com/site/dorisentner/publications/VARLiNGAM

Examples

s <- generate_varlingam_sample(n = 1000, seed = 42)
m <- lingam_var(s$data, lags = 1, reg_method = "ols", prune = FALSE)
test_varlingam_residual_normality(m)

Run several normality tests on VAR-LiNGAM residuals at once

Description

Convenience wrapper (analogous to the Moneta Gauss_Tests) that applies multiple normality tests to the residuals and returns a single table with one p-value column per method plus per-variable skewness and excess kurtosis. Methods whose optional package is unavailable are skipped with a warning.

Usage

test_varlingam_residual_normality_all(
  result,
  methods = c("shapiro", "ad", "lillie", "jb"),
  alpha = 0.05,
  on = c("innovations", "var")
)

Arguments

result

a VARLiNGAMResult from lingam_var()

methods

character vector of tests to run; any of "shapiro", "ks", "ad", "lillie", "jb" (default runs shapiro/ad/lillie/jb)

alpha

significance level (default 0.05)

on

which series to test: "innovations" (default) or "var"

Value

a data frame with columns variable, skewness, kurtosis, one ⁠p_<method>⁠ column per method, and all_non_gauss (TRUE when every run test rejects normality for that variable).

References

Analogous to the multi-test residual check (Gauss_Tests) in the VARLiNGAM R code of Moneta, A., Entner, D., Hoyer, P. O., & Coad, A. (2013), Oxford Bulletin of Economics and Statistics, 75(5), 705-730. https://sites.google.com/site/dorisentner/publications/VARLiNGAM

Examples

s <- generate_varlingam_sample(n = 1000, seed = 42)
m <- lingam_var(s$data, lags = 1, reg_method = "ols", prune = FALSE)
test_varlingam_residual_normality_all(m, methods = c("shapiro", "jb"))

Convert a BootstrapResult to a tidy data.frame

Description

Returns a summary of the occurrence count, proportion, and effect size for each causal direction. Internally it calls get_causal_direction_counts(), so that function's arguments can be passed through ....

Usage

## S3 method for class 'BootstrapResult'
tidy(x, ...)

Arguments

x

The return value of lingam_direct_bootstrap() (a BootstrapResult object)

...

Arguments passed to get_causal_direction_counts() (such as n_directions, min_causal_effect, split_by_causal_effect_sign, labels)

Value

data.frame (from, to, count, proportion, ...)

Examples

dat <- generate_lingam_sample_6()
bs <- lingam_direct_bootstrap(dat$data, n_sampling = 30L, reg_method = "ols", seed = 42)
tidy(bs)

Convert an ImputationBootstrapResult to a tidy data.frame

Description

Collapses the imputation dimension with as_bootstrap_result() and then summarizes the causal direction counts like tidy.BootstrapResult().

Usage

## S3 method for class 'ImputationBootstrapResult'
tidy(x, aggregate = c("median", "mean"), ...)

Arguments

x

The return value of bootstrap_with_imputation() (an ImputationBootstrapResult object)

aggregate

How to collapse the n_repeats imputation dimension, passed to as_bootstrap_result() ("median" or "mean")

...

Arguments passed to get_causal_direction_counts()

Value

data.frame (from, to, count, proportion, ...)

Examples


dat <- generate_lingam_sample_6(n = 200, seed = 1)$data
dat[sample(nrow(dat), 20), 1] <- NA
bs <- bootstrap_with_imputation(dat, n_sampling = 5L, n_repeats = 2L, seed = 42)
tidy(bs)


Convert a LiMResult to a tidy data.frame

Description

Converts the estimated adjacency matrix of a LiM model into a long-format data.frame with one edge per row, exactly like tidy.LingamResult().

Usage

## S3 method for class 'LiMResult'
tidy(x, threshold = 0, ...)

Arguments

x

The return value of lingam_lim() (a LiMResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

...

Unused

Value

data.frame(from, to, estimate)

Examples

set.seed(1)
dat <- generate_lim_sample(n = 300)
model <- lingam_lim(dat$data, is_continuous = dat$is_continuous)
tidy(model)

Convert a LingamResult to a tidy data.frame

Description

Converts the estimated adjacency matrix into a long-format data.frame with one edge per row. Following the B[i, j] convention (the coefficient for j -> i), the from column is the cause and the to column is the effect. Convenient for visualization with ggplot2 or ggraph and for filtering with dplyr.

Usage

## S3 method for class 'LingamResult'
tidy(x, threshold = 0, ...)

Arguments

x

The return value of lingam_direct() (a LingamResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

...

Unused

Value

data.frame(from, to, estimate). from/to are variable names (strings) and estimate is the causal coefficient. Returns a 0-row data.frame if there are no edges.

Examples

dat <- generate_lingam_sample_6()
model <- lingam_direct(dat$data, reg_method = "ols")
tidy(model)

Convert a MultiGroupBootstrapResult to a tidy data.frame

Description

Stacks each group's causal direction counts (via get_causal_direction_counts()) into a single data.frame with a group column in front. Arguments for get_causal_direction_counts() can be passed through ....

Usage

## S3 method for class 'MultiGroupBootstrapResult'
tidy(x, ...)

Arguments

x

The return value of lingam_multi_group_bootstrap() (a MultiGroupBootstrapResult object)

...

Arguments passed to get_causal_direction_counts() (such as n_directions, min_causal_effect, split_by_causal_effect_sign)

Value

data.frame (group, from, to, count, proportion, ...)

Examples

mg <- generate_multi_group_sample()
bs <- lingam_multi_group_bootstrap(mg$data_list,
  n_sampling = 10L, reg_method = "ols", seed = 42
)
tidy(bs)

Convert a MultiGroupLingamResult to a tidy data.frame

Description

Stacks the per-group edge lists into a single long-format data.frame with a group column in front, one edge per row per group (the causal order is shared across groups but the coefficients differ).

Usage

## S3 method for class 'MultiGroupLingamResult'
tidy(x, threshold = 0, ...)

Arguments

x

The return value of lingam_multi_group() (a MultiGroupLingamResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0)

...

Unused

Value

data.frame(group, from, to, estimate)

Examples

mg <- generate_multi_group_sample()
model <- lingam_multi_group(mg$data_list, reg_method = "ols")
tidy(model)

Convert a ParceLingamResult to a tidy data.frame

Description

Converts the estimated adjacency matrix into a long-format data.frame with one edge per row, like tidy.LingamResult(). NA entries of the adjacency matrix (variable pairs whose order could not be resolved / suspected latent confounding) are kept as rows with estimate = NA so they remain visible; drop them with e.g. subset(tidy(x), !is.na(estimate)) if not needed.

Usage

## S3 method for class 'ParceLingamResult'
tidy(x, threshold = 0, ...)

Arguments

x

The return value of lingam_parce() (a ParceLingamResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0). NA entries are always kept.

...

Unused

Value

data.frame(from, to, estimate)

Examples

dat <- generate_parce_sample(n = 500, seed = 42)
model <- lingam_parce(dat$data)
tidy(model)

Convert an RCDResult to a tidy data.frame

Description

Converts the estimated adjacency matrix into a long-format data.frame with one edge per row, like tidy.LingamResult(). NA entries of the adjacency matrix (variable pairs suspected to share a latent confounder; marked in both directions) are kept as rows with estimate = NA so they remain visible; drop them with e.g. subset(tidy(x), !is.na(estimate)) if not needed.

Usage

## S3 method for class 'RCDResult'
tidy(x, threshold = 0, ...)

Arguments

x

The return value of lingam_rcd() (an RCDResult object)

threshold

Coefficients with an absolute value at or below this are not treated as edges (default: 0). NA entries are always kept.

...

Unused

Value

data.frame(from, to, estimate)

Examples

confounded <- generate_rcd_sample(n = 300, seed = 1)
model <- lingam_rcd(confounded$data)
tidy(model)

Validate the return value of a cd_fit function

Description

Validate the return value of a cd_fit function

Usage

validate_cd_fit_output(cd_res, p, n_datasets)

Arguments

cd_res

Return value of cd_fit(X_list)

p

Number of features

n_datasets

Expected number of adjacency matrices (= number of imputed datasets)


Validate the return value of an imputer function

Description

Validate the return value of an imputer function

Usage

validate_imputer_output(datasets, X_boot)

Arguments

datasets

Return value of imputer(X_boot)

X_boot

The bootstrap-resampled data passed to imputer


Validate the return value of lingam_direct()

Description

Validate the return value of lingam_direct()

Usage

validate_lingam_result(x)

Reject constant or perfectly collinear columns

Description

Constant and linearly dependent columns produce divisions by zero inside the pairwise regressions / standardization of the causal order search, which would otherwise surface as cryptic errors (e.g. "argument is of length zero") deep in the algorithm. The rank check runs on the centered matrix so that a column equal to another column plus a constant offset is also caught.

Usage

validate_no_degenerate_columns(X)

Arguments

X

numeric matrix

Value

NULL, invisibly. Stops with an informative error on violation.


Validate the return value of lingam_parce()

Description

Validate the return value of lingam_parce()

Usage

validate_parce_result(x)

Validate a prior knowledge matrix and convert unknowns to NA

Description

Checks the shape and that every entry is -1 (unknown), 0 (no path), 1 (path), or NA (treated as unknown). Anything else (e.g. 0.5 or 2) would otherwise be silently interpreted as "path exists" by the candidate search, so it is rejected here.

Usage

validate_prior_knowledge(prior_knowledge, n_features)

Arguments

prior_knowledge

prior knowledge matrix

n_features

expected number of variables

Value

the validated matrix with negative entries replaced by NA


Validate the return value of lingam_rcd()

Description

Validate the return value of lingam_rcd()

Usage

validate_rcd_result(x)

Validate and coerce n / seed for the sample generation functions

Description

Validate and coerce n / seed for the sample generation functions

Usage

validate_sample_args(n, seed)

Arguments

n

sample size

seed

random seed

Value

list(n, seed) (both integers)


Total causal effect from a joined adjacency matrix (graph-based)

Description

Computes the total effect by summing path products over the time-expanded graph, reusing calculate_total_effect(). Port of the Python reference estimate_total_effect2; used internally by the VAR-LiNGAM bootstrap.

Usage

var_total_effect_graph(am_joined, from_index, to_index)

Arguments

am_joined

joined adjacency matrix (n_features x n_features*(1 + lags)), B[i, j] is the coefficient of j -> i

from_index

source column in the joined index space (1-based)

to_index

destination column in the joined index space (1-based)

Value

the total effect (scalar)


Build a zero-adjacency LingamResult

Description

A stand-in LingamResult whose adjacency matrix is all zeros, so that lingam_residuals() returns its input unchanged. This lets the VAR diagnostics reuse the Direct LiNGAM residual routines on an already-computed residual matrix.

Usage

zero_lingam_result(p)

Arguments

p

number of features

Value

a LingamResult with a p x p zero adjacency matrix