Click here to hide/show the list of notebooks.
  pyAgrum on notebooks   pyAgrum jupyter
☰  relevanceReasoning 
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.

Relevance Reasoning with pyAgrum

Relevance reasoning is the analysis of the influence of evidence on a Bayesian Network.

In this notebook we will explain what is relevance reasoning and how to do it using pyAgrum.

In [1]:
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb

import time
import os
%matplotlib inline
from pylab import *
import matplotlib.pyplot as plt

Multiple inference

In the well known 'alarm' BN, how to analyze the influence on 'VENTALV' of a soft evidence on 'MINVOLSET' ?

In [2]:
bn=gum.loadBN(os.path.join("res","alarm.dsl"))
gnb.showBN(bn,size="6")
G KINKEDTUBE KINKEDTUBE VENTLUNG VENTLUNG KINKEDTUBE->VENTLUNG PRESS PRESS KINKEDTUBE->PRESS HYPOVOLEMIA HYPOVOLEMIA STROKEVOLUME STROKEVOLUME HYPOVOLEMIA->STROKEVOLUME LVEDVOLUME LVEDVOLUME HYPOVOLEMIA->LVEDVOLUME INTUBATION INTUBATION SHUNT SHUNT INTUBATION->SHUNT INTUBATION->VENTLUNG MINVOL MINVOL INTUBATION->MINVOL INTUBATION->PRESS VENTALV VENTALV INTUBATION->VENTALV MINVOLSET MINVOLSET VENTMACH VENTMACH MINVOLSET->VENTMACH PULMEMBOLUS PULMEMBOLUS PAP PAP PULMEMBOLUS->PAP PULMEMBOLUS->SHUNT INSUFFANESTH INSUFFANESTH CATECHOL CATECHOL INSUFFANESTH->CATECHOL ERRLOWOUTPUT ERRLOWOUTPUT HRBP HRBP ERRLOWOUTPUT->HRBP ERRCAUTER ERRCAUTER HRSAT HRSAT ERRCAUTER->HRSAT HREKG HREKG ERRCAUTER->HREKG FIO2 FIO2 PVSAT PVSAT FIO2->PVSAT LVFAILURE LVFAILURE LVFAILURE->STROKEVOLUME LVFAILURE->LVEDVOLUME HISTORY HISTORY LVFAILURE->HISTORY DISCONNECT DISCONNECT VENTTUBE VENTTUBE DISCONNECT->VENTTUBE ANAPHYLAXIS ANAPHYLAXIS TPR TPR ANAPHYLAXIS->TPR CO CO STROKEVOLUME->CO TPR->CATECHOL BP BP TPR->BP PCWP PCWP LVEDVOLUME->PCWP CVP CVP LVEDVOLUME->CVP VENTMACH->VENTTUBE SAO2 SAO2 SHUNT->SAO2 VENTTUBE->VENTLUNG VENTTUBE->PRESS VENTLUNG->MINVOL VENTLUNG->VENTALV EXPCO2 EXPCO2 VENTLUNG->EXPCO2 ARTCO2 ARTCO2 VENTALV->ARTCO2 VENTALV->PVSAT ARTCO2->EXPCO2 ARTCO2->CATECHOL PVSAT->SAO2 SAO2->CATECHOL HR HR CATECHOL->HR HR->HRBP HR->HRSAT HR->CO HR->HREKG CO->BP

We propose to draw the plot of the posterior of 'VENTALV' for the evidence : $$\forall x \in [0,1], e_{MINVOLSET}=[0,x,0.5]$$

To do so, we perform a large number of inference and plot the posteriors.

In [3]:
K=1000
r=range(0,K)
xs=[x/K for x in r]

def getPlot(xs,ys,K,duration):
    p=plot(xs,ys)
    legend(p,[bn.variableFromName('VENTALV').label(i) 
              for i in range(bn.variableFromName('VENTALV').domainSize())],loc=7);
    title('VENTALV ({} inferences in {} s)'.format(K,duration));
    ylabel('posterior Probability');
    xlabel('Evidence on MINVOLSET : [0,x,0.5]');

First try : classical lazy inference

In [4]:
tf=time.time()
ys=[]
for x in r:
    ie=gum.LazyPropagation(bn)
    ie.addEvidence('MINVOLSET',[0,x/K,0.5])
    ie.makeInference()
    ys.append(ie.posterior('VENTALV').tolist())
delta1=time.time()-tf
getPlot(xs,ys,K,delta1)

Second try : classical variable elimination

One can note that we just need one posterior. This is a case where VariableElimination should give best results.

In [5]:
tf=time.time()
ys=[]
for x in r:
    ie=gum.VariableElimination(bn)
    ie.addEvidence('MINVOLSET',[0,x/K,0.5])
    ie.makeInference()
    ys.append(ie.posterior('VENTALV').tolist())
delta2=time.time()-tf
getPlot(xs,ys,K,delta2)

pyAgrum give us a function gum.getPosterior to do this same job more easily.

In [6]:
tf=time.time()
ys=[gum.getPosterior(bn,{'MINVOLSET':[0,x/K,0.5]},'VENTALV').tolist() 
        for x in r]
getPlot(xs,ys,K,time.time()-tf)

Last try : optimized Lazy propagation with relevance reasoning and incremental inference

Optimized inference in aGrUM can use the targets and the evidence to optimize the computations. This is called relevance reasonning.

Moreover, if the values of the evidence change but not the structure of the query (same nodes as target, same nodes as hard evidence, same nodes as soft evidence), inference in aGrUM may re-use some of the computations from a query to another. This is called incremental inference.

In [7]:
tf=time.time()
ie=gum.VariableElimination(bn)
ie.addEvidence('MINVOLSET',[1,1,1])
ie.addTarget('VENTALV')
ys=[]
for x in r:
    ie.chgEvidence('MINVOLSET',[0,x/K,0.5])
    ie.makeInference()
    ys.append(ie.posterior('VENTALV').tolist())
delta3=time.time()-tf
getPlot(xs,ys,K,delta3)
In [8]:
print("Mean duration of a lazy propagation            : {:5.3f}ms".format(1000*delta1/K))
print("Mean duration of a variable elimination        : {:5.3f}ms".format(1000*delta2/K))
print("Mean duration of an optimized lazy propagation : {:5.3f}ms".format(1000*delta3/K))
Mean duration of a lazy propagation            : 4.895ms
Mean duration of a variable elimination        : 1.274ms
Mean duration of an optimized lazy propagation : 0.793ms

How it works

In [9]:
bn=gum.fastBN("Y->X->T1;Z2->X;Z1->X;Z1->T1;Z1->Z3->T2")
ie=gum.LazyPropagation(bn)

gnb.sideBySide(bn,
               bn.cpt("X"),
               gnb.getJunctionTree(bn),
               captions=["BN","potential","Junction Tree"])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
X
Z1
Z2
Y
0
1
0
0
0
0.22720.7728
1
0.27150.7285
1
0
0.49130.5087
1
0.50350.4965
1
0
0
0.66460.3354
1
0.39130.6087
1
0
0.70370.2963
1
0.45730.5427
G (0) 3-1-4-0 Z2 X Z1 Y (0) 3-1-4-0^(5) 4-5 Z1 (0) 3-1-4-0--(0) 3-1-4-0^(5) 4-5 (0) 3-1-4-0^(2) 1-2-4 X Z1 (0) 3-1-4-0--(0) 3-1-4-0^(2) 1-2-4 (1) 6-5 T2 Z3 (1) 6-5^(5) 4-5 Z3 (1) 6-5--(1) 6-5^(5) 4-5 (2) 1-2-4 X T1 Z1 (5) 4-5 Z1 Z3 (1) 6-5^(5) 4-5--(5) 4-5 (0) 3-1-4-0^(5) 4-5--(5) 4-5 (0) 3-1-4-0^(2) 1-2-4--(2) 1-2-4
BN
potential
Junction Tree

aGrUM/pyAgrum use as much as possible techniques of relevance reasonning to reduce the complexity of the inference.

In [10]:
print(ie.BN().arcs())
ie.setEvidence({"X":0})
gnb.sideBySide(ie,gnb.getDot(ie.joinTree().toDotWithNames(bn)),
               captions=["","Join tree optimized for hard evidence on X"])
{(0, 1), (1, 2), (4, 5), (5, 6), (3, 1), (4, 2), (4, 1)}
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • hard evidence
    X
  • target(s)
    all
Lazy Propagation on this BN
Evidence and targets
G (0) 3-4-0 Z2 Z1 Y (0) 3-4-0^(4) 4-5 Z1 (0) 3-4-0--(0) 3-4-0^(4) 4-5 (1) 6-5 T2 Z3 (1) 6-5^(4) 4-5 Z3 (1) 6-5--(1) 6-5^(4) 4-5 (2) 2-4 T1 Z1 (2) 2-4^(4) 4-5 Z1 (2) 2-4--(2) 2-4^(4) 4-5 (4) 4-5 Z1 Z3 (2) 2-4^(4) 4-5--(4) 4-5 (1) 6-5^(4) 4-5--(4) 4-5 (0) 3-4-0^(4) 4-5--(4) 4-5
Join tree optimized for hard evidence on X
In [11]:
ie.updateEvidence({"X":[0.1,0.9]})
gnb.sideBySide(ie,gnb.getDot(ie.joinTree().toDotWithNames(bn)),
               captions=["","Join tree optimized for soft evidence on X"])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • soft evidence
    X
  • target(s)
    all
