Dictionary of Applied Machine Learning · hypothesis

hypothesis — Python demo

Numerical companion to the entry hypothesis: it recomputes what the entry states and prints one line per check

One block per paragraph of the entry (marked [P...]): each block verifies numerically what the corresponding statement asserts. Self-contained (numpy/matplotlib only), fixed seed.

Run it with python3 hypothesis.py, from any directory — it writes its output files into the current directory. Requires NumPy and Matplotlib only, and uses fixed seeds, so the printed numbers reproduce exactly. Download hypothesis.py

The script, block by block

One cell per block of the script: the code, and what that code printed when it last ran here

setup

"""
hypothesis.py — numerical companion to the glossary entry 'hypothesis'.

One block per paragraph of the entry (marked [P...]): each block verifies
numerically what the corresponding statement asserts. Self-contained
(numpy/matplotlib only), fixed seed.

Blocks
------
[P-def]   A hypothesis is a map h: X -> Y: a temperature predictor
          returns a prediction y-hat = h(x) for every feature value, and
          the same features always yield the same prediction.
[P-learn] ML searches a SUBSET of Y^X: for finite spaces |X| = 4,
          |Y| = 2 the set of all maps has |Y|^|X| = 16 elements, while
          the subset of threshold maps has only 5 — restricting the
          search is what makes learning with finite resources possible.
          ERM over the trainset returns the element of the subset with
          minimal empirical risk, achieving y ~ h(x).
[P-repr]  Different hypothesis spaces represent their maps differently:
          the same underlying map is represented as a polynomial
          coefficient vector, as an executable Python function, and as
          a decision-tree flow chart — all three agree on every input.

Outputs
-------
hypothesis.png : preview figure (checking only).

Data generated by pythondemos/hypothesis.py.
"""

import numpy as np
import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt

rng = np.random.default_rng(42)
report = []


def check(name, ok):
    report.append((name, bool(ok)))
    print(f"  [{'ok' if ok else 'FAIL'}] {name}")

P-def

A hypothesis is a map h: X -> Y: a temperature predictor returns a prediction y-hat = h(x) for every feature value, and the same features always yield the same prediction.

print("[P-def] a hypothesis maps features to predictions")
h = lambda x: 0.9 * x + 4.0                      # tomorrow ~ h(morning temp)
x_morning = np.array([8.0, 12.0, 15.0])
y_hat = h(x_morning)
check("h returns a prediction for every feature value",
      y_hat.shape == x_morning.shape)
check("h is a map: same features, same prediction",
      np.array_equal(h(x_morning), y_hat))
[P-def] a hypothesis maps features to predictions
  [ok] h returns a prediction for every feature value
  [ok] h is a map: same features, same prediction

P-learn

ML searches a SUBSET of Y^X: for finite spaces |X| = 4, |Y| = 2 the set of all maps has |Y|^|X| = 16 elements, while the subset of threshold maps has only 5 — restricting the search is what makes learning with finite resources possible. ERM over the trainset returns the element of the subset with minimal empirical risk, achieving y ~ h(x).

print("[P-learn] the search is restricted to a subset of Y^X")
X_space = [0, 1, 2, 3]                            # |X| = 4
Y_space = [0, 1]                                  # |Y| = 2
from itertools import product
all_maps = list(product(Y_space, repeat=len(X_space)))
thresh_maps = [tuple(int(x >= t) for x in X_space) for t in range(5)]
check("|Y^X| = |Y|^|X| = 16 maps", len(all_maps) == 2 ** 4 == 16)
check("the threshold hypothesis space is a strict subset (5 of 16)",
      len(set(thresh_maps)) == 5
      and set(thresh_maps) <= set(all_maps))
# ERM over the subset achieves y ~ h(x)
xs = rng.choice(X_space, 40)
ys = (xs >= 2).astype(int)                        # true threshold t = 2
emp = [np.mean([m[x] != y for x, y in zip(xs, ys)]) for m in thresh_maps]
h_hat = thresh_maps[int(np.argmin(emp))]
check("ERM over the subset finds the true threshold map",
      h_hat == tuple(int(x >= 2) for x in X_space))
check("the learned hypothesis achieves y = h(x) on the trainset",
      min(emp) == 0)
[P-learn] the search is restricted to a subset of Y^X
  [ok] |Y^X| = |Y|^|X| = 16 maps
  [ok] the threshold hypothesis space is a strict subset (5 of 16)
  [ok] ERM over the subset finds the true threshold map
  [ok] the learned hypothesis achieves y = h(x) on the trainset

P-repr

Different hypothesis spaces represent their maps differently: the same underlying map is represented as a polynomial coefficient vector, as an executable Python function, and as a decision-tree flow chart — all three agree on every input.

print("[P-repr] one map, three representations")
w_poly = np.array([1.0, -2.0, 0.5])               # h(x) = 1 - 2x + 0.5 x^2
h_poly = lambda x: sum(w * x**j for j, w in enumerate(w_poly))
def h_code(x):                                    # executable source code
    return 1.0 - 2.0 * x + 0.5 * x * x
def h_tree(x):                                    # flow chart of comparisons
    # piecewise-constant approximation on a grid: a depth-3 tree
    return h_poly(np.round(x * 8) / 8)
grid = np.linspace(-2, 2, 33)                     # tree grid points
check("polynomial and source-code representations agree everywhere",
      np.allclose(h_poly(grid), h_code(grid)))
check("the flow-chart (tree) representation agrees on its grid",
      np.allclose(h_tree(grid), h_poly(grid)))

# ------------------------------------------------------------ preview
fig, ax = plt.subplots(figsize=(4.8, 3.2))
xx = np.linspace(-2, 2, 200)
ax.plot(xx, h_poly(xx), label="polynomial / code")
ax.step(xx, h_tree(xx), where="mid", label="tree (piecewise)")
ax.legend(frameon=False)
ax.set_title("[P-repr] one hypothesis, several representations")
fig.tight_layout()
fig.savefig("hypothesis.png", dpi=110)
print(f"\n{sum(ok for _, ok in report)}/{len(report)} checks passed")
assert all(ok for _, ok in report)
[P-repr] one map, three representations
  [ok] polynomial and source-code representations agree everywhere
  [ok] the flow-chart (tree) representation agrees on its grid

8/8 checks passed
Preview figure produced by hypothesis.py
The preview figure the block P-repr writes when the script runs