In pyAgrum>=2.0.0 , Tensors (previously 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.
import pyagrum.lib.notebook as gnb
va, vb, vc = [gum.LabelizedVariable(s, s, 2 ) for s in "abc" ]
p1 = gum.Tensor(va, vb).fillWith([ 1 , 2 , 3 , 4 ]).normalize()
p2 = gum.Tensor(vb, vc).fillWith([ 4 , 5 , 2 , 3 ]).normalize()
gnb.flow.row(p1, p2, p1 + p2, captions = [ "p1" , "p2" , "p1+p2" ])
a
b
0
1
0 0.1000 0.2000
1 0.3000 0.4000
p1
b
c
0
1
0 0.2857 0.3571
1 0.1429 0.2143
p2
b
a c
0
1
0 0 0.3857 0.6571
1 0.2429 0.5143
1 0 0.4857 0.7571
1 0.3429 0.6143
p1+p2
c
b a
0
1
0 0 0.3699 0.3208
1 0.3908 0.3582
1 0 0.6301 0.6792
1 0.6092 0.6418
gnb.flow.row(p3, p4, captions = [ "p3" , "p4" ])
b
a c
0
1
0 0 0.3857 0.6571
1 0.2429 0.5143
1 0 0.4857 0.7571
1 0.3429 0.6143
p3
b
a c
0
1
0 0 1.3857 1.6571
1 1.2429 1.5143
1 0 1.4857 1.7571
1 1.3429 1.6143
p4
bn = gum.fastBN( "a->c;b->c" , 3 )
G
c
c
b
b
b->c
a
a
a->c
In such a small bayes net, we can directly manipulate P ( a , b , c ) P(a,b,c) P ( a , b , c ) . For instance : P ( b ∣ c ) = ∑ a P ( a , b , c ) ∑ a , b P ( a , b , c ) P(b|c)=\frac{\sum_{a} P(a,b,c)}{\sum_{a,b} P(a,b,c)} P ( b ∣ c ) = ∑ a , b P ( a , b , c ) ∑ a P ( a , b , c )
pABC = bn.cpt( "a" ) * bn.cpt( "b" ) * bn.cpt( "c" )
pBgivenC = pABC.sumOut([ "a" ]) / pABC.sumOut([ "a" , "b" ])
pBgivenC.putFirst( "b" ) # in order to have b horizontally in the table
b
c
0
1
2
0 0.4667 0.5024 0.0308
1 0.4885 0.4644 0.0471
2 0.6521 0.2761 0.0719
Let’s compute the joint probability P ( A , B ) P(A,B) P ( A , B ) from P ( A , B , C ) P(A,B,C) P ( A , B , C )
print ( "pAC really is a probability : it sums to {} " .format(pAC.sum()))
pAC really is a probability : it sums to 0.9999999999999999
a
c
0
1
2
0 0.2608 0.1782 0.0036
1 0.2211 0.0715 0.0051
2 0.1147 0.1409 0.0041
a
0
1
2
0.5967 0.3906 0.0128
It is easy to compute p ( A , C = 1 ) p(A, C=1) p ( A , C = 1 )
a
0
1
2
0.2211 0.0715 0.0051
Moreover, we know that P ( C = 1 ) = ∑ A P ( A , C = 1 ) P(C=1)=\sum_A P(A,C=1) P ( C = 1 ) = ∑ A P ( A , C = 1 )
pAC.extract({ "c" : 1 }).sum()
Now we can compute p ( A ∣ C = 1 ) = P ( A , C = 1 ) p ( C = 1 ) p(A|C=1)=\frac{P(A,C=1)}{p(C=1)} p ( A ∣ C = 1 ) = p ( C = 1 ) P ( A , C = 1 )
pAC.extract({ "c" : 1 }).normalize()
a
0
1
2
0.7427 0.2403 0.0170
P ( A ∣ C ) P(A|C) P ( A ∣ C ) is represented by a matrix that verifies p ( A ∣ C ) = P ( A , C ) P ( C p(A|C)=\frac{P(A,C)}{P(C} p ( A ∣ C ) = P ( C P ( A , C )
pAgivenC = (pAC / pAC.sumIn( "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.5893 0.4025 0.0082
1 0.7427 0.2403 0.0170
2 0.4418 0.5426 0.0157
$P(A|C)$
a
0
1
2
0.7427 0.2403 0.0170
$P(A|C=1)$
A likelihood can also be found in this matrix.
pAgivenC.extract({ "a" : 2 })
c
0
1
2
0.0082 0.0170 0.0157
A likelihood does not have to sum to 1. It is not relevant to normalize it.
a
0
1
2
1.7738 1.1853 0.0409
import matplotlib.pyplot as plt
x = np.linspace( 0 , 1 , 100 )
plt.plot(x, [p1.fillWith([p, 1 - p]).entropy() for p in x])
t = gum.LabelizedVariable( "t" , "t" , 3 )
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.0e-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):
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)