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