Purpose: demonstrate approximate inference

Simple example with known parameters and structure

This example creates two variables with defined parameters (means and covariances) and structure.


In [1]:
import numpy as np
from pybbn.lg.graph import Dag, Parameters, Bbn

# create the directed acylic graph
dag = Dag()
dag.add_node(0)
dag.add_node(1)
dag.add_edge(0, 1)

# create parameters
means = np.array([0, 25])
cov = np.array([
    [1.09, 1.95],
    [1.95, 4.52]
])
params = Parameters(means, cov)

# create the bayesian belief network
bbn = Bbn(dag, params)

# do the inference
M, S = bbn.do_inference()
print(M)

# set the evidence on node 0 to a value of 1
bbn.set_evidence(0, 1)
M, S = bbn.do_inference()
print(M)
bbn.clear_evidences()

# set the evidence on node 1 to a value of 20
bbn.set_evidence(1, 20)
M, S = bbn.do_inference()
print(M)
bbn.clear_evidences()


[ 0 25]
[ 1 26]
[-2 20]

Example with learned parameters and known structure

This example simulates data and then computes the means and covariances to be used as the parameter input. The structure is given as follows.

  • $X_1 \rightarrow X_3$
  • $X_2 \rightarrow X_3$
  • $X_3 \rightarrow X_4$

The data is sampled as follows.

  • $X_1 \sim \mathcal{N}(0, 1)$
  • $X_2 \sim \mathcal{N}(2, 2)$
  • $X_3 \sim \mathcal{N}(1.0 + 0.8 X_1 + 0.2 X_2, 1)$
  • $X_4 \sim \mathcal{N}(0.9 X_3, 1)$

In [2]:
import numpy as np
from numpy.random import normal
import pandas as pd

In [3]:
np.random.seed(37)
N = 1000
x1 = normal(0, 1, N)
x2 = normal(2, 2, N)
x3 = normal(1.0 + 0.8 * x1 + 0.2 * x2, 1, N)
x4 = normal(0.9 * x3, 1, N)
df = pd.DataFrame({
    'x1': x1,
    'x2': x2,
    'x3': x3,
    'x4': x4
})

In [4]:
dag = Dag()
dag.add_node(0)
dag.add_node(1)
dag.add_node(2)
dag.add_node(3)
dag.add_edge(0, 2)
dag.add_edge(1, 2)
dag.add_edge(2, 3)

# create parameters
means = np.array(list(df.mean()))
cov = df.cov().values
params = Parameters(means, cov)

print('means: {}'.format(means))
print('cov: {}'.format(cov))

# create the bayesian belief network
bbn = Bbn(dag, params)

# do the inference
print('doing inference with and without evidence')
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))

bbn.set_evidence(2, 1.0)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()

bbn.set_evidence(3, 0.5)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()

bbn.set_evidence(0, 0)
bbn.set_evidence(2, 0.5)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()


means: [0.01277839 1.96783059 1.39369055 1.25516026]
cov: [[ 0.9634615  -0.00742708  0.75799913  0.60274112]
 [-0.00742708  3.91462611  0.67076612  0.52561797]
 [ 0.75799913  0.67076612  1.6807885   1.39650737]
 [ 0.60274112  0.52561797  1.39650737  2.15634038]]
doing inference with and without evidence
>
means: [0.01277839 1.96783059 1.39369055 1.25516026]
cov: [[ 0.9634615  -0.00742708  0.75799913  0.60274112]
 [-0.00742708  3.91462611  0.67076612  0.52561797]
 [ 0.75799913  0.67076612  1.6807885   1.39650737]
 [ 0.60274112  0.52561797  1.39650737  2.15634038]]
>
means: [-0.16476751  1.81071726  1.          0.92805679]
cov: [[ 0.62162034 -0.30992804  0.75799913 -0.02705339]
 [-0.30992804  3.64693794  0.67076612 -0.03169774]
 [ 0.75799913  0.67076612  0.01        1.39650737]
 [-0.02705339 -0.03169774  1.39650737  0.99603208]]
>
means: [-0.19830431  1.78375677  0.90462728  0.5       ]
cov: [[ 0.79498306 -0.15434802  0.36764683  0.60274112]
 [-0.15434802  3.78650429  0.33036097  0.52561797]
 [ 0.36764683  0.33036097  0.7763706   1.39650737]
 [ 0.60274112  0.52561797  1.39650737  0.01      ]]