Lazy Propagation on this BN
Evidence and targets
G (0) 3-1-4-0 Z2 X Z1 Y (0) 3-1-4-0^(5) 4-5 Z1 (0) 3-1-4-0--(0) 3-1-4-0^(5) 4-5 (0) 3-1-4-0^(2) 1-2-4 X Z1 (0) 3-1-4-0--(0) 3-1-4-0^(2) 1-2-4 (1) 6-5 T2 Z3 (1) 6-5^(5) 4-5 Z3 (1) 6-5--(1) 6-5^(5) 4-5 (2) 1-2-4 X T1 Z1 (5) 4-5 Z1 Z3 (1) 6-5^(5) 4-5--(5) 4-5 (0) 3-1-4-0^(5) 4-5--(5) 4-5 (0) 3-1-4-0^(2) 1-2-4--(2) 1-2-4
Join tree optimized for soft evidence on X
In [12]:
ie.updateEvidence({"Y":0,"X":0,3:[0.1,0.9],"Z1":[0.4,0.6]})
gnb.sideBySide(ie,gnb.getDot(ie.joinTree().toDotWithNames(bn)),
               captions=["","Join tree optimized for hard evidence on X and Y, soft on Z2 and Z1"])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • hard evidence
    Y, X
  • soft evidence
    Z2, Z1
  • target(s)
    all
Lazy Propagation on this BN
Evidence and targets
G (0) 3-4 Z2 Z1 (0) 3-4^(4) 4 Z1 (0) 3-4--(0) 3-4^(4) 4 (1) 6-5 T2 Z3 (1) 6-5^(3) 4-5 Z3 (1) 6-5--(1) 6-5^(3) 4-5 (2) 2-4 T1 Z1 (2) 2-4^(4) 4 Z1 (2) 2-4--(2) 2-4^(4) 4 (3) 4-5 Z1 Z3 (3) 4-5^(4) 4 Z1 (3) 4-5--(3) 4-5^(4) 4 (4) 4 Z1 (1) 6-5^(3) 4-5--(3) 4-5 (0) 3-4^(4) 4--(4) 4 (2) 2-4^(4) 4--(4) 4 (3) 4-5^(4) 4--(4) 4
Join tree optimized for hard evidence on X and Y, soft on Z2 and Z1
In [13]:
ie.setEvidence({"X":0})
ie.setTargets({"T1","Z1"})
gnb.sideBySide(ie,gnb.getDot(ie.joinTree().toDotWithNames(bn)),
               captions=["","Join tree optimized for hard evidence on X and targets T1,Z1"])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • hard evidence
    X
  • target(s)
    T1, Z1
Lazy Propagation on this BN
Evidence and targets
G (0) 3-4-0 Z2 Z1 Y (0) 3-4-0^(2) 4-2 Z1 (0) 3-4-0--(0) 3-4-0^(2) 4-2 (2) 4-2 Z1 T1 (0) 3-4-0^(2) 4-2--(2) 4-2
Join tree optimized for hard evidence on X and targets T1,Z1
In [14]:
ie.updateEvidence({"Y":0,"X":0,3:[0.1,0.9],"Z1":[0.4,0.6]})
ie.addJointTarget({"Z2","Z1","T1"})

gnb.sideBySide(ie,
               gnb.getDot(ie.joinTree().toDotWithNames(bn)),
               captions=["","Join tree optimized for hard evidence on X and targets T1,Z1"])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • hard evidence
    Y, X
  • soft evidence
    Z2, Z1
  • target(s)
    T1, Z1
  • Joint target(s)
    [T1, Z2, Z1]
Lazy Propagation on this BN
Evidence and targets
G (0) 3-4-2 Z2 Z1 T1
Join tree optimized for hard evidence on X and targets T1,Z1
In [15]:
ie.makeInference()
ie.jointPosterior({"Z2","Z1","T1"})
Out[15]:
Z1
Z2
T1
0
1
0
0
0.00050.0150
1
0.01810.0506
1
0
0.00870.1328
1
0.32700.4473
In [16]:
ie.jointPosterior({"Z2","Z1"})
Out[16]:
Z1
Z2
0
1
0
0.01860.0656
1
0.33570.5801
In [17]:
# this will not work 
try:
    ie.jointPosterior({"Z3","Z1"})
except gum.UndefinedElement:  
    print("Indeed, there is no joint target which contains {4,5} !")
Indeed, there is no joint target which contains {4,5} !
In [18]:
ie.addJointTarget({"Z2","Z1"})
gnb.sideBySide(ie,
               gnb.getDot(ie.joinTree().toDotWithNames(bn)),
              captions=['','JoinTree'])
G Y Y X X Y->X T1 T1 X->T1 Z2 Z2 Z2->X Z1 Z1 Z1->X Z1->T1 Z3 Z3 Z1->Z3 T2 T2 Z3->T2
  • hard evidence
    Y, X
  • soft evidence
    Z2, Z1
  • target(s)
    T1, Z1
  • Joint target(s)
    [T1, Z2, Z1]
Lazy Propagation on this BN
Evidence and targets
G (0) 3-4-2 Z2 Z1 T1
JoinTree
In [ ]: