sempler.ANM

The sempler.ANM class allows to define and sample from general additive noise models. Any assignment function is possible, as are the noise term distributions. The underlying graph is assumed to be acyclic.

The ANM is represented by (1) the adjacency matrix of the underlying graph, (2) the assignment functions, and (3) the distribution of the noise terms.

class sempler.ANM(A, assignments, noise_distributions)

Class to represent a general (acyclic) additive noise model.

Parameters:
  • A (numpy.ndarray) – The p x p adjacency matrix specifying the functional dependencies, where p is the number of variables and A[i,j] != 0 if i appears in the assignment of j (i.e. i -> j).

  • assignments (list of (function or None)) – A list of p functions representing the functional assignments of each variable. Each function must take a vector of observations where each column corresponds to a parent as specified by the adjacency matrix A, or be None or sempler.functions.null if the variable has no parents.

  • noise_distributions (list of function) – A list of p functions that generate samples from each variable’s noise distribution (see sempler.noise for details).

Raises:

ValueError – If the given adjacency does not correspond to a DAG.

Example

Constructing an ANM.

>>> import sempler
>>> import sempler.noise as noise
>>> import numpy as np
  1. Define the connectivity matrix:

>>> A = np.array([[0, 0, 0, 1, 0],
...               [0, 0, 1, 0, 0],
...               [0, 0, 0, 1, 0],
...               [0, 0, 0, 0, 1],
...               [0, 0, 0, 0, 0]])
  1. Define the noise distributions (see sempler.noise):

>>> noise_distributions = [noise.normal(0,1)] * 5
  1. Define the variable assignments:

>>> assignments = [None, None, np.sin, lambda x: np.exp(x[:,0]) + 2*x[:,1], lambda x: 2*x]

Putting it all together:

>>> anm = sempler.ANM(A, assignments, noise_distributions)

An exception is raised if the adjacency matrix does not belong to a DAG:

>>> A[4,0] = 1
>>> sempler.LGANM(A, (0,0), (1,1))
Traceback (most recent call last):
  ...
ValueError: The given graph is not a DAG.
A

The adjacency matrix specifying the functional dependencies.

Type:

numpy.ndarray

p

The number of variables (size) of the SCM.

Type:

int

assignments

The assignment functions of the variables.

Type:

list of function

noise_distributions

A list of functions representing the noise term distribution of each variable (see sempler.noise).

Type:

list of function

sample(n, do_interventions={}, shift_interventions={}, noise_interventions={}, random_state=None)

Generates i.i.d. observations from the ANM, under the given do, shift or noise interventions. If no interventions are given, sample from the observational distribution.

Parameters:
  • n (int) – The size of the sample (i.e. number of observations).

  • do_interventions (dict, optional) – A dictionary where keys correspond to the intervened variables, and the values are the distribution functions (see sempler.noise) to generate samples for each intervened variable.

  • shift_interventions (dict, optional) – A dictionary where keys correspond to the intervened variables, and the values are the distribution functions (see sempler.noise) to generate noise samples which are added to the intervened variables.

  • noise_interventions (dict, optional) – A dictionary where keys correspond to the intervened variables, and the values are the distribution functions (see sempler.noise) of the new noise.

  • random_state (int, optional) – To set the random state for reproducibility, i.e. successive calls will return the same sample.

Returns:

An array containing the sample, with each column corresponding to a variable.

Return type:

numpy.ndarray

Examples

Sampling from the observational setting:

>>> samples = anm.sample(100)

Sampling under a shift intervention on variable 1:

>>> import sempler.noise as noise
>>> samples = anm.sample(100, shift_interventions = {1: noise.normal(0,1)})

Sampling under a noise intervention on variable 0 and a do intervention on variable 2:

>>> samples = anm.sample(100,
...                      noise_interventions = {0: noise.normal()},
...                      do_interventions = {2 : noise.uniform()})