>
means: [0.         1.41660362 0.5        0.49564031]
cov: [[ 0.01       -0.00742708  0.75799913  0.60274112]
 [-0.00742708  3.49241374  0.67076612 -0.04518604]
 [ 0.75799913  0.67076612  0.01        1.39650737]
 [ 0.60274112 -0.04518604  1.39650737  0.9948547 ]]

Example with learned parameters and learned structure

This is a simple example of learning the parameters (as before above) and structure using a simple maximum-weight spanning tree algorithm. Note that arc-orientation is simply the order given to it.

True Model

  • $X_1 \rightarrow X_3$
  • $X_2 \rightarrow X_3$
  • $X_3 \rightarrow X_4$

Learned Model: arc commission error with $X_1 \rightarrow X_2$, arc omission error with $X_2 \rightarrow X_3$

  • $X_1 \rightarrow X_3$
  • $X_1 \rightarrow X_2$
  • $X_3 \rightarrow X_4$

In [5]:
def to_edge_list(df):
    data = []
    corr_matrix = df.corr().values
    num_vars = corr_matrix.shape[0]
    for i in range(num_vars):
        for j in range(num_vars):
            if j > i:
                t = (i, j, abs(corr_matrix[i, j]))
                data.append(t)
    return data

def learn_structure(num_vars, edge_list):
    # add all nodes
    dag = Dag()
    for i in range(num_vars):
        dag.add_node(i)
    
    # add edges using maximum weight spanning tree algorithm
    for edge in edge_list:
        try:
            dag.add_edge(edge[0], edge[1])
        except ValueError:
            pass
        if len(dag.g.edges()) == num_vars - 1:
            break
    
    return dag

In [6]:
edge_list = sorted(to_edge_list(df), key=lambda tup: tup[2], reverse=True)
print(edge_list)


[(2, 3, 0.7335471611852428), (0, 2, 0.5956552726580833), (0, 3, 0.4181720299771823), (1, 2, 0.2614986442653267), (1, 3, 0.18091159589992045), (0, 1, 0.003824331204180586)]

In [7]:
dag = learn_structure(df.shape[1], edge_list)

In [8]:
dag.g.nodes()


Out[8]:
NodeView((0, 1, 2, 3))

In [9]:
dag.g.edges()


Out[9]:
OutEdgeView([(0, 2), (0, 3), (2, 3)])

In [10]:
# create the bayesian belief network
bbn = Bbn(dag, params)

# do the inference
print('inferences')
M, C = bbn.do_inference()
print('means: {}'.format(M))
print('cov: {}'.format(C))

bbn.set_evidence(2, 1.0)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()

bbn.set_evidence(3, 0.5)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()

bbn.set_evidence(0, 0)
bbn.set_evidence(2, 0.5)
M, C = bbn.do_inference()
print('>')
print('means: {}'.format(M))
print('cov: {}'.format(C))
bbn.clear_evidences()


inferences
means: [0.01277839 1.96783059 1.39369055 1.25516026]
cov: [[ 0.9634615  -0.00742708  0.75799913  0.60274112]
 [-0.00742708  3.91462611  0.67076612  0.52561797]
 [ 0.75799913  0.67076612  1.6807885   1.39650737]
 [ 0.60274112  0.52561797  1.39650737  2.15634038]]
>
means: [-0.16476751  1.81071726  1.          0.92805679]
cov: [[ 0.62162034 -0.30992804  0.75799913 -0.02705339]
 [-0.30992804  3.64693794  0.67076612 -0.03169774]
 [ 0.75799913  0.67076612  0.01        1.39650737]
 [-0.02705339 -0.03169774  1.39650737  0.99603208]]
>
means: [-0.19830431  1.78375677  0.90462728  0.5       ]
cov: [[ 0.79498306 -0.15434802  0.36764683  0.60274112]
 [-0.15434802  3.78650429  0.33036097  0.52561797]
 [ 0.36764683  0.33036097  0.7763706   1.39650737]
 [ 0.60274112  0.52561797  1.39650737  0.01      ]]
>
means: [0.         1.41660362 0.5        0.49564031]
cov: [[ 0.01       -0.00742708  0.75799913  0.60274112]
 [-0.00742708  3.49241374  0.67076612 -0.04518604]
 [ 0.75799913  0.67076612  0.01        1.39650737]
 [ 0.60274112 -0.04518604  1.39650737  0.9948547 ]]

In [ ]: