Inference in Bayesian network, building a junction tree

137 views Asked by At

Assuming you know a junction tree of a Bayesian network (to build manually for simple examples) write a programme in python for the propagation of beliefs in order to calculate the conditional probabilities P(Q|e) for arbitrary Q ∈ U and e ⊂ U. I should use junction tree algorithm.

This is the code I was able to write. Can someone help me? I know the theory behind this problem but I don't know how to implement it.

network = {
    'flu': {'prob': 0.05},
    'cough': {'prob': 0.1, 'parents': ['flu']},
    'fever': {'prob': 0.3, 'parents': ['flu']},
    'fatigue': {'prob': 0.2, 'parents': ['flu']}
}

moralized_graph = {}
for node in network:
    moralized_graph[node] = set(network[node].get('parents', []))
for node1 in network:
    for node2 in moralized_graph[node1]:
        moralized_graph[node2].add(node1)


flu_prob = {"flu": {0: 0.95, 1: 0.05}}
cough_prob = {"cough": {0: 0.9, 1: 0.1}, "flu": {0: {0: 0.6, 1: 0.4}, 1: {0: 0.8, 1: 0.2}}}
fever_prob = {"fever": {0: 0.7, 1: 0.3}, "flu": {0: {0: 0.8, 1: 0.2}, 1: {0: 0.5, 1: 0.5}}}
fatigue_prob = {"fatigue": {0: 0.8, 1: 0.2}, "flu": {0: {0: 0.7, 1: 0.3}, 1: {0: 0.6, 1: 0.4}}}

potential_1 = {(0, 0): flu_prob["flu"][0] * cough_prob["flu"][0][0],
               (0, 1): flu_prob["flu"][0] * cough_prob["flu"][0][1],
               (1, 0): flu_prob["flu"][1] * cough_prob["flu"][1][0],
               (1, 1): flu_prob["flu"][1] * cough_prob["flu"][1][1]}
potential_2 = {(0, 0): flu_prob["flu"][0] * fever_prob["flu"][0][0],
               (0, 1): flu_prob["flu"][0] * fever_prob["flu"][0][1],
               (1, 0): flu_prob["flu"][1] * fever_prob["flu"][1][0],
               (1, 1): flu_prob["flu"][1] * fever_prob["flu"][1][1]}
potential_3 = {(0, 0): flu_prob["flu"][0] * fatigue_prob["flu"][0][0],
               (0, 1): flu_prob["flu"][0] * fatigue_prob["flu"][0][1],
               (1, 0): flu_prob["flu"][1] * fatigue_prob["flu"][1][0],
               (1, 1): flu_prob["flu"][1] * fatigue_prob["flu"][1][1]}

class JunctionTree:
    def __init__(self, clusters, edges):
        self.clusters = clusters
        self.edges = edges
        
junction_tree_clusters = [
    (["flue", "fatigue"], potential_1),
    (["flue", "fever"], potential_2),
    (["flue", "cough"], potential_3),
]

junction_tree_edges = [
    (["flue", "fatigue"], ["flue", "fever"]),
    (["flue", "fever"], ["cough", "flue"]),
]

junction_tree = JunctionTree(junction_tree_clusters, junction_tree_edges)

graph = {"flu": ["cough",fever", "fatigue"], "cough": [], "fever": [], "fatigue": []}
1

There are 1 answers

0
Pierre-Henri Wuillemin On

using pyAgrum and for this BN and this inference :

enter image description here

Here is the code of this inference. This can be easily generalized (and optimized).

# evidence: fever is 1
evidence=gum.Potential().add(bn.variable("fever")).fillWith([0,1])

# potentials for cliques
psi03=bn.cpt("flu")*bn.cpt("fatigue")
psi01=bn.cpt("cough")
psi02=bn.cpt("fever")*evidence

#collect (for instance) : 03->02->01
mu03_02=psi03.margSumIn("flu") # marginalize out everything else thant "flu"
mu02_01=(mu03_02*psi02).margSumIn("flu")

# distribute (for instance) : 01->02->03
mu01_02=psi01.margSumIn("flu")
mu02_03=(mu01_02*psi02).margSumIn("flu")

# Finally
joint03=(psi03*mu02_03).normalize()
joint02=(psi02*mu03_02*mu01_02).normalize()
joint01=(psi01*mu02_01).normalize()

enter image description here