Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implementation: Current Best Learning #593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Here is a table of algorithms, the figure, name of the code in the book and in t
| 18.11 | Decision-List-Learning | `DecisionListLearner` | [`learning.py`][learning] |
| 18.24 | Back-Prop-Learning | `BackPropagationLearner` | [`learning.py`][learning] |
| 18.34 | AdaBoost | `AdaBoost` | [`learning.py`][learning] |
| 19.2 | Current-Best-Learning | |
| 19.2 | Current-Best-Learning | `current_best_learning` | [`knowledge.py`](knowledge.py) |
| 19.3 | Version-Space-Learning | |
| 19.8 | Minimal-Consistent-Det | |
| 19.12 | FOIL | |
Expand Down Expand Up @@ -146,6 +146,7 @@ Many thanks for contributions over the years. I got bug reports, corrected code,
[csp]:../master/csp.py
[games]:../master/games.py
[grid]:../master/grid.py
[knowledge]:../master/knowledge.py
[learning]:../master/learning.py
[logic]:../master/logic.py
[mdp]:../master/mdp.py
Expand Down
175 changes: 175 additions & 0 deletions knowledge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
"""Knowledge in learning, Chapter 19"""

from random import shuffle
from utils import powerset
from collections import defaultdict

# ______________________________________________________________________________


def current_best_learning(examples, h, examples_so_far=[]):
""" [Figure 19.2]
The hypothesis is a list of dictionaries, with each dictionary representing
a disjunction."""
if not examples:
return h

e = examples[0]
if is_consistent(e, h):
return current_best_learning(examples[1:], h, examples_so_far + [e])
elif false_positive(e, h):
for h2 in specializations(examples_so_far + [e], h):
h3 = current_best_learning(examples[1:], h2, examples_so_far + [e])
if h3 != 'FAIL':
return h3
elif false_negative(e, h):
for h2 in generalizations(examples_so_far + [e], h):
h3 = current_best_learning(examples[1:], h2, examples_so_far + [e])
if h3 != 'FAIL':
return h3

return 'FAIL'


def specializations(examples_so_far, h):
"""Specialize the hypothesis by adding AND operations to the disjunctions"""
hypotheses = []

for i, disj in enumerate(h):
for e in examples_so_far:
for k, v in e.items():
if k in disj or k == 'GOAL':
continue

h2 = h[i].copy()
h2[k] = '!' + v
h3 = h.copy()
h3[i] = h2
if check_all_consistency(examples_so_far, h3):
hypotheses.append(h3)

shuffle(hypotheses)
return hypotheses


def generalizations(examples_so_far, h):
"""Generalize the hypothesis. First delete operations
(including disjunctions) from the hypothesis. Then, add OR operations."""
hypotheses = []

# Delete disjunctions
disj_powerset = powerset(range(len(h)))
for disjs in disj_powerset:
h2 = h.copy()
for d in reversed(list(disjs)):
del h2[d]

if check_all_consistency(examples_so_far, h2):
hypotheses += h2

# Delete AND operations in disjunctions
for i, disj in enumerate(h):
a_powerset = powerset(disj.keys())
for attrs in a_powerset:
h2 = h[i].copy()
for a in attrs:
del h2[a]

if check_all_consistency(examples_so_far, [h2]):
h3 = h.copy()
h3[i] = h2.copy()
hypotheses += h3

# Add OR operations
hypotheses.extend(add_or(examples_so_far, h))

shuffle(hypotheses)
return hypotheses


def add_or(examples_so_far, h):
"""Adds an OR operation to the hypothesis. The AND operations in the disjunction
are generated by the last example (which is the problematic one)."""
ors = []
e = examples_so_far[-1]

attrs = {k: v for k, v in e.items() if k != 'GOAL'}
a_powerset = powerset(attrs.keys())

for c in a_powerset:
h2 = {}
for k in c:
h2[k] = attrs[k]

if check_negative_consistency(examples_so_far, h2):
h3 = h.copy()
h3.append(h2)
ors.append(h3)

return ors

# ______________________________________________________________________________


def check_all_consistency(examples, h):
"""Check for the consistency of all examples under h"""
for e in examples:
if not is_consistent(e, h):
return False

return True


def check_negative_consistency(examples, h):
"""Check if the negative examples are consistent under h"""
for e in examples:
if e['GOAL']:
continue

if not is_consistent(e, [h]):
return False

return True


def disjunction_value(e, d):
"""The value of example e under disjunction d"""
for k, v in d.items():
if v[0] == '!':
# v is a NOT expression
# e[k], thus, should not be equal to v
if e[k] == v[1:]:
return False
elif e[k] != v:
return False

return True


def guess_value(e, h):
"""Guess value of example e under hypothesis h"""
for d in h:
if disjunction_value(e, d):
return True

return False


def is_consistent(e, h):
return e["GOAL"] == guess_value(e, h)


def false_positive(e, h):
if e["GOAL"] == False:
if guess_value(e, h):
return True

return False


def false_negative(e, h):
if e["GOAL"] == True:
if not guess_value(e, h):
return True

return False
2 changes: 1 addition & 1 deletion learning.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Learn to estimate functions from examples. (Chapters 18-20)"""
"""Learn to estimate functions from examples. (Chapters 18, 20)"""

from utils import (
removeall, unique, product, mode, argmax, argmax_random_tie, isclose, gaussian,
Expand Down
85 changes: 85 additions & 0 deletions tests/test_knowledge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from knowledge import *
import random

random.seed("aima-python")


def test_current_best_learning():
examples = restaurant
hypothesis = [{'Alt': 'Yes'}]
h = current_best_learning(examples, hypothesis)
values = []
for e in examples:
values.append(guess_value(e, h))

assert values == [True, False, True, True, False, True, False, True, False, False, False, True]

examples = animals_umbrellas
initial_h = [{'Species': 'Cat'}]
h = current_best_learning(examples, initial_h)
values = []
for e in examples:
values.append(guess_value(e, h))

assert values == [True, True, True, False, False, False, True]


animals_umbrellas = [
{'Species': 'Cat', 'Rain': 'Yes', 'Coat': 'No', 'GOAL': True},
{'Species': 'Cat', 'Rain': 'Yes', 'Coat': 'Yes', 'GOAL': True},
{'Species': 'Dog', 'Rain': 'Yes', 'Coat': 'Yes', 'GOAL': True},
{'Species': 'Dog', 'Rain': 'Yes', 'Coat': 'No', 'GOAL': False},
{'Species': 'Dog', 'Rain': 'No', 'Coat': 'No', 'GOAL': False},
{'Species': 'Cat', 'Rain': 'No', 'Coat': 'No', 'GOAL': False},
{'Species': 'Cat', 'Rain': 'No', 'Coat': 'Yes', 'GOAL': True}
]

restaurant = [
{'Alt': 'Yes', 'Bar': 'No', 'Fri': 'No', 'Hun': 'Yes', 'Pat': 'Some',
'Price': '$$$', 'Rain': 'No', 'Res': 'Yes', 'Type': 'French', 'Est': '0-10',
'GOAL': True},

{'Alt': 'Yes', 'Bar': 'No', 'Fri': 'No', 'Hun': 'Yes', 'Pat': 'Full',
'Price': '$', 'Rain': 'No', 'Res': 'No', 'Type': 'Thai', 'Est': '30-60',
'GOAL': False},

{'Alt': 'No', 'Bar': 'Yes', 'Fri': 'No', 'Hun': 'No', 'Pat': 'Some',
'Price': '$', 'Rain': 'No', 'Res': 'No', 'Type': 'Burger', 'Est': '0-10',
'GOAL': True},

{'Alt': 'Yes', 'Bar': 'No', 'Fri': 'Yes', 'Hun': 'Yes', 'Pat': 'Full',
'Price': '$', 'Rain': 'Yes', 'Res': 'No', 'Type': 'Thai', 'Est': '10-30',
'GOAL': True},

{'Alt': 'Yes', 'Bar': 'No', 'Fri': 'Yes', 'Hun': 'No', 'Pat': 'Full',
'Price': '$$$', 'Rain': 'No', 'Res': 'Yes', 'Type': 'French', 'Est': '>60',
'GOAL': False},

{'Alt': 'No', 'Bar': 'Yes', 'Fri': 'No', 'Hun': 'Yes', 'Pat': 'Some',
'Price': '$$', 'Rain': 'Yes', 'Res': 'Yes', 'Type': 'Italian', 'Est': '0-10',
'GOAL': True},

{'Alt': 'No', 'Bar': 'Yes', 'Fri': 'No', 'Hun': 'No', 'Pat': 'None',
'Price': '$', 'Rain': 'Yes', 'Res': 'No', 'Type': 'Burger', 'Est': '0-10',
'GOAL': False},

{'Alt': 'No', 'Bar': 'No', 'Fri': 'No', 'Hun': 'Yes', 'Pat': 'Some',
'Price': '$$', 'Rain': 'Yes', 'Res': 'Yes', 'Type': 'Thai', 'Est': '0-10',
'GOAL': True},

{'Alt': 'No', 'Bar': 'Yes', 'Fri': 'Yes', 'Hun': 'No', 'Pat': 'Full',
'Price': '$', 'Rain': 'Yes', 'Res': 'No', 'Type': 'Burger', 'Est': '>60',
'GOAL': False},

{'Alt': 'Yes', 'Bar': 'Yes', 'Fri': 'Yes', 'Hun': 'Yes', 'Pat': 'Full',
'Price': '$$$', 'Rain': 'No', 'Res': 'Yes', 'Type': 'Italian', 'Est': '10-30',
'GOAL': False},

{'Alt': 'No', 'Bar': 'No', 'Fri': 'No', 'Hun': 'No', 'Pat': 'None',
'Price': '$', 'Rain': 'No', 'Res': 'No', 'Type': 'Thai', 'Est': '0-10',
'GOAL': False},

{'Alt': 'Yes', 'Bar': 'Yes', 'Fri': 'Yes', 'Hun': 'Yes', 'Pat': 'Full',
'Price': '$', 'Rain': 'No', 'Res': 'No', 'Type': 'Burger', 'Est': '30-60',
'GOAL': True}
]
4 changes: 4 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ def test_mode():
assert mode("absndkwoajfkalwpdlsdlfllalsflfdslgflal") == 'l'


def test_powerset():
assert powerset([1, 2, 3]) == [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]


def test_argminmax():
assert argmin([-2, 1], key=abs) == 1
assert argmax([-2, 1], key=abs) == -2
Expand Down
8 changes: 8 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import random
import math
import functools
from itertools import chain, combinations


# ______________________________________________________________________________
# Functions on Sequences and Iterables
Expand Down Expand Up @@ -66,6 +68,12 @@ def mode(data):
return item


def powerset(iterable):
"""powerset([1,2,3]) --> (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"""
s = list(iterable)
return list(chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))[1:]


# ______________________________________________________________________________
# argmin and argmax

Expand Down