Click here to hide/show the list of notebooks.
  pyAgrum on notebooks   pyAgrum jupyter
☰  dynamicBn 
pyAgrum 0.16.2   
Zipped notebooks   
generation: 2019-10-02 10:58  

Creative Commons License
This pyAgrum's notebook is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

dynamic Bayesian Networks with pyAgrum

In [1]:
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb
import pyAgrum.lib.dynamicBN as gdyn
%matplotlib inline

Building a 2TBN

Note the naming convention for a 2TBN : a variable with a name $A$ is present at t=0 with the name $A0$ and at time t as $At$.

In [2]:
twodbn=gum.BayesNet()
a0,b0,c0,at,bt,ct=[twodbn.add(gum.LabelizedVariable(s,s,6)) 
                   for s in ["a0","b0","c0","at","bt","ct"]]
d0,dt=[twodbn.add(gum.LabelizedVariable(s,s,3)) 
       for s in ["d0","dt"]]

twodbn.addArc(a0,b0)

twodbn.addArc(c0,d0)
twodbn.addArc(c0,at)

twodbn.addArc(a0,at)
twodbn.addArc(a0,bt)
twodbn.addArc(a0,dt)
twodbn.addArc(b0,bt)
twodbn.addArc(c0,ct)
twodbn.addArc(d0,ct)
twodbn.addArc(d0,dt)

twodbn.addArc(at,ct)
twodbn.generateCPTs()

gnb.showBN(twodbn)
G a0 a0 b0 b0 a0->b0 at at a0->at bt bt a0->bt dt dt a0->dt b0->bt c0 c0 c0->at ct ct c0->ct d0 d0 c0->d0 at->ct d0->ct d0->dt

2TBN

The dbn above actually is a 2TBN and is not correctly shown as a BN. Using the naming convention, it can be shown as a 2TBN.

In [3]:
gdyn.showTimeSlices(twodbn)
G cluster_0 Time slice 0 cluster_t Time slice t a0 a b0 b a0->b0 at a a0->at bt b a0->bt dt d a0->dt c0 c b0->bt d0 d c0->d0 c0->at ct c c0->ct d0->ct d0->dt at->ct

unrolling 2TBN

A dBN is 'unrolled' using the 2TBN and the time period size. For a couple $a_0$,$a_t$ in the 2TBN, the unrolled dBN will include $a_0, a_1, \cdots, a_{T-1}$

In [4]:
T=5

dbn=gdyn.unroll2TBN(twodbn,T)
gdyn.showTimeSlices(dbn,size="10")
G cluster_0 Time slice 0 cluster_1 Time slice 1 cluster_2 Time slice 2 cluster_3 Time slice 3 cluster_4 Time slice 4 a0 a b0 b a0->b0 a1 a a0->a1 b1 b a0->b1 d1 d a0->d1 c0 c b0->b1 d0 d c0->d0 c0->a1 c1 c c0->c1 d0->c1 d0->d1 a1->c1 a2 a a1->a2 b2 b a1->b2 d2 d a1->d2 b1->b2 c1->a2 c2 c c1->c2 d1->c2 d1->d2 a2->c2 a3 a a2->a3 b3 b a2->b3 d3 d a2->d3 b2->b3 c2->a3 c3 c c2->c3 d2->c3 d2->d3 a3->c3 a4 a a3->a4 b4 b a3->b4 d4 d a3->d4 b3->b4 c3->a4 c4 c c3->c4 d3->c4 d3->d4 a4->c4

We can infer on bn just as on a normal bn. Following the naming convention in 2TBN, the variables in a dbN are named using the convention $a_i$ where $i$ is the number of their time slice.

In [5]:
for i in range(T):
    gnb.showPosterior(dbn,target="d{}".format(i),evs={})

dynamic inference : following variables

gdyn.plotFollow directly ask for the 2TBN, unroll it and add evidence evs. Then it shows the dynamic of variable $a$ for instance by plotting $a_0,a_1,\cdots,a_{T-1}$.

