Logo
pyAgrum 1.8.1 on Jupyter

Tutorials

  • ▶ Tutorial
    • ▷ Tutorial
    • ▷ Tutorial2
  • ▶ Examples
    • ▷ Asthma
    • ▷ Kaggle Titanic
    • ▷ Naive Credit Default Modeling
    • ▷ Causality And Learning
    • ▷ Sensitivity Analysis Using Credal Networks
    • ▷ Quasi Continuous
    • ▷ Parameters Learning With Pandas
    • ▷ Bayesian Beta Coin
  • ▶ Models
    • ▷ Influence Diagram
    • ▷ Dynamic Bn
    • ▷ Markov Random Field
    • ▷ Credal Networks
    • ▷ O3PRM
  • ▶ Learning
    • ▷ Structural Learning
    • ▷ Learning Classifier
    • ▷ Learning And Essential Graphs
    • ▷ Dirichlet Prior And Weigthed Database
    • ▷ Parametric Em
    • ▷ Chi2 And Scores From Bn Learner
  • ▶ Inference
    • ▷ Graphical Inference
    • ▷ Relevance Reasoning
    • ▷ Lazy Propagation Advanced Features
    • ▷ Approximate Inference
    • ▷ Sampling Inference
  • ▶ Classifier
    • ▷ Learning
    • ▷ Discretizer
    • ▷ Compare Classifiers With Sklearn
    • ▷ Cross Validation
    • ▷ Binary And Nary Classifier From Bn
  • ▶ Causality
    • ▷ Tobacco
    • ▷ Simpson Paradox
    • ▷ Multinomial Simpson Paradox
    • ▷ Do Calculus Examples
    • ▷ Counterfactual
  • ▶ Applications
    • ▷ Ipywidgets
  • ▶ Tools
    • ▷ Potentials
    • ▷ Aggregators
    • ▷ Explain
    • ▷ Kl For BNs
    • ▷ Comparing Bn
    • ▷ Colouring And Exporting BNs
    • ▷ Config For PyAgrum
pyAgrum

Potentials : named tensors¶

In pyAgrum, Potentials represent multi-dimensionnal arrays with (discrete) random variables attached to each dimension. This mathematical object have tensorial operators w.r.t. to the variables attached.

Creative Commons License aGrUM interactive online version
In [1]:
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb

a,b,c=[gum.LabelizedVariable(s,s,2) for s in "abc"]

potential algebra¶

In [2]:
p1=gum.Potential().add(a).add(b).fillWith([1,2,3,4]).normalize()
p2=gum.Potential().add(b).add(c).fillWith([4,5,2,3]).normalize()
In [3]:
gnb.flow.row(p1,p2,p1+p2,
              captions=['p1','p2','p1+p2'])
a
b
0
1
0
0.10000.2000
1
0.30000.4000

p1
b
c
0
1
0
0.28570.3571
1
0.14290.2143

p2
b
a
c
0
1
0
0
0.38570.6571
1
0.24290.5143
1
0
0.48570.7571
1
0.34290.6143

p1+p2
In [4]:
p3=p1+p2 
gnb.showPotential(p3/p3.margSumOut(["b"]))
c
b
a
0
1
0
0
0.36990.3208
1
0.39080.3582
1
0
0.63010.6792
1
0.60920.6418
In [5]:
p4=gum.Potential()+p3
gnb.flow.row(p3,p4,
              captions=['p3','p4'])
b
a
c
0
1
0
0
0.38570.6571
1
0.24290.5143
1
0
0.48570.7571
1
0.34290.6143

p3
b
a
c
0
1
0
0
1.38571.6571
1
1.24291.5143
1
0
1.48571.7571
1
1.34291.6143

p4

Bayes' theorem¶

In [6]:
bn=gum.fastBN("a->c;b->c",3)
bn
Out[6]:
pyAgrum▶Tools▷PotentialsG pyAgrum▶Tools▷Potentialsc c pyAgrum▶Tools▷Potentialsa a pyAgrum▶Tools▷Potentialsa->c pyAgrum▶Tools▷Potentialsb b pyAgrum▶Tools▷Potentialsb->c

In such a small bayes net, we can directly manipulate $P(a,b,c)$. For instance : $$P(b|c)=\frac{\sum_{a} P(a,b,c)}{\sum_{a,b} P(a,b,c)}$$

In [7]:
pABC=bn.cpt("a")*bn.cpt("b")*bn.cpt("c")
pBgivenC=(pABC.margSumOut(["a"])/pABC.margSumOut(["a","b"]))

pBgivenC.putFirst("b") # in order to have b horizontally in the table
Out[7]:
b
c
0
1
2
0
0.62330.18850.1881
1
0.70190.17330.1248
2
0.50820.36180.1301

Joint, marginal probability, likelihood¶

Let's compute the joint probability $P(A,B)$ from $P(A,B,C)$

In [8]:
pAC=pABC.margSumOut(["b"])
print("pAC really is a probability : it sums to {}".format(pAC.sum()))
pAC
pAC really is a probability : it sums to 1.0
Out[8]:
a
c
0
1
2
0
0.22140.06970.0729
1
0.23490.15080.0829
2
0.04170.05580.0699

Computing $p(A)$¶

In [9]:
pAC.margSumOut(["c"])
Out[9]:
a
0
1
2
0.49790.27630.2257

Computing $p(A |C=1)$¶

It is easy to compute $p(A, C=1)$

In [10]:
pAC.extract({"c":1})
Out[10]:
a
0
1
2
0.23490.15080.0829

Moreover, we know that $P(C=1)=\sum_A P(A,C=1)$

In [11]:
pAC.extract({"c":1}).sum()
Out[11]:
0.46857414425142496

Now we can compute $p(A|C=1)=\frac{P(A,C=1)}{p(C=1)}$

In [12]:
pAC.extract({"c":1}).normalize()
Out[12]:
a
0
1
2
0.50120.32180.1770

Computing $P(A|C)$¶

$P(A|C)$ is represented by a matrix that verifies $p(A|C)=\frac{P(A,C)}{P(C}$

In [13]:
pAgivenC=(pAC/pAC.margSumIn("c")).putFirst("a") 
# putFirst("a") : to correctly show a cpt, the first variable have to bethe conditionned one
gnb.flow.row(pAgivenC,pAgivenC.extract({'c':1}),
               captions=["$P(A|C)$","$P(A|C=1)$"])
a
c
0
1
2
0
0.60810.19150.2003
1
0.50120.32180.1770
2
0.24920.33350.4172

$P(A|C)$
a
0
1
2
0.50120.32180.1770

$P(A|C=1)$

Likelihood $P(A=2|C)$¶

A likelihood can also be found in this matrix.

In [14]:
pAgivenC.extract({'a':2})
Out[14]:
c
0
1
2
0.20030.17700.4172

A likelihood does not have to sum to 1. It is not relevant to normalize it.

In [15]:
pAgivenC.margSumIn(["a"])
Out[15]:
a
0
1
2
1.35860.84680.7946

entropy of potential¶

In [16]:
%matplotlib inline
from pylab import *
import matplotlib.pyplot as plt
import numpy as np
In [17]:
p1=gum.Potential().add(a)
x = np.linspace(0, 1, 100)
plt.plot(x,[p1.fillWith([p,1-p]).entropy() for p in x])
plt.show()
<rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <cc:Work> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> <dc:date>2023-05-24T15:17:22.109209</dc:date> <dc:format>image/svg+xml</dc:format> <dc:creator> <cc:Agent> <dc:title>Matplotlib v3.7.1, https://matplotlib.org/</dc:title> </cc:Agent> </dc:creator> </cc:Work> </rdf:RDF> <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
In [18]:
t=gum.LabelizedVariable('t','t',3)
p1=gum.Potential().add(t)

def entrop(bc):
    """
    bc is a list [a,b,c] close to a distribution 
    (normalized just to be sure)
    """
    return p1.fillWith(bc).normalize().entropy()

import matplotlib.tri as tri

corners = np.array([[0, 0], [1, 0], [0.5, 0.75**0.5]])
triangle = tri.Triangulation(corners[:, 0], corners[:, 1])

# Mid-points of triangle sides opposite of each corner
midpoints = [(corners[(i + 1) % 3] + corners[(i + 2) % 3]) / 2.0 \
             for i in range(3)]
def xy2bc(xy, tol=1.e-3):
    """
    From 2D Cartesian coordinates to barycentric.
    """
    s = [(corners[i] - midpoints[i]).dot(xy - midpoints[i]) / 0.75 \
         for i in range(3)]
    return np.clip(s, tol, 1.0 - tol)
    
def draw_entropy(nlevels=200, subdiv=6, **kwargs):
    import math

    refiner = tri.UniformTriRefiner(triangle)
    trimesh = refiner.refine_triangulation(subdiv=subdiv)
    pvals = [entrop(xy2bc(xy)) for xy in zip(trimesh.x, trimesh.y)]

    plt.tricontourf(trimesh, pvals, nlevels, **kwargs)
    plt.axis('equal')
    plt.xlim(0, 1)
    plt.ylim(0, 0.75**0.5)
    plt.axis('off')
    
draw_entropy()
plt.show()
<rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <cc:Work> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> <dc:date>2023-05-24T15:17:22.401809</dc:date> <dc:format>image/svg+xml</dc:format> <dc:creator> <cc:Agent> <dc:title>Matplotlib v3.7.1, https://matplotlib.org/</dc:title> </cc:Agent> </dc:creator> </cc:Work> </rdf:RDF> <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>