Hoppa till innehåll

Dynamiskt bayesianskt nätverk i Python

Jag implementerar ett dynamiskt bayesianskt nätverk (DBN) för ett paraplyproblem med pgmpy och pyAgrum i denna handledning. Ett DBN är ett bayesianskt nätverk med noder som kan representera olika tidsperioder. Ett DBN kan användas för att göra förutsägelser om framtiden baserat på observationer (bevis) från det förflutna.

Ett DBN är ett bayesianskt nätverk som representerar en temporär sannolikhetsmodell, varje tidsskiva kan ha ett valfritt antal tillståndsvariabler och bevisvariabler. Varje dold markovmodell (HMM) kan representeras som ett DBN och varje DBN kan översättas till en HMM. Ett DBN är mindre i jämförelse med en HMM och det går snabbare att göra förutsägelser från ett DBN jämfört med en HMM.

Ett dynamiskt bayesianskt nätverk består av noder, kanter och villkorliga sannolikhetsfördelningar för kanter. Varje kant i ett DBN representerar en tidsperiod och nätverket kan inkludera flera tidsperioder till skillnad från markovmodeller som endast tillåter markovprocesser. DBN:s är vanliga inom applikationer för robotik och datautvinning. Dynamiska bayesianska nätverk kallas också 2-tidsskive bayesianska nätverk (2TBN).

Problem och bibliotek

Jag använder ett enkelt problem som modelleras med två olika bibliotek. Problemdefinitionen är: En säkerhetsvakt är stationerad i en underjordisk bunker och försöker gissa om det regnar utifrån att observera om direktören kommer till jobbet med ett paraply eller inte. Jag använder följande bibliotek i denna handledning: cairosvg, pyAgrum, matplotlib, pgmpy och numpy. Jag hade vissa problem när jag installerade pgmpy eftersom biblioteket kräver torch, installationen av torch misslyckades. Jag installerade torch till Python 3.7 med: pip install https://download.pytorch.org/whl/cpu/torch-1.1.0-cp37-cp37m-win_amd64.whl.

PGMPY-implementering

Följande kod använder DBN-modellen i pgmpy-biblioteket för att göra förutsägelser i paraplyvärlden. Resultatet från en körning visas under koden. Detta bibliotek har följande inferensmetoder: backward_inference, forward_inference och query.

# Import libraries
import pgmpy.models
import pgmpy.inference
import numpy as np

# The main entry point for this module
def main():

    # Create a dynamic bayesian network
    model = pgmpy.models.DynamicBayesianNetwork()

    # Add nodes
    model.add_nodes_from(['Weather', 'Umbrella'])

    # Print nodes
    print('--- Nodes ---')
    print(model.nodes())

    # Add edges
    model.add_edges_from([(('Umbrella',0), ('Weather',0)),
                          (('Weather',0), ('Weather',1)),
                          (('Umbrella',0), ('Umbrella',1))])

    # Print edges
    print('--- Edges ---')
    print(model.edges())
    print()

    # Print parents
    print('--- Parents ---')
    print('Umbrella 0: {0}'.format(model.get_parents(('Umbrella', 0))))
    print('Weather 0: {0}'.format(model.get_parents(('Weather', 0))))
    print('Weather 1: {0}'.format(model.get_parents(('Weather', 1))))
    print('Umbrella 1: {0}'.format(model.get_parents(('Umbrella', 1))))
    print()

    # Add probabilities
    weather_cpd = pgmpy.factors.discrete.TabularCPD(('Weather', 0), 2, [[0.1, 0.8], 
                                                                        [0.9, 0.2]], 
                                                       evidence=[('Umbrella', 0)], 
                                                       evidence_card=[2])
    umbrella_cpd = pgmpy.factors.discrete.TabularCPD(('Umbrella', 1), 2, [[0.5, 0.5], 
                                                                          [0.5, 0.5]], 
                                                     evidence=[('Umbrella', 0)], 
                                                     evidence_card=[2])
    transition_cpd = pgmpy.factors.discrete.TabularCPD(('Weather', 1), 2, [[0.25, 0.9, 0.1, 0.25], 
                                                                           [0.75, 0.1, 0.9, 0.75]], 
                                                   evidence=[('Weather', 0), ('Umbrella', 1)], 
                                                   evidence_card=[2, 2])

    # Add conditional probability distributions (cpd:s)
    model.add_cpds(weather_cpd, umbrella_cpd, transition_cpd)

    # This method will automatically re-adjust the cpds and the edges added to the bayesian network.
    model.initialize_initial_state()

    # Check if the model is valid, throw an exception otherwise
    model.check_model()

    # Print probability distributions
    print('Probability distribution, P(Weather(0) | Umbrella(0)')
    print(weather_cpd)
    print()
    print('Probability distribution, P(Umbrella(1) | Umbrella(0)')
    print(umbrella_cpd)
    print()
    print('Probability distribution, P(Weather(1) | Umbrella(1), Weather(0)')
    print(transition_cpd)
    print()

    # Make inference
    map = {0: 'Sunny', 1: 'Rainy' }
    dbn_inf = pgmpy.inference.DBNInference(model)
    result = dbn_inf.forward_inference([('Weather', 1)], {('Umbrella', 1):0, ('Weather', 0):0})
    arr = result[('Weather', 1)].values
    print()
    print('Prediction (Umbrella(1) : Yes, Weather(0): Sunny): {0} ({1} %)'.format(map[np.argmax(arr)], np.max(arr) * 100))
    print()

    result = dbn_inf.forward_inference([('Weather', 1)], {('Umbrella', 1):0, ('Weather', 0):1})
    arr = result[('Weather', 1)].values
    print()
    print('Prediction (Umbrella(1) : Yes, Weather(0): Rainy): {0} ({1} %)'.format(map[np.argmax(arr)], np.max(arr) * 100))
    print()

    result = dbn_inf.forward_inference([('Weather', 1)], {('Umbrella', 1):1, ('Weather', 0):0})
    arr = result[('Weather', 1)].values
    print()
    print('Prediction (Umbrella(1) : No, Weather(0): Sunny): {0} ({1} %)'.format(map[np.argmax(arr)], np.max(arr) * 100))
    print()

    result = dbn_inf.forward_inference([('Weather', 1)], {('Umbrella', 1):1, ('Weather', 0):1})
    arr = result[('Weather', 1)].values
    print()
    print('Prediction (Umbrella(1) : No, Weather(0): Rainy): {0} ({1} %)'.format(map[np.argmax(arr)], np.max(arr) * 100))
    print()

# Tell python to run main method
if __name__ == "__main__": main()
--- Nodes ---
[('Weather', 0), ('Umbrella', 0)]
--- Edges ---
[(('Weather', 0), ('Weather', 1)), (('Umbrella', 0), ('Weather', 0)), (('Umbrella', 0), ('Umbrella', 1)), (('Umbrella', 1), ('Weather', 1))]

--- Parents ---
Umbrella 0: []
Weather 0: [('Umbrella', 0)]
Weather 1: [('Umbrella', 1), ('Weather', 0)]
Umbrella 1: [('Umbrella', 0)]

Probability distribution, P(Weather(0) | Umbrella(0)
+-------------------+--------------------+--------------------+
| ('Umbrella', 0)   | ('Umbrella', 0)(0) | ('Umbrella', 0)(1) |
+-------------------+--------------------+--------------------+
| ('Weather', 0)(0) | 0.1                | 0.8                |
+-------------------+--------------------+--------------------+
| ('Weather', 0)(1) | 0.9                | 0.2                |
+-------------------+--------------------+--------------------+

Probability distribution, P(Umbrella(1) | Umbrella(0)
+--------------------+--------------------+--------------------+
| ('Umbrella', 0)    | ('Umbrella', 0)(0) | ('Umbrella', 0)(1) |
+--------------------+--------------------+--------------------+
| ('Umbrella', 1)(0) | 0.5                | 0.5                |
+--------------------+--------------------+--------------------+
| ('Umbrella', 1)(1) | 0.5                | 0.5                |
+--------------------+--------------------+--------------------+

Probability distribution, P(Weather(1) | Umbrella(1), Weather(0)
+-------------------+--------------------+--------------------+--------------------+--------------------+
| ('Weather', 0)    | ('Weather', 0)(0)  | ('Weather', 0)(0)  | ('Weather', 0)(1)  | ('Weather', 0)(1)  |
+-------------------+--------------------+--------------------+--------------------+--------------------+
| ('Umbrella', 1)   | ('Umbrella', 1)(0) | ('Umbrella', 1)(1) | ('Umbrella', 1)(0) | ('Umbrella', 1)(1) |
+-------------------+--------------------+--------------------+--------------------+--------------------+
| ('Weather', 1)(0) | 0.25               | 0.9                | 0.1                | 0.25               |
+-------------------+--------------------+--------------------+--------------------+--------------------+
| ('Weather', 1)(1) | 0.75               | 0.1                | 0.9                | 0.75               |
+-------------------+--------------------+--------------------+--------------------+--------------------+

WARNING:root:Replacing existing CPD for ('Weather', 1)
WARNING:root:Replacing existing CPD for ('Umbrella', 1)
Eliminating: ('Umbrella', 0): 100%|█████████████| 1/1 [00:00<00:00, 977.24it/s]

Prediction (Umbrella(1) : Yes, Weather(0): Sunny): Rainy (75.0 %)

Eliminating: ('Umbrella', 0): 100%|████████████| 1/1 [00:00<00:00, 1001.51it/s]

Prediction (Umbrella(1) : Yes, Weather(0): Rainy): Rainy (90.0 %)

Eliminating: ('Umbrella', 0): 100%|████████████| 1/1 [00:00<00:00, 1002.70it/s]

Prediction (Umbrella(1) : No, Weather(0): Sunny): Sunny (90.0 %)

Eliminating: ('Umbrella', 0): 100%|████████████| 1/1 [00:00<00:00, 1001.27it/s]

Prediction (Umbrella(1) : No, Weather(0): Rainy): Rainy (75.0 %)

PyAgrum-implementering

Följande kod använder DBN-modellen i pyAgrum-biblioteket för att göra förutsägelser i paraplyvärlden. Resultatet från en körning visas under koden. Detta bibliotek har följande inferensmodeller: LazyPropagation, ShaferShenoyInference, VariableElimination och LoopyBeliefPropagation.

# Import libraries
import cairosvg
import pyAgrum as gum
import pyAgrum.lib.notebook as gnb
import pyAgrum.lib.dynamicBN as gdyn
import matplotlib.pyplot as plt

# The main entry point for this module
def main():

    # Create a dynamic bayesian network
    model = gum.BayesNet()

    # Add umbrella nodes
    umbrella0 = gum.LabelizedVariable('Umbrella(0)','Umbrella day 0',2)
    umbrella0.changeLabel(0,'Yes')
    umbrella0.changeLabel(1,'No')
    u0 = model.add(umbrella0)
    umbrella1 = gum.LabelizedVariable('Umbrella(1)','Umbrella day 1',2)
    umbrella1.changeLabel(0,'Yes')
    umbrella1.changeLabel(1,'No')
    u1 = model.add(umbrella1)

    # Add weather nodes
    weather0 = gum.LabelizedVariable('Weather(0)','Weather day 0',2)
    weather0.changeLabel(0,'Sunny')
    weather0.changeLabel(1,'Rainy')
    w0 = model.add(weather0)
    weather1 = gum.LabelizedVariable('Weather(1)','Weather day 1',2)
    weather1.changeLabel(0,'Sunny')
    weather1.changeLabel(1,'Rainy')
    w1 = model.add(weather1)

    # Add connections between nodes (tail, head)
    model.addArc(u0, w0)
    model.addArc(w0, w1)
    model.addArc(u1, w1)

    # Visualize bayesian network
    svg = gnb.getBN(model)
    cairosvg.svg2png(bytestring=svg,write_to='plots\\dnb_chart.png')

    # Get time slices and save as image
    svg = gdyn.getTimeSlices(model)
    cairosvg.svg2png(bytestring=svg,write_to='plots\\dnb_time_slices.png')

    # Add CPT:s (Conditional probability tables)
    model.cpt(model.idFromName('Weather(0)'))[{'Umbrella(0)':'Yes'}]=[0.1, 0.8]
    model.cpt(model.idFromName('Weather(0)'))[{'Umbrella(0)':'No'}]=[0.9, 0.2]
    model.cpt(model.idFromName('Weather(1)'))[{'Umbrella(1)':'Yes'}]=[[0.25, 0.75], 
                                                                      [0.1, 0.9]]
    model.cpt(model.idFromName('Weather(1)'))[{'Umbrella(1)':'No'}]=[[0.9, 0.1], 
                                                                     [0.75, 0.25]]

    # Create an inference model
    ie = gum.LazyPropagation(model)

    # Make inference and print the results
    print('--- Umbrella(0): No ---')
    ie.setEvidence({'Umbrella(0)':'No'})
    ie.makeInference()
    print(ie.posterior('Weather(0)'))
    print()

    print('--- Umbrella(0): Yes ---')
    ie.setEvidence({'Umbrella(0)':'Yes'})
    ie.makeInference()
    print(ie.posterior('Weather(0)'))
    print()

    print('--- Weather(0): Sunny, Umbrella(1): Yes ---')
    ie.setEvidence({'Weather(0)':'Sunny', 'Umbrella(1)':'Yes'})
    ie.makeInference()
    #gnb.getPosterior(model, {'Weather(0)':'Sunny', 'Umbrella(1)':'Yes'}, 'Weather(1)')
    #plt.show()
    print(ie.posterior('Weather(1)'))
    print()

    print('--- Weather(0): Sunny, Umbrella(1): No ---')
    ie.setEvidence({'Weather(0)':'Sunny', 'Umbrella(1)':'No'})
    ie.makeInference()
    print(ie.posterior('Weather(1)'))
    print()

    print('--- Weather(0): Rainy, Umbrella(1): Yes ---')
    ie.setEvidence({'Weather(0)':'Rainy', 'Umbrella(1)':'Yes'})
    ie.makeInference()
    print(ie.posterior('Weather(1)'))
    print()

    print('--- Weather(0): Rainy, Umbrella(1): No ---')
    ie.setEvidence({'Weather(0)':'Rainy', 'Umbrella(1)':'No'})
    ie.makeInference()
    print(ie.posterior('Weather(1)'))
    print()

# Tell python to run main method
if __name__ == "__main__": main()
--- Umbrella(0): No ---
<Weather(0):Sunny> :: 0.818182 /<Weather(0):Rainy> :: 0.181818

--- Umbrella(0): Yes ---
<Weather(0):Sunny> :: 0.111111 /<Weather(0):Rainy> :: 0.888889

--- Weather(0): Sunny, Umbrella(1): Yes ---
<Weather(1):Sunny> :: 0.25 /<Weather(1):Rainy> :: 0.75

--- Weather(0): Sunny, Umbrella(1): No ---
<Weather(1):Sunny> :: 0.9 /<Weather(1):Rainy> :: 0.1

--- Weather(0): Rainy, Umbrella(1): Yes ---
<Weather(1):Sunny> :: 0.1 /<Weather(1):Rainy> :: 0.9

--- Weather(0): Rainy, Umbrella(1): No ---
<Weather(1):Sunny> :: 0.75 /<Weather(1):Rainy> :: 0.25
Etiketter:

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *