Sensitivity analysis for Bayesian networks using credal networks

Creative Commons License

aGrUM

interactive online version

There are several sensitivity analysis frameworks for Bayesian networks. A fairly efficient method is certainly to use credal networks to do this analysis.

Creating a Bayesian network

In [1]:
import pyagrum as gum
import pyagrum.lib.notebook as gnb
In [2]:
bn = gum.fastBN("A->B->C<-D->E->F<-B")
gnb.flow.row(bn, gnb.getInference(bn))
G A A B B A->B C C B->C F F B->F D D D->C E E D->E E->F
structs Inference in   4.18ms A 2025-10-29T13:56:20.143392 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:20.166670 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:20.187827 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:20.250615 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:20.208679 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:20.229839 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F

Building a credal network from a BN

It is easy to build a credal network from a Bayesian network by indicating the ‘noise’ on each parameter.

In [3]:
cr = gum.CredalNet(bn, bn)
gnb.show(cr)
../_images/notebooks_14-Examples_SensitivityAnalysisUsingCredalNetworks_6_0.svg
In [4]:
cr.bnToCredal(1e-10, False, False)
In [5]:
cr.computeBinaryCPTMinMax()
In [6]:
print(cr)

A:Range([0,1])
<> : [[0.960602 , 0.0393976]]

B:Range([0,1])
<A:0> : [[0.656802 , 0.343198] , [0.656793 , 0.343207]]
<A:1> : [[0.929183 , 0.0708164]]

C:Range([0,1])
<B:0|D:0> : [[0.796228 , 0.203772] , [0.796227 , 0.203773]]
<B:1|D:0> : [[0.296307 , 0.703693] , [0.293682 , 0.706318]]
<B:0|D:1> : [[0.866449 , 0.13355]]
<B:1|D:1> : [[0.365068 , 0.634932] , [0.364288 , 0.635712]]

D:Range([0,1])
<> : [[0.296323 , 0.703677] , [0.293699 , 0.706301]]

E:Range([0,1])
<D:0> : [[0.216518 , 0.783482] , [0.203086 , 0.796914]]
<D:1> : [[0.314793 , 0.685207] , [0.312918 , 0.687082]]

F:Range([0,1])
<E:0|B:0> : [[0.439406 , 0.560594] , [0.439178 , 0.560822]]
<E:1|B:0> : [[0.56696 , 0.43304] , [0.566927 , 0.433073]]
<E:0|B:1> : [[0.608625 , 0.391375] , [0.00899224 , 0.991008]]
<E:1|B:1> : [[0.887344 , 0.112656]]


Testing difference hypothesis about the global precision on the parameters

We can therefore easily conduct a sensitivity analysis based on an assumption of error on all the parameters of the network.

In [7]:
def showNoisy(bn, beta):
  cr = gum.CredalNet(bn, bn)
  cr.bnToCredal(beta, False, False)
  cr.computeBinaryCPTMinMax()
  ielbp = gum.CNLoopyPropagation(cr)
  return gnb.getInference(cr, engine=ielbp)
In [8]:
for eps in [1, 1e-1, 1e-2, 1e-3, 1e-10]:
  gnb.flow.add(showNoisy(bn, eps), caption=f"noise={eps}")
gnb.flow.display()
structs Inference in   0.25ms A 2025-10-29T13:56:20.721173 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:20.739096 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:20.755052 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:20.806301 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:20.772915 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:20.789394 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F
noise=1
structs Inference in   0.20ms A 2025-10-29T13:56:20.968590 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:20.985941 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:21.003535 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:21.055744 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:21.021950 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:21.038874 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F
noise=0.1
structs Inference in   0.21ms A 2025-10-29T13:56:21.208759 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:21.228016 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:21.250186 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:21.319110 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:21.282763 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:21.300344 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F
noise=0.01
structs Inference in   0.22ms A 2025-10-29T13:56:21.464850 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:21.484387 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:21.502064 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:21.554980 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:21.520215 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:21.537647 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F
noise=0.001
structs Inference in   0.22ms A 2025-10-29T13:56:21.715121 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B 2025-10-29T13:56:21.734589 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ A->B C 2025-10-29T13:56:21.757001 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->C F 2025-10-29T13:56:21.830374 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ B->F D 2025-10-29T13:56:21.793646 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->C E 2025-10-29T13:56:21.812598 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ D->E E->F
noise=1e-10
In [ ]: