BBN Generation

BBN generation is available in py-scm. We support singly- and multi-connected Gaussian BBNs.

Singly-connected BBN

Use generate_singly_gaussian_bbn() to generate a singly-connected Gaussian BBN and then use create_reasoning_model() to create a reasoning model.

This example uses max_iter=20 so the generated tree is more illustrative than the initial ordered chain.

[1]:
from help.viz import get_graph_layout, to_networkx
import matplotlib.pyplot as plt
import networkx as nx
from pyscm.generator import generate_singly_gaussian_bbn
from pyscm.reasoning import create_reasoning_model

generated = generate_singly_gaussian_bbn(
    n=10,
    max_iter=20,
    seed=37,
    max_degree=3,
    max_condition_number=25.0,
)

g = generated.graph
p = generated.parameters

model = create_reasoning_model(g, p)

The singly-connected BBN graph looks like the following.

[2]:
dag = to_networkx(g)

fig, ax = plt.subplots(figsize=(8.0, 6.75))

pos = get_graph_layout(dag, seed=37)
nx.draw(
    dag,
    pos=pos,
    with_labels=True,
    node_color="#e0e0e0",
    node_size=1700,
    font_size=10,
    arrows=True,
    arrowsize=18,
    ax=ax,
)

ax.margins(x=0.10, y=0.18)
fig.tight_layout()
_images/generate_4_0.png

Posterior queries proceed as usual.

[3]:
means, covariance = model.pquery({"X1": 0.5}, pandas=True)
means.to_frame("mean")
[3]:
mean
X0 0.448743
X1 0.500000
X2 0.235416
X3 -0.670662
X4 -0.602994
X5 -0.064449
X6 0.261791
X7 0.194697
X8 -0.158753
X9 0.323203
[4]:
model.iquery("X9", {"X1": 1.25}, pandas=True)
[4]:
mean    0.346223
std     0.445736
dtype: float64

Multi-connected BBN

Use generate_multi_gaussian_bbn() to generate a multi-connected Gaussian BBN and then use create_reasoning_model() to create a reasoning model.

This example also uses max_iter=20, and the fixed seed below keeps the example reproducible while avoiding a near-chain structure.

[5]:
from pyscm.generator import generate_multi_gaussian_bbn

generated = generate_multi_gaussian_bbn(
    n=10,
    max_iter=20,
    seed=3,
    max_degree=4,
    intercept_mean=0.25,
    intercept_sd=0.2,
    weight_mean=0.0,
    weight_sd=0.3,
    noise_sd_min=0.4,
    noise_sd_max=0.8,
    max_condition_number=25.0,
)

g = generated.graph
p = generated.parameters

model = create_reasoning_model(g, p)

The multi-connected BBN graph looks like the following.

[6]:
dag = to_networkx(g)

fig, ax = plt.subplots(figsize=(8.0, 6.75))

pos = get_graph_layout(dag, seed=37)
nx.draw(
    dag,
    pos=pos,
    with_labels=True,
    node_color="#e0e0e0",
    node_size=1700,
    font_size=10,
    arrows=True,
    arrowsize=18,
    ax=ax,
)

ax.margins(x=0.10, y=0.18)
fig.tight_layout()
_images/generate_11_0.png
[7]:
model.equery("X9", {"X1": 1.0}, {"X1": -1.0}, pandas=True)
[7]:
mean   -0.065951
std     0.000000
dtype: float64
[8]:
model.samples(size=10).head()
[8]:
X0 X1 X2 X3 X4 X5 X6 X7 X8 X9
0 -0.556711 1.441756 1.197602 1.866988 1.280589 1.494780 0.098026 -1.253835 1.353719 -0.212623
1 -0.197582 0.442962 0.409467 0.598435 0.287417 -0.534240 -0.379872 -0.264745 -0.311271 -1.134408
2 0.932308 -0.675724 0.050717 -0.025196 1.192979 0.476395 0.155484 0.517682 0.180630 1.389682
3 0.999141 0.412904 0.997719 0.746910 1.027509 -0.066919 0.186078 -0.061389 -0.409386 0.091236
4 0.063324 0.269446 0.948745 0.565484 0.967308 -0.756124 -0.774144 -0.307976 -0.050875 1.624334