From 6e478b0da15f500bef22e624a571aa9f59fa1e98 Mon Sep 17 00:00:00 2001 From: Anthony Marakis Date: Fri, 28 Jul 2017 16:59:02 +0300 Subject: [PATCH 1/3] add version-space learner + small fix --- knowledge.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/knowledge.py b/knowledge.py index 106176c19..a42640bfd 100644 --- a/knowledge.py +++ b/knowledge.py @@ -81,7 +81,10 @@ def generalizations(examples_so_far, h): hypotheses += h3 # Add OR operations - hypotheses.extend(add_or(examples_so_far, h)) + if hypotheses == [] or hypotheses == [{}]: + hypotheses = add_or(examples_so_far, h) + else: + hypotheses.extend(add_or(examples_so_far, h)) shuffle(hypotheses) return hypotheses @@ -111,6 +114,97 @@ def add_or(examples_so_far, h): # ______________________________________________________________________________ +def version_space_learning(examples): + """ [Figure 19.3] + The version space is a list of hypotheses, which in turn are a list + of dictionaries/disjunctions.""" + V = all_hypotheses(examples) + for e in examples: + if V: + V = version_space_update(V, e) + + return V + + +def version_space_update(V, e): + return [h for h in V if is_consistent(e, h)] + + +def all_hypotheses(examples): + """Builds a list of all the possible hypotheses""" + values = values_table(examples) + h_powerset = powerset(values.keys()) + hypotheses = [] + for s in h_powerset: + hypotheses.extend(build_attr_combinations(s, values)) + + hypotheses.extend(build_h_combinations(hypotheses)) + + return hypotheses + + +def values_table(examples): + """Builds a table with all the possible values for each attribute. + Returns a dictionary with keys the attribute names and values a list + with the possible values for the corresponding attribute.""" + values = defaultdict(lambda: []) + for e in examples: + for k, v in e.items(): + if k == 'GOAL': + continue + + mod = '!' + if e['GOAL']: + mod = '' + + if mod + v not in values[k]: + values[k].append(mod + v) + + values = dict(values) + return values + + +def build_attr_combinations(s, values): + """Given a set of attributes, builds all the combinations of values. + If the set holds more than one attribute, recursively builds the + combinations.""" + if len(s) == 1: + # s holds just one attribute, return its list of values + k = values[s[0]] + h = [[{s[0]: v}] for v in values[s[0]]] + return h + + h = [] + for i, a in enumerate(s): + rest = build_attr_combinations(s[i+1:], values) + for v in values[a]: + o = {a: v} + for r in rest: + t = o.copy() + for d in r: + t.update(d) + h.append([t]) + + return h + + +def build_h_combinations(hypotheses): + """Given a set of hypotheses, builds and returns all the combinations of the + hypotheses.""" + h = [] + h_powerset = powerset(range(len(hypotheses))) + + for s in h_powerset: + t = [] + for i in s: + t.extend(hypotheses[i]) + h.append(t) + + return h + +# ______________________________________________________________________________ + + def check_all_consistency(examples, h): """Check for the consistency of all examples under h""" for e in examples: From c935228b200ff79fc75831f209977a0a4b185872 Mon Sep 17 00:00:00 2001 From: Anthony Marakis Date: Fri, 28 Jul 2017 17:00:29 +0300 Subject: [PATCH 2/3] add test for version-space learner + trivial example --- tests/test_knowledge.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/test_knowledge.py b/tests/test_knowledge.py index d9822c625..025da5ddd 100644 --- a/tests/test_knowledge.py +++ b/tests/test_knowledge.py @@ -23,6 +23,37 @@ def test_current_best_learning(): assert values == [True, True, True, False, False, False, True] + examples = trivial + initial_h = [{'Pizza': 'Yes'}] + h = current_best_learning(examples, initial_h) + values = [] + for e in examples: + values.append(guess_value(e, h)) + + assert values == [True, True, False] + + +def test_version_space_learning(): + V = version_space_learning(trivial) + results = [] + for e in trivial: + guess = False + for h in V: + if guess_value(e, h): + guess = True + break + + results.append(guess) + + assert results == [True, True, False] + assert [{'Pizza': 'Yes'}] in V + + +trivial = [ + {'Pizza': 'Yes', 'Soda': 'No', 'GOAL': True}, + {'Pizza': 'Yes', 'Soda': 'Yes', 'GOAL': True}, + {'Pizza': 'No', 'Soda': 'No', 'GOAL': False} +] animals_umbrellas = [ {'Species': 'Cat', 'Rain': 'Yes', 'Coat': 'No', 'GOAL': True}, From 588f59f9704f5bdb8fa7aa1baf69901987a5c9f8 Mon Sep 17 00:00:00 2001 From: Anthony Marakis Date: Fri, 28 Jul 2017 17:01:40 +0300 Subject: [PATCH 3/3] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ed47475d..d7ba58b33 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Here is a table of algorithms, the figure, name of the code in the book and in t | 18.24 | Back-Prop-Learning | `BackPropagationLearner` | [`learning.py`][learning] | | 18.34 | AdaBoost | `AdaBoost` | [`learning.py`][learning] | | 19.2 | Current-Best-Learning | `current_best_learning` | [`knowledge.py`](knowledge.py) | -| 19.3 | Version-Space-Learning | | +| 19.3 | Version-Space-Learning | `version_space_learning` | [`knowledge.py`](knowledge.py) | | 19.8 | Minimal-Consistent-Det | | | 19.12 | FOIL | | | 21.2 | Passive-ADP-Agent | `PassiveADPAgent` | [`rl.py`][rl] |