In [6]:
import matplotlib.pyplot as plt

plt.rcParams['figure.figsize'] = (10, 2)
gdyn.plotFollow(["a","b","c","d"],twodbn,T=51,evs={'a9':2,'a30':0,'c14':0,'b40':0,'c50':3})  

nsDBN (Non-Stationnary Dynamic Bayesian Network)

In [7]:
T=15

dbn=gdyn.unroll2TBN(twodbn,T)
gdyn.showTimeSlices(dbn,size="14")
G cluster_0 Time slice 0 cluster_1 Time slice 1 cluster_2 Time slice 2 cluster_3 Time slice 3 cluster_4 Time slice 4 cluster_5 Time slice 5 cluster_6 Time slice 6 cluster_7 Time slice 7 cluster_8 Time slice 8 cluster_9 Time slice 9 cluster_10 Time slice 10 cluster_11 Time slice 11 cluster_12 Time slice 12 cluster_13 Time slice 13 cluster_14 Time slice 14 a0 a b0 b a0->b0 a1 a a0->a1 b1 b a0->b1 d1 d a0->d1 c0 c b0->b1 d0 d c0->d0 c0->a1 c1 c c0->c1 d0->c1 d0->d1 a1->c1 a2 a a1->a2 b2 b a1->b2 d2 d a1->d2 b1->b2 c1->a2 c2 c c1->c2 d1->c2 d1->d2 a2->c2 a3 a a2->a3 b3 b a2->b3 d3 d a2->d3 b2->b3 c2->a3 c3 c c2->c3 d2->c3 d2->d3 a3->c3 a4 a a3->a4 b4 b a3->b4 d4 d a3->d4 b3->b4 c3->a4 c4 c c3->c4 d3->c4 d3->d4 a4->c4 a5 a a4->a5 b5 b a4->b5 d5 d a4->d5 b4->b5 c4->a5 c5 c c4->c5 d4->c5 d4->d5 a5->c5 a6 a a5->a6 b6 b a5->b6 d6 d a5->d6 b5->b6 c5->a6 c6 c c5->c6 d5->c6 d5->d6 a6->c6 a7 a a6->a7 b7 b a6->b7 d7 d a6->d7 b6->b7 c6->a7 c7 c c6->c7 d6->c7 d6->d7 a7->c7 a8 a a7->a8 b8 b a7->b8 d8 d a7->d8 b7->b8 c7->a8 c8 c c7->c8 d7->c8 d7->d8 a8->c8 a9 a a8->a9 b9 b a8->b9 d9 d a8->d9 b8->b9 c8->a9 c9 c c8->c9 d8->c9 d8->d9 a9->c9 a10 a a9->a10 b10 b a9->b10 d10 d a9->d10 b9->b10 c9->a10 c10 c c9->c10 d9->c10 d9->d10 a10->c10 a11 a a10->a11 b11 b a10->b11 d11 d a10->d11 b10->b11 c10->a11 c11 c c10->c11 d10->c11 d10->d11 a11->c11 a12 a a11->a12 b12 b a11->b12 d12 d a11->d12 b11->b12 c11->a12 c12 c c11->c12 d11->c12 d11->d12 a12->c12 a13 a a12->a13 b13 b a12->b13 d13 d a12->d13 b12->b13 c12->a13 c13 c c12->c13 d12->c13 d12->d13 a13->c13 a14 a a13->a14 b14 b a13->b14 d14 d a13->d14 b13->b14 c13->a14 c14 c c13->c14 d13->c14 d13->d14 a14->c14

Non-stationnaty DBN allows to express that the dBN do not follow the same 2TBN during all steps. A unrolled dbn is a classical BayesNet and then can be changed as you want after unrolling.

In [8]:
# new P(ct|c0) 
pot=gum.Potential().add(twodbn.variableFromName("ct")).add(twodbn.variableFromName("c0"))  
pot.fillWith([1,0,0,0.1]*9).normalizeAsCPT() # 36 valeurs normalized as CPT
Out[8]:
ct
c0
0
1
2
3
4
5
0
0.47620.00000.00000.04760.47620.0000
1
0.00000.08330.83330.00000.00000.0833
2
0.47620.00000.00000.04760.47620.0000
3
0.00000.08330.83330.00000.00000.0833
4
0.47620.00000.00000.04760.47620.0000
5
0.00000.08330.83330.00000.00000.0833
In [9]:
# from steps 5 to 10, $C_t$ only depends on $C_{t-1}$ and follows this new CPT
for i in range(5,11):
    dbn.eraseArc(f"d{i-1}",f"c{i}")
    dbn.eraseArc(f"a{i}",f"c{i}")
    dbn.cpt(f"c{i}").fillWith(pot,["ct","c0"]) # ct in pot <- first var of cpt, c0 in pot<-second var in cpt
    
gdyn.showTimeSlices(dbn,size="14")
G cluster_0 Time slice 0 cluster_1 Time slice 1 cluster_2 Time slice 2 cluster_3 Time slice 3 cluster_4 Time slice 4 cluster_5 Time slice 5 cluster_6 Time slice 6 cluster_7 Time slice 7 cluster_8 Time slice 8 cluster_9 Time slice 9 cluster_10 Time slice 10 cluster_11 Time slice 11 cluster_12 Time slice 12 cluster_13 Time slice 13 cluster_14 Time slice 14 a0 a b0 b a0->b0 a1 a a0->a1 b1 b a0->b1 d1 d a0->d1 c0 c b0->b1 d0 d c0->d0 c0->a1 c1 c c0->c1 d0->c1 d0->d1 a1->c1 a2 a a1->a2 b2 b a1->b2 d2 d a1->d2 b1->b2 c1->a2 c2 c c1->c2 d1->c2 d1->d2 a2->c2 a3 a a2->a3 b3 b a2->b3 d3 d a2->d3 b2->b3 c2->a3 c3 c c2->c3 d2->c3 d2->d3 a3->c3 a4 a a3->a4 b4 b a3->b4 d4 d a3->d4 b3->b4 c3->a4 c4 c c3->c4 d3->c4 d3->d4 a4->c4 a5 a a4->a5 b5 b a4->b5 d5 d a4->d5 b4->b5 c4->a5 c5 c c4->c5 d4->d5 a6 a a5->a6 b6 b a5->b6 d6 d a5->d6 b5->b6 c5->a6 c6 c c5->c6 d5->d6 a7 a a6->a7 b7 b a6->b7 d7 d a6->d7 b6->b7 c6->a7 c7 c c6->c7 d6->d7 a8 a a7->a8 b8 b a7->b8 d8 d a7->d8 b7->b8 c7->a8 c8 c c7->c8 d7->d8 a9 a a8->a9 b9 b a8->b9 d9 d a8->d9 b8->b9 c8->a9 c9 c c8->c9 d8->d9 a10 a a9->a10 b10 b a9->b10 d10 d a9->d10 b9->b10 c9->a10 c10 c c9->c10 d9->d10 a11 a a10->a11 b11 b a10->b11 d11 d a10->d11 b10->b11 c10->a11 c11 c c10->c11 d10->c11 d10->d11 a11->c11 a12 a a11->a12 b12 b a11->b12 d12 d a11->d12 b11->b12 c11->a12 c12 c c11->c12 d11->c12 d11->d12 a12->c12 a13 a a12->a13 b13 b a12->b13 d13 d a12->d13 b12->b13 c12->a13 c13 c c12->c13 d12->c13 d12->d13 a13->c13 a14 a a13->a14 b14 b a13->b14 d14 d a13->d14 b13->b14 c13->a14 c14 c c13->c14 d13->c14 d13->d14 a14->c14
In [10]:
plt.rcParams['figure.figsize'] = (10, 2)
gdyn.plotFollowUnrolled(["a","b","c","d"],dbn,T=15,evs={'a9':2,'c14':0})  
In [ ]: