From d34fc788ab182ad3a68dd4f4beb0ba8098670b91 Mon Sep 17 00:00:00 2001 From: Jon <vitale.jonathan@ymail.com> Date: Mon, 24 Jul 2023 19:26:13 +0200 Subject: [PATCH] Add material and solution for workshop week 6 --- week6/material/burglar_alarm.py | 102 +++++++++++ week6/material/rain_umbrella.py | 34 ++++ week6/solution/exercise1-2.py | 306 ++++++++++++++++++++++++++++++++ week6/solution/exercise3.py | 92 ++++++++++ week6/solution/exercise4.py | 64 +++++++ week6/solution/exercise5.py | 59 ++++++ 6 files changed, 657 insertions(+) create mode 100644 week6/material/burglar_alarm.py create mode 100644 week6/material/rain_umbrella.py create mode 100644 week6/solution/exercise1-2.py create mode 100644 week6/solution/exercise3.py create mode 100644 week6/solution/exercise4.py create mode 100644 week6/solution/exercise5.py diff --git a/week6/material/burglar_alarm.py b/week6/material/burglar_alarm.py new file mode 100644 index 0000000..e5a5b3e --- /dev/null +++ b/week6/material/burglar_alarm.py @@ -0,0 +1,102 @@ +from pgmpy.models import BayesianNetwork +from pgmpy.factors.discrete.CPD import TabularCPD + +# Let's create the Bayesian network model +burglar_alarm_bn = BayesianNetwork() + +# Adding the nodes to the network +burglar_alarm_bn.add_nodes_from(['Burglary', 'Earthquake', 'Alarm', 'JohnCalls', 'MaryCalls']) + +# Adding dependencies +burglar_alarm_bn.add_edge('Burglary', 'Alarm') +burglar_alarm_bn.add_edge('Earthquake', 'Alarm') +burglar_alarm_bn.add_edge('Alarm', 'JohnCalls') +burglar_alarm_bn.add_edge('Alarm', 'MaryCalls') + +# Conditional probability tables + +burglary_cpd = TabularCPD( + variable='Burglary', + variable_card=2, + values=[[0.001], [0.999]] +) + +eq_cpd = TabularCPD( + variable='Earthquake', + variable_card=2, + values=[[0.002], [0.998]] +) + +alarm_cpd = TabularCPD( + variable='Alarm', + variable_card=2, + evidence=['Burglary', 'Earthquake'], + evidence_card=[2, 2], + values=[ + # B=true^E=true, B=true^E=false, B=false^E=true, B=false^E=false + [0.95, 0.94, 0.29, 0.001], # Alarm true + [0.05, 0.06, 0.71, 0.999] # Alarm false + ] +) + +jc_cpd = TabularCPD( + variable='JohnCalls', + variable_card=2, + evidence=['Alarm'], + evidence_card=[2], + values=[ + # Alarm=true, Alarm=false + [0.9, 0.05], # JC true + [0.1, 0.95] # JC false + ] +) + +mc_cpd = TabularCPD( + variable='MaryCalls', + variable_card=2, + evidence=['Alarm'], + evidence_card=[2], + values=[ + # Alarm=true, Alarm=false + [0.7, 0.01], # MC true + [0.3, 0.99] # MC false + ] +) + +burglar_alarm_bn.add_cpds(burglary_cpd, eq_cpd, alarm_cpd, jc_cpd, mc_cpd) + +# checking that everything is ok +try: + model_check = burglar_alarm_bn.check_model() +except Exception as e: + model_check = e + +if model_check == True: + print("The Bayesian network model does not have any error") +else: + print("Warning! There is an error in the Bayesian network model: {0}".format(e)) + +# Probabilistic inference +from pgmpy.inference import VariableElimination + +inference = VariableElimination(burglar_alarm_bn) + +# Probability of Alarm being on or off +query = inference.query(variables=['Alarm']) +print("What is the probability for the alarm to become activated?") +print(query) + +# Probability of Alarm being on or off given JohnCalls=true +query = inference.query(variables=['Alarm'], evidence={'JohnCalls': 0}) +print("What is the probability for the alarm to become activated given that John called?") +print(query) + +# Probability of Burglary and Alarm given JohnCalls=true +query = inference.query(variables=['Burglary','Alarm'], evidence={'JohnCalls': 0}) +print("What is the probability of a burglar in the apartment and the alarm to be active given that John called?") +print(query) + +# MAP query +query = inference.map_query(variables=['JohnCalls', 'MaryCalls'], evidence={'Burglary': 0}) +print("Who would more likely call us when a burglar is in our house?") +print(query) \ No newline at end of file diff --git a/week6/material/rain_umbrella.py b/week6/material/rain_umbrella.py new file mode 100644 index 0000000..3823ddf --- /dev/null +++ b/week6/material/rain_umbrella.py @@ -0,0 +1,34 @@ +from pomegranate.distributions import Categorical +from pomegranate.hmm import DenseHMM +import numpy as np + +model = DenseHMM() + +states = ['rain', 'not_rain'] + +# emission probability distributions for the two hidden states +rain = Categorical([[0.9, 0.1]]) # 90% chances of seeing the umbrella if it's raining +not_rain = Categorical([[0.2, 0.8]]) # 20% chances of seeing the umbrella if it's not raining +model.add_distributions([rain, not_rain]) + +# Initial probabilities for state X0 +model.add_edge(model.start, rain, 0.5) +model.add_edge(model.start, not_rain, 0.5) + +# Transition probabilities +model.add_edge(rain, rain, 0.7) +model.add_edge(rain, not_rain, 0.3) +model.add_edge(not_rain, rain, 0.3) +model.add_edge(not_rain, not_rain, 0.7) + +# Using the following observations +observations = ['umbrella', 'umbrella', 'not_umbrella', 'umbrella', 'not_umbrella', 'not_umbrella', 'not_umbrella'] +X = np.array([[[['umbrella', 'not_umbrella'].index(label)] for label in observations]]) + +# Making a prediction of the most likely sequence of states that generated the observations +y_hat = model.predict(X) +predictions = [states[y] for y in y_hat[0].tolist()] + +# Results +print("Observations: {}".format(observations)) +print("hmm pred: {}".format(predictions)) \ No newline at end of file diff --git a/week6/solution/exercise1-2.py b/week6/solution/exercise1-2.py new file mode 100644 index 0000000..bff4f79 --- /dev/null +++ b/week6/solution/exercise1-2.py @@ -0,0 +1,306 @@ +""" +Exercise 1: + +From the scenario we can identify the following RVs: + +SpottingUnicorn, PureHeartWizard, SpottingTarantula, TimeOfDay, BraveWizard, WizardHouse + +Now we can specify the ranges for these RVs: + +UnicornSighting: {true, false} +PureHeart: {true, false} +AcromantulaSighting: {true, false} +TimeOfDay: {day, night} +House: {hufflepuff, gryffindor, ravenclaw, slytherin} +Brave: {true, false} + +Dependencies: + +UnicornSighting depends on PureHeart +PureHeart depends on House +AcromantulaSighting depends on TimeOfDay and Brave +Brave depends on House + +We can specify the following probability distributions given by the scenario: +""" + +pd = {} + +pd['UnicornSighting=true|PureHeart=false'] = 1/400 +pd['UnicornSighting=false|PureHeart=false'] = 1 - pd['UnicornSighting=true|PureHeart=false'] +pd['UnicornSighting=true|PureHeart=true'] = 0.1 +pd['UnicornSighting=false|PureHeart=true'] = 1 - pd['UnicornSighting=true|PureHeart=true'] +pd['TimeOfDay=day'] = 0.5 # assuming uniform distribution +pd['TimeOfDay=night'] = 0.5 # assuming uniform distribution + +probs = [0.01, 0.025, 0.05, 0.1] +i = 0 +for t in ['day', 'night']: + for brave in ['true', 'false']: + pd['AcromantulaSighting=true|TimeOfDay={0},Brave={1}'.format(t, brave)] = probs[i] + pd['AcromantulaSighting=false|TimeOfDay={0},Brave={1}'.format(t, brave)] = 1 - probs[i] + i += 1 + +houses = ['gryffindor', 'ravenclaw', 'slytherin', 'hufflepuff'] +for i, prob in enumerate([0.002, 0.002, 0.0001, 0.01]): + pd['PureHeart=true|House={0}'.format(houses[i])] = prob + pd['PureHeart=false|House={0}'.format(houses[i])] = 1 - prob +for i, prob in enumerate([0.05, 0.02, 0.02, 0.001]): + pd['Brave=true|House={0}'.format(houses[i])] = prob + pd['Brave=false|House={0}'.format(houses[i])] = 1 - prob +for house in houses: + pd['House={0}'.format(house)] = 0.25 + +print("\n>>>Given probability distributions:") +for key, value in pd.items(): + print('P({0}) = {1}'.format(key, value)) + +""" +Exercise 2: Inference + +Now we can proceed to infer new information from the one available. +""" + +print('\n>>>Inferred probability distributions:') + +""" +1. Computing P(PureHeart): + +We can find thid distribution by marginalising the joint distribution P(PureHeart, House): + +P(PureHeart) = sum_h P(PureHeart, House) += sum_h P(PureHeart | House)P(House) + +""" +for heart in ['true', 'false']: + cur_key = 'PureHeart={0}'.format(heart) + pd[cur_key] = 0 + for house in houses: + pd[cur_key] += pd['PureHeart={0}|House={1}'.format(heart, house)]*pd['House={0}'.format(house)] + + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +2. Computing P(UnicornSighting): + +We can estimate the prior by marginalising the joint distribution P(UnicornSighting, PureHeart): + +P(UnicornSighting) = sum_h P(UnicornSighting, PureHeart = h) += sum_h P(UnicornSighting | PureHeart = h)P(Heart = h) +""" +for unicorn in ['true', 'false']: + cur_key = 'UnicornSighting={0}'.format(unicorn) + pd[cur_key] = 0 + for heart in ['true', 'false']: + pd[cur_key] += pd['UnicornSighting={0}|PureHeart={1}'.format(unicorn, heart)]*pd['PureHeart={0}'.format(heart)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) +""" + +3. Computing P(Brave): + +We can marginalise this variable from the joint distribution + +P(Brave, House) = P(Brave | House)P(House) + +so + +P(Brave) = sum_h P(Brave | House = h)P(House = h) +""" + +pd['Brave=true'] = 0 +pd['Brave=false'] = 0 + +for house in houses: + for brave in ['true', 'false']: + pd['Brave={0}'.format(brave)] += pd['Brave={0}|House={1}'.format(brave, house)]*pd['House={0}'.format(house)] + +print("P(Brave=true) = {0}".format(pd['Brave=true'])) +print("P(Brave=false) = {0}".format(pd['Brave=false'])) + +""" +4. Computing P(House | Brave): + +Given the Bayes' rule, + +P(House | Brave) = P(Brave | House)P(House) / P(Brave) + +Therefore +""" + +for house in houses: + for brave in ['true', 'false']: + cur_key = 'House={0}|Brave={1}'.format(house, brave) + pd[cur_key] = (pd['Brave={0}|House={1}'.format(brave,house)]*pd['House={0}'.format(house)])/pd['Brave={0}'.format(brave)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +5. Computing P(AcromantulaSighting): + +We can marginalise AcromantulaSighting from the joint distribution P(AcromantulaSighting, TimeOfDay, Brave) + +P(A) = sum_t sum_b P(A, T=t, B=b) = sum_t sum_b P(A | T=t, B=b)P(T=t | B=b)P(B=b) + +TimeOfDay is independent from Brave because Brave is a non-descentent of TimeOfDay and +TimeOfDay does not have parents, therefore we can simplify the formula: + +P(A) = sum_t sum_b P(A | T=t, B=b)P(T=t)P(B=b) + +""" +for acromantula in ['true', 'false']: + cur_key = 'AcromantulaSighting={0}'.format(acromantula) + pd[cur_key] = 0 + for t in ['day', 'night']: + for brave in ['true', 'false']: + pd[cur_key] += pd['AcromantulaSighting={0}|TimeOfDay={1},Brave={2}'.format(acromantula, t, brave)]*pd['TimeOfDay={0}'.format(t)]*pd["Brave={0}".format(brave)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +6. Computing P(AcromantulaSighting | TimeOfDay): + +As per the Bayes' rule + +P(AcromantulaSighiting | TimeOfDay) = P(AcromantulaSighting, TimeOfDay) / P(TimeOfDay) + +We can compute P(AcromantulaSighting, TimeOfDay) by marginalising the joint distribution + +P(AcromantulaSighting, TimeOfDay, Brave) = P(AcromantulaSighting | TimeOfDay, Brave)P(TimeOfDay)P(Brave) + +P(AcromantulaSighting, TimeOfDay) = sum_b P(AcromantulaSighting | TimeOfDay, Brave=b)P(TimeOfDay)P(Brave=b) +""" + +for acromantula in ['true', 'false']: + for t in ['day', 'night']: + cur_key = 'AcromantulaSighting={0},TimeOfDay={1}'.format(acromantula, t) + pd[cur_key] = 0 + for brave in ['true', 'false']: + pd[cur_key] += pd['AcromantulaSighting={0}|TimeOfDay={1},Brave={2}'.format(acromantula, t, brave)]*pd['TimeOfDay={0}'.format(t)]*pd['Brave={0}'.format(brave)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) +""" +Now we can plug this in and compute the posteriori +""" +for acromantula in ['true', 'false']: + for t in ['day', 'night']: + cur_key = 'AcromantulaSighting={0}|TimeOfDay={1}'.format(acromantula, t) + pd[cur_key] = pd['AcromantulaSighting={0},TimeOfDay={1}'.format(acromantula, t)]/pd['TimeOfDay={0}'.format(t)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) +""" +7. Computing P(AcromantulaSighting | Brave): + +As per the Bayes' rule + +P(AcromantulaSighting | Brave) = P(AcromantulaSighting, Brave) / P(Brave) + +We can compute P(AcromantulaSighting, Brave) by marginalising P(AcromantulaSighting, TimeOfDay, Brave) + +P(AcromantulaSighting, Brave) = sum_t P(AcromantulaSighting, TimeOfDay=t, Brave) +P(AcromantulaSighting, Brave) = sum_t P(AcromantulaSighting | TimeOfDay=t, Brave)P(TimeOfDay = t)P(Brave) +""" +for acromantula in ['true', 'false']: + for brave in ['true', 'false']: + cur_key = 'AcromantulaSighting={0},Brave={1}'.format(acromantula, brave) + pd[cur_key] = 0 + for t in ['day', 'night']: + pd[cur_key] += pd['AcromantulaSighting={0}|TimeOfDay={1},Brave={2}'.format(acromantula, t, brave)]*pd['TimeOfDay={0}'.format(t)]*pd['Brave={0}'.format(brave)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) +""" +Now we can plug it in the bayes rule +""" +for acromantula in ['true', 'false']: + for brave in ['true', 'false']: + cur_key = 'AcromantulaSighting={0}|Brave={1}'.format(acromantula, brave) + pd[cur_key] = pd['AcromantulaSighting={0},Brave={1}'.format(acromantula, brave)]/pd['Brave={0}'.format(brave)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +8. Computing P(AcromantulaSighting | House): + +P(A | H) = P(A, H) / P(H) + +P(A, H) = sum_b P(A, B=b, H) = sum_b P(A | B=b, H)P(B=b| H)P(H) + +In this scenario, A is conditionally independent from H given B, in fact, if we know that a student is brave, we don't +need to know their house to infer the likelihood of spotting an acromantula. Therefore: + +P(A, H) = P(H) sum_b P(A | B=b)P(B=b | H) + +By putting all together + +P(A | H) = [P(H) sum_b P(A | B=b)P(B=b | H)] / P(H) = sum_b P(A | B=b)P(B=b | H) +""" +for acromantula in ['true', 'false']: + for house in houses: + cur_key = 'AcromantulaSighting={0}|House={1}'.format(acromantula, house) + if cur_key not in pd: + pd[cur_key] = 0 + for brave in ['true', 'false']: + pd[cur_key] += pd['AcromantulaSighting={0}|Brave={1}'.format(acromantula, brave)]*pd['Brave={0}|House={1}'.format(brave,house)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +9. Computing P(AcromantulaSighting | TimeOfDay, House): + +We can use the Bayes' rule: + +P(A | T, H) = P(T, H, A) / P(T, H) + +We know that TimeOfDay is independent from House so + +P(A | T, H) = P(T, H, A) / (P(T)P(H)) + +We can decompose the joint distribution P(T, H, A) with the chain rule + +P(T, H, A) = P(T | H, A)P(H | A)P(A) + +We know that TimeOfDay is independent from House, so we obtain + +P(T, H, A) = P(T | A)P(H | A)P(A) + +We need to compute P(T | A) and P(H | A). We can compute them +by using the Bayes' rule: + +P(T | A) = P(A, T) / P(A) + +P(H | A) = P(A | H)P(H) / P(A) +""" +for t in ['day', 'night']: + for acromantula in ['true', 'false']: + cur_key = 'TimeOfDay={0}|AcromantulaSighting={1}'.format(t, acromantula) + pd[cur_key] = pd['AcromantulaSighting={0},TimeOfDay={1}'.format(acromantula, t)]/pd['AcromantulaSighting={0}'.format(acromantula)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +for house in houses: + for acromantula in ['true', 'false']: + cur_key = 'House={0}|AcromantulaSighting={1}'.format(house, acromantula) + pd[cur_key] = (pd['AcromantulaSighting={0}|House={1}'.format(acromantula, house)]*pd['House={0}'.format(house)])/pd['AcromantulaSighting={0}'.format(acromantula)] + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" + +And now we can finally compute P(A | T, H) by putting all together + +P(A | T, H) = (P(T | A)P(H | A)P(A)) / (P(T)P(H)) +""" +for acromantula in ['true', 'false']: + for t in ['day', 'night']: + for house in houses: + cur_key = 'AcromantulaSighting={0}|TimeOfDay={1},House={2}'.format(acromantula, t, house) + pd[cur_key] = (pd['TimeOfDay={0}|AcromantulaSighting={1}'.format(t, acromantula)]*pd['House={0}|AcromantulaSighting={1}'.format(house, acromantula)]*pd['AcromantulaSighting={0}'.format(acromantula)]) / \ + (pd['TimeOfDay={0}'.format(t)]*pd['House={0}'.format(house)]) + print('P({0}) = {1}'.format(cur_key, pd[cur_key])) + +""" +10. Harry Potter is from Gryffindor. We already have P(A | T, H) so we don't need to compute it again + +""" +print("\n>>>Answers:") + +print("1. What are the chances of a Hogwarts' student to posses a pure heart?", pd['PureHeart=true']) +print("2. What is the likelihood of spotting a unicorn in the Forbidden Forest?", pd['UnicornSighting=true']) +print("3. What is the likelihood for a Hogwarts' student to be brave?", pd['Brave=true']) +print("4. What are the chances for a brave student to come from the Gryffindor house?", pd['House=gryffindor|Brave=true']) +print("5. What are the chances of seeing an acromantula in the Forbidden Forest?", pd['AcromantulaSighting=true']) +print("6. How likely is it to spot an acromantula at night?", pd['AcromantulaSighting=true|TimeOfDay=night']) +print("7. What are the chances for a brave student to encounter an acromantula?", pd['AcromantulaSighting=true|Brave=true']) +print("8. What is the likelihood of encountering an acromantula for a Ravenclaw student?", pd['AcromantulaSighting=true|House=ravenclaw']) +print("9. To what extent the likelihood of encountering an acromantula for a Ravenclaw student increases at night?", "It increases of " + str(pd['AcromantulaSighting=true|TimeOfDay=night,House=ravenclaw']/pd['AcromantulaSighting=true|House=ravenclaw']) + " times") +print("10. What is the likelihood for Harry Potter to encounter an acromantula when sneaking out from his dormroom during the night?", pd['AcromantulaSighting=true|TimeOfDay=night,House=gryffindor']) \ No newline at end of file diff --git a/week6/solution/exercise3.py b/week6/solution/exercise3.py new file mode 100644 index 0000000..a1a0ec8 --- /dev/null +++ b/week6/solution/exercise3.py @@ -0,0 +1,92 @@ +from pgmpy.models import BayesianNetwork +from pgmpy.factors.discrete.CPD import TabularCPD + +# Creating a Bayesian network and its nodes +hogwarts_bn = BayesianNetwork() +hogwarts_bn.add_nodes_from( + ['UnicornSighting', 'PureHeart', 'AcromantulaSighting', + 'TimeOfDay', 'House', 'Brave'] +) + +# Adding dependencies +hogwarts_bn.add_edge('House', 'PureHeart') +hogwarts_bn.add_edge('House', 'Brave') +hogwarts_bn.add_edge('House', 'PureHeart') +hogwarts_bn.add_edge('PureHeart', 'UnicornSighting') +hogwarts_bn.add_edge('Brave', 'AcromantulaSighting') +hogwarts_bn.add_edge('TimeOfDay', 'AcromantulaSighting') + +# Adding CPD tables to nodes +time_cpd = TabularCPD( + variable='TimeOfDay', + variable_card=2, + values=[[0.5], [0.5]] +) +hogwarts_bn.add_cpds(time_cpd) + +house_cpd = TabularCPD( + variable='House', + variable_card=4, + values=[[0.25], [0.25], [0.25], [0.25]] +) +hogwarts_bn.add_cpds(house_cpd) + +unicorn_cpd = TabularCPD( + variable='UnicornSighting', + variable_card=2, + evidence=['PureHeart'], + evidence_card=[2], + values=[ + [0.1, 1/400], # UnicornSighting True + [1 - 0.1, 1 - (1/400)] # UnicornSighting False + ] +) +hogwarts_bn.add_cpds(unicorn_cpd) + +heart_cpd = TabularCPD( + variable='PureHeart', + variable_card=2, + evidence=['House'], + evidence_card=[4], + values=[ + [0.002, 0.002, 0.0001, 0.01], # PureHeart true + [1 - 0.002, 1 - 0.002, 1 - 0.0001, 1 - 0.01] # PureHeart false + ] +) +hogwarts_bn.add_cpds(heart_cpd) + +brave_cpd = TabularCPD( + variable='Brave', + variable_card=2, + evidence=['House'], + evidence_card=[4], + values=[ + [0.05, 0.02, 0.02, 0.001], # Brave true + [1 - 0.05, 1 - 0.02, 1 - 0.02, 1 - 0.001] # Brave false + ] +) +hogwarts_bn.add_cpds(brave_cpd) + +acromantula_cpd = TabularCPD( + variable='AcromantulaSighting', + variable_card=2, + evidence=['TimeOfDay', 'Brave'], + evidence_card=[2, 2], + values=[ + [0.01, 0.025, 0.05, 0.1], # AcromantulaSighting true + [1 - 0.01, 1 - 0.025, 1 - 0.05, 1 - 0.1] # AcromantulaSighting false + ] +) +hogwarts_bn.add_cpds(acromantula_cpd) + +# checking that everything is ok +try: + model_check = hogwarts_bn.check_model() +except Exception as e: + model_check = e + +if __name__ == "__main__": + if model_check == True: + print("The Bayesian network model does not have any error") + else: + print("Warning! There is an error in the Bayesian network model: {0}".format(e)) \ No newline at end of file diff --git a/week6/solution/exercise4.py b/week6/solution/exercise4.py new file mode 100644 index 0000000..1c1aec9 --- /dev/null +++ b/week6/solution/exercise4.py @@ -0,0 +1,64 @@ +from pgmpy.inference import VariableElimination +from exercise3 import hogwarts_bn + +inference = VariableElimination(hogwarts_bn) + +# Question 1 +query = inference.query(variables=['PureHeart']) +print("1. What are the chances of a Hogwarts' student to posses a pure heart?") +print(query) + +# Question 2 +query = inference.query(variables=['UnicornSighting']) +print("2. What is the likelihood of spotting a unicorn in the Forbidden Forest?") +print(query) + +# Question 3 +query = inference.query(variables=['Brave']) +print("3. What is the likelihood for a Hogwarts' student to be brave?") +print(query) + +# Question 4 +query = inference.query(variables=['House'], evidence={'Brave': 0}) +print("4. What are the chances that a brave student comes from the Gryffindor house?") +print(query) + +# Question 5 +query = inference.query(variables=['AcromantulaSighting']) +print("5. What are the chances of seeing an acromantula in the Forbidden Forest?") +print(query) + +# Question 6 +query = inference.query(variables=['AcromantulaSighting'], evidence={'TimeOfDay': 1}) +print("6. How likely is it to spot an acromantula at night?") +print(query) + +# Question 7 +query = inference.query(variables=['AcromantulaSighting'], evidence={'Brave': 0}) +print("7. What are the chances for a brave student to encounter an acromantula?") +print(query) + +# Question 8 +query = inference.query(variables=['AcromantulaSighting'], evidence={'House': 1}) +print("8. What is the likelihood of encountering an acromantula for a Ravenclaw student?") +print(query) + +# Question 9 +temp = inference.query(variables=['AcromantulaSighting'], evidence={'TimeOfDay':1, 'House': 1}) +print("9. To what extent the likelihood of encountering an acromantula for a Ravenclaw student increases at night?") +print("It increases of ", temp.values[0]/query.values[0], " times") + +# Question 10 +query = inference.query(variables=['AcromantulaSighting'], evidence={'TimeOfDay':1, 'House': 0}) +print("10. What is the likelihood for Harry Potter to encounter an acromantula when sneaking out from his dormroom during the night?") +print(query) + +# Question 11 +query = inference.map_query(variables=['AcromantulaSighting', 'UnicornSighting'], evidence={'TimeOfDay': 1, 'House': 2}) +print("11. Consider Draco Malfoy sneaking out to go Forbidden Forest at night. Which scenario most likely happen? a. He will spot an acromantula and a unicorn, b. He will spot an acromantula only, c. He will spot a unicorn only, d. He will not spot any creature.") +print(query) + +# Question 12 +query = inference.map_query(variables=['House'], evidence={'Brave': 0, 'PureHeart': 0}) +print("12. To which house a brave and pure hearted student is more likely to be allocated by the Sorting Hat?") +print(query) diff --git a/week6/solution/exercise5.py b/week6/solution/exercise5.py new file mode 100644 index 0000000..0c3038d --- /dev/null +++ b/week6/solution/exercise5.py @@ -0,0 +1,59 @@ +from pomegranate.distributions import Categorical +from pomegranate.hmm import DenseHMM +import numpy as np + +from pgmpy.inference import VariableElimination +from exercise3 import hogwarts_bn + +inference = VariableElimination(hogwarts_bn) + +hogwarts_hmm = DenseHMM() + +states = ['gryffindor', 'ravenclaw', 'slytherin', 'hufflepuff'] + +# Possible observations: +# 0. AcromantulaSighting=true, UnicornSighting=true (AU) +# 1. AcromantulaSighting=true, UnicornSighting=false (AX) +# 2. AcromantulaSighting=false, UnicornSighting=true (XU) +# 4. AcromantulaSighting=false, UnicornSighting=false (XX) + +# emission probability distributions for the two hidden states +state_dists = [None, None, None, None] + +for i, house in enumerate(states): + query = inference.query(variables=['AcromantulaSighting','UnicornSighting'], evidence={'House': i, 'TimeOfDay': 1} ) + val = query.values + probabilities = [val[0,0], val[0,1], val[1,0], val[1,1]] + print(np.array(probabilities).sum()) + cur_state_dist = Categorical([probabilities]) + state_dists[i] = cur_state_dist + +hogwarts_hmm.add_distributions(state_dists) + +# Transition probabilities +# 25% uniform chances for a student to be allocated to a house + +for i in range(4): + hogwarts_hmm.add_edge(hogwarts_hmm.start, state_dists[i], 0.25) + +# and then it is impossible to change house, so we keep the chances very low +for i in range(4): + for j in range(4): + if i == j: + prob = 0.997 + else: + prob = 0.001 + hogwarts_hmm.add_edge(state_dists[i],state_dists[j], prob) + + +# Using the following observations +observations = ['00', '00', '00', 'X0', '00', '00', 'X0', '00', '0X', '00'] +X = np.array([[[['XX', 'X0', '0X', '00'].index(label)] for label in observations]]) + +# Making a prediction of the most likely sequence of states that generated the observations +y_hat = hogwarts_hmm.predict(X) +predictions = [states[y] for y in y_hat[0].tolist()] + +# Results +print("Observations: {}".format(observations)) +print("hmm pred: {}".format(predictions)) \ No newline at end of file -- GitLab