Using pyAgrum

Creative Commons License

aGrUM

interactive online version

In [1]:
%matplotlib inline
from pylab import *
import matplotlib.pyplot as plt

import os

Initialisation

  • importing pyAgrum

  • importing pyAgrum.lib tools

  • loading a BN

In [2]:
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb
gnb.configuration()
LibraryVersion
OSposix [darwin]
Python3.11.1 (main, Dec 23 2022, 09:28:24) [Clang 14.0.0 (clang-1400.0.29.202)]
IPython8.6.0
Matplotlib3.6.1
Numpy1.23.4
pyDot1.4.2
pyAgrum1.5.2.9
Mon Feb 13 23:21:19 2023 CET
In [3]:
bn=gum.loadBN("res/alarm.dsl")
gnb.showBN(bn,size='9')
../_images/notebooks_02-Tutorial_Tutorial2_5_0.svg

Visualisation and inspection

In [4]:
print(bn.variableFromName('SHUNT'))
SHUNT:Labelized({NORMAL|HIGH})
In [5]:
print(bn.cpt(bn.idFromName('SHUNT')))

             ||  SHUNT            |
PULMEM|INTUBA||NORMAL   |HIGH     |
------|------||---------|---------|
TRUE  |NORMAL|| 0.1000  | 0.9000  |
FALSE |NORMAL|| 0.9500  | 0.0500  |
TRUE  |ESOPHA|| 0.1000  | 0.9000  |
FALSE |ESOPHA|| 0.9500  | 0.0500  |
TRUE  |ONESID|| 0.0100  | 0.9900  |
FALSE |ONESID|| 0.0500  | 0.9500  |

In [6]:
gnb.showPotential(bn.cpt(bn.idFromName('SHUNT')),digits=3)
SHUNT
INTUBATION
PULMEMBOLUS
NORMAL
HIGH
NORMAL
TRUE
0.1000.900
FALSE
0.9500.050
ESOPHAGEAL
TRUE
0.1000.900
FALSE
0.9500.050
ONESIDED
TRUE
0.0100.990
FALSE
0.0500.950

Results of inference

It is easy to look at result of inference

In [7]:
gnb.showPosterior(bn,{'SHUNT':'HIGH'},'PRESS')
../_images/notebooks_02-Tutorial_Tutorial2_11_0.svg
In [8]:
gnb.showPosterior(bn,{'MINVOLSET':'NORMAL'},'VENTALV')
../_images/notebooks_02-Tutorial_Tutorial2_12_0.svg

Overall results

In [9]:
gnb.showInference(bn,size="10")
../_images/notebooks_02-Tutorial_Tutorial2_14_0.svg

What is the impact of observed variables (SHUNT and VENTALV for instance) on another on (PRESS) ?

In [10]:
ie=gum.LazyPropagation(bn)
ie.evidenceImpact('PRESS',['SHUNT','VENTALV'])
Out[10]:
PRESS
SHUNT
VENTALV
ZERO
LOW
NORMAL
HIGH
NORMAL
ZERO
0.05690.26690.20050.4757
LOW
0.02080.25150.05530.6724
NORMAL
0.07690.32670.17720.4192
HIGH
0.05010.16330.27960.5071
HIGH
ZERO
0.05890.27260.19970.4688
LOW
0.03180.22370.05210.6924
NORMAL
0.17350.58390.14020.1024
HIGH
0.07110.23470.25330.4410

Using inference as a function

It is also easy to use inference as a routine in more complex procedures.

In [11]:
import time
r=range(0,100,2)
xs=[x/100.0 for x in r]

tf=time.time()
ys=[gum.getPosterior(bn,evs={'MINVOLSET':[0,x/100.0,0.5]},target='VENTALV').tolist()
        for x in r]
delta=time.time()-tf

p=plot(xs,ys)
legend(p,[bn.variableFromName('VENTALV').label(i)
          for i in range(bn.variableFromName('VENTALV').domainSize())],loc=7);
title('VENTALV (100 inferences in %d ms)'%delta);
ylabel('posterior Probability');
xlabel('Evidence on MINVOLSET : [0,x,0.5]')
plt.show()
../_images/notebooks_02-Tutorial_Tutorial2_18_0.svg

Another example : python gives access to a large set of tools. Here the value for the equality of two probabilities of a posterior is easely computed.

In [12]:
x=[p/100.0 for p in range(0,100)]

tf=time.time()
y=[gum.getPosterior(bn,evs={'HRBP':[1.0-p/100.0,1.0-p/100.0,p/100.0]},target='TPR').tolist()
   for p in range(0,100)]
delta=time.time()-tf

p=plot(x,y)
title('HRBP (100 inferences in %d ms)'%delta);
v=bn.variableFromName('TPR');
legend([v.label(i) for i in range(v.domainSize())],loc='best');
np1=(transpose(y)[0]>transpose(y)[2]).argmin()
text(x[np1]-0.05,y[np1][0]+0.005,str(x[np1]),bbox=dict(facecolor='red', alpha=0.1))
plt.show()
../_images/notebooks_02-Tutorial_Tutorial2_20_0.svg

BN as a classifier

Generation of databases

Using the CSV format for the database:

In [13]:
gum.generateSample(bn,1000,"out/test.csv",with_labels=True)
Out[13]:
-15310.297116565764
In [14]:
with open("out/test.csv","r") as src:
    for _ in range(10):
        print(src.readline(),end="")
INSUFFANESTH,PULMEMBOLUS,MINVOL,HRSAT,ERRLOWOUTPUT,BP,HREKG,DISCONNECT,LVFAILURE,CVP,INTUBATION,SHUNT,TPR,VENTALV,KINKEDTUBE,MINVOLSET,LVEDVOLUME,PAP,CATECHOL,ARTCO2,HR,EXPCO2,VENTLUNG,STROKEVOLUME,FIO2,VENTTUBE,HRBP,CO,VENTMACH,HYPOVOLEMIA,HISTORY,ANAPHYLAXIS,PRESS,PCWP,PVSAT,ERRCAUTER,SAO2
FALSE,FALSE,ZERO,HIGH,FALSE,HIGH,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,ZERO,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,HIGH,LOW,ZERO,NORMAL,NORMAL,LOW,HIGH,HIGH,NORMAL,FALSE,FALSE,FALSE,NORMAL,NORMAL,LOW,FALSE,LOW
TRUE,FALSE,ZERO,LOW,FALSE,HIGH,NORMAL,FALSE,FALSE,NORMAL,NORMAL,NORMAL,HIGH,ZERO,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,NORMAL,LOW,ZERO,NORMAL,NORMAL,LOW,LOW,NORMAL,NORMAL,FALSE,FALSE,FALSE,NORMAL,NORMAL,LOW,FALSE,LOW
FALSE,FALSE,ZERO,HIGH,FALSE,LOW,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,ZERO,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,HIGH,LOW,ZERO,NORMAL,NORMAL,LOW,HIGH,HIGH,NORMAL,FALSE,FALSE,FALSE,HIGH,NORMAL,LOW,FALSE,LOW
FALSE,FALSE,ZERO,HIGH,TRUE,NORMAL,HIGH,FALSE,FALSE,HIGH,NORMAL,NORMAL,LOW,ZERO,FALSE,NORMAL,HIGH,NORMAL,HIGH,HIGH,HIGH,LOW,ZERO,NORMAL,NORMAL,LOW,NORMAL,HIGH,NORMAL,TRUE,FALSE,FALSE,HIGH,HIGH,LOW,FALSE,LOW
TRUE,FALSE,ZERO,HIGH,TRUE,HIGH,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,ZERO,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,HIGH,LOW,ZERO,NORMAL,NORMAL,LOW,NORMAL,HIGH,NORMAL,FALSE,FALSE,FALSE,HIGH,NORMAL,LOW,FALSE,LOW
FALSE,FALSE,ZERO,HIGH,FALSE,HIGH,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,LOW,LOW,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,HIGH,HIGH,HIGH,NORMAL,NORMAL,LOW,HIGH,HIGH,NORMAL,FALSE,FALSE,FALSE,HIGH,NORMAL,NORMAL,FALSE,LOW
TRUE,FALSE,LOW,LOW,FALSE,HIGH,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,HIGH,HIGH,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,HIGH,NORMAL,ZERO,NORMAL,NORMAL,NORMAL,NORMAL,LOW,NORMAL,NORMAL,FALSE,FALSE,FALSE,HIGH,NORMAL,HIGH,FALSE,NORMAL
FALSE,FALSE,ZERO,HIGH,FALSE,NORMAL,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,ZERO,FALSE,NORMAL,NORMAL,NORMAL,HIGH,NORMAL,HIGH,LOW,ZERO,NORMAL,NORMAL,LOW,HIGH,HIGH,NORMAL,FALSE,FALSE,FALSE,HIGH,NORMAL,LOW,FALSE,LOW
FALSE,FALSE,ZERO,HIGH,FALSE,HIGH,HIGH,FALSE,FALSE,NORMAL,NORMAL,NORMAL,NORMAL,ZERO,FALSE,LOW,NORMAL,NORMAL,HIGH,HIGH,HIGH,LOW,ZERO,NORMAL,NORMAL,ZERO,HIGH,HIGH,LOW,FALSE,FALSE,FALSE,LOW,NORMAL,LOW,FALSE,LOW

probabilistic classifier using BN

(because of the use of from-bn-generated csv files, quite good ROC curves are expected)

In [15]:
from pyAgrum.lib.bn2roc import showROC_PR

showROC_PR(bn,"out/test.csv",
        target='CATECHOL',label='HIGH',  # class and label
        show_progress=True,show_fig=True,with_labels=True)
out/test.csv: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|
../_images/notebooks_02-Tutorial_Tutorial2_26_1.svg
Out[15]:
(0.9735044240858195, 0.9300899828, 0.9984643933686319, 0.4221808066)

Using another class variable

In [16]:
showROC_PR(bn,"out/test.csv",'SAO2','HIGH',show_progress=True)
out/test.csv: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|
../_images/notebooks_02-Tutorial_Tutorial2_28_1.svg
Out[16]:
(0.9461236338797815, 0.048531175, 0.6373213039718758, 0.2331074743)

Fast prototyping for BNs

In [17]:
bn1=gum.fastBN("a->b;a->c;b->c;c->d",3)

gnb.sideBySide(*[gnb.getInference(bn1,evs={'c':val},targets={'a','c','d'}) for val in range(3)],
              captions=[f"Inference given that $c={val}$" for val in range(3)])
structs Inference in   1.03ms a 2023-02-13T23:21:22.892580 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b b a->b c 2023-02-13T23:21:22.956513 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ a->c b->c d 2023-02-13T23:21:22.978894 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ c->d
Inference given that $c=0$
structs Inference in   0.52ms a 2023-02-13T23:21:23.165231 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b b a->b c 2023-02-13T23:21:23.207002 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ a->c b->c d 2023-02-13T23:21:23.256205 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ c->d
Inference given that $c=1$
structs Inference in   0.52ms a 2023-02-13T23:21:23.472348 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b b a->b c 2023-02-13T23:21:23.505996 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ a->c b->c d 2023-02-13T23:21:23.532040 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ c->d
Inference given that $c=2$
In [18]:
print(gum.getPosterior(bn1,evs={'c':0},target='c'))
print(gum.getPosterior(bn1,evs={'c':0},target='d'))

# using pyagrum.lib.notebook's helpers
gnb.flow.row(gum.getPosterior(bn1,evs={'c':0},target='c'),gum.getPosterior(bn1,evs={'c':0},target='d'))

  c                          |
0        |1        |2        |
---------|---------|---------|
 1.0000  | 0.0000  | 0.0000  |


  d                          |
0        |1        |2        |
---------|---------|---------|
 0.6638  | 0.1259  | 0.2103  |

c
0
1
2
1.00000.00000.0000
d
0
1
2
0.66380.12590.2103

Joint posterior, impact of multiple evidence

In [19]:
bn=gum.fastBN("a->b->c->d;b->e->d->f;g->c")
gnb.sideBySide(bn,gnb.getInference(bn))
G d d f f d->f g g c c g->c b b e e b->e b->c e->d a a a->b c->d
structs Inference in   2.10ms a 2023-02-13T23:21:23.751140 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b 2023-02-13T23:21:23.803575 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ a->b c 2023-02-13T23:21:23.837175 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b->c e 2023-02-13T23:21:23.904304 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ b->e d 2023-02-13T23:21:23.868946 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ c->d f 2023-02-13T23:21:24.016800 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ d->f e->d g 2023-02-13T23:21:24.038836 image/svg+xml Matplotlib v3.6.1, https://matplotlib.org/ g->c
In [20]:
ie=gum.LazyPropagation(bn)
ie.addJointTarget({"e","f","g"})
ie.makeInference()
gnb.sideBySide(ie.jointPosterior({"e","f","g"}),ie.jointPosterior({"e","g"}),
               captions=["Joint posterior $P(e,f,g)$","Joint posterior $P(e,f)$"])
g
f
e
0
1
0
0
0.11390.1285
1
0.03740.0484
1
0
0.23670.3159
1
0.05290.0662

Joint posterior $P(e,f,g)$
g
e
0
1
0
0.35060.4445
1
0.09040.1146

Joint posterior $P(e,f)$
In [21]:
gnb.sideBySide(ie.evidenceImpact("a",["e","f"]),ie.evidenceImpact("a",["d","e","f"]),
              captions=["$\\forall e,f, P(a|e,f)$",
                        "$\\forall d,e,f, P(a|d,e,f)=P(a|d,e)$ using d-separation"]
                        )
a
f
e
0
1
0
0
0.49350.5065
1
0.65240.3476
1
0
0.50570.4943
1
0.65200.3480

$\forall e,f, P(a|e,f)$
a
e
d
0
1
0
0
0.51760.4824
1
0.47890.5211
1
0
0.65010.3499
1
0.65260.3474

$\forall d,e,f, P(a|d,e,f)=P(a|d,e)$ using d-separation
In [22]:
gnb.sideBySide(ie.evidenceJointImpact(["a","b"],["e","f"]),ie.evidenceJointImpact(["a","b"],["d","e","f"]),
              captions=["$\\forall e,f, P(a,b|e,f)$",
                        "$\\forall d,e,f, P(a,b|d,e,f)=P(a,b|d,e)$ using d-separation"]
                        )
b
f
e
a
0
1
0
0
0
0.49090.0027
1
0.22670.2797
1
0
0.65200.0004
1
0.30110.0464
1
0
0
0.50320.0025
1
0.23240.2618
1
0
0.65150.0004
1
0.30090.0471

$\forall e,f, P(a,b|e,f)$
b
e
d
a
0
1
0
0
0
0.51530.0023
1
0.23800.2443
1
0
0.47600.0029
1
0.21990.3012
1
0
0
0.64960.0005
1
0.30010.0499
1
0
0.65220.0004
1
0.30120.0461

$\forall d,e,f, P(a,b|d,e,f)=P(a,b|d,e)$ using d-separation
In [ ]: