import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('seaborn-talk')
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
iris = load_iris()
iris.feature_names[:2], iris.target_names[:2]
idx = (iris.target == 0) | (iris.target == 1)
X = iris.data[idx, :2]
y = iris.target[idx]
fig, ax = plt.subplots(figsize=(12, 7))
ax.scatter(X[y == 0, 0], X[y == 0, 1], c='navy', label='Iris Setosa')
ax.scatter(X[y == 1, 0], X[y == 1, 1], c='crimson', label='Iris Versicolor')
ax.set(xlabel='Sepal Length', ylabel='Sepal Width')
ax.legend();
model = Perceptron()
model.fit(X, y)
gx = np.linspace(min(X[:, 0]), max(X[:, 0]), 128)
gy = np.linspace(min(X[:, 1]), max(X[:, 1]), 128)
gx, gy = np.meshgrid(gx, gy)
g_X = np.c_[gx.reshape(-1), gy.reshape(-1)]
g_y = model.predict(g_X)
fig, ax = plt.subplots(figsize=(12, 7))
ax.plot(g_X[g_y == 0, 0], g_X[g_y == 0, 1], '.', c='navy', alpha=.1)
ax.plot(g_X[g_y == 1, 0], g_X[g_y == 1, 1], '.', c='crimson', alpha=.1)
ax.scatter(X[y == 0, 0], X[y == 0, 1], c='navy', label='Iris Setosa')
ax.scatter(X[y == 1, 0], X[y == 1, 1], c='crimson', label='Iris Versicolor')
ax.set(xlabel='Sepal Length', ylabel='Sepal Width')
ax.legend();
model.coef_, model.intercept_
def hardlim(x):
return np.heaviside(x, 0)
g_y = model.coef_ @ g_X.T + model.intercept_
g_y = hardlim(g_y).reshape(-1)
fig, ax = plt.subplots(figsize=(12, 7))
ax.plot(g_X[g_y == 0, 0], g_X[g_y == 0, 1], '.', c='navy', alpha=.1)
ax.plot(g_X[g_y == 1, 0], g_X[g_y == 1, 1], '.', c='crimson', alpha=.1)
ax.scatter(X[y == 0, 0], X[y == 0, 1], c='navy', label='Iris Setosa')
ax.scatter(X[y == 1, 0], X[y == 1, 1], c='crimson', label='Iris Versicolor')
ax.set(xlabel='Sepal Length', ylabel='Sepal Width')
ax.legend();
class GenPerceptron:
def __init__(self, ch):
self.coef_ = np.array([[ch[0], ch[1]]]).copy()
self.intercept_ = np.array([ch[2]]).copy()
def predict(self, X):
y_hat = self.coef_ @ X.T + self.intercept_
return np.heaviside(y_hat, 0).reshape(-1)
def train_gen_perceptron(chs, n, X, y):
model = GenPerceptron(chs[n, :])
# we return the unchanged numbers
# but a different function could change them
ch = np.c_[model.coef_, model.intercept_]
y_hat = model.predict(X)
mse = ((y - y_hat)**2).mean()
return model, mse, ch
def gen_eval(chs, X, y, fun=None):
err = []
if fun is None:
fun = train_gen_perceptron
for n in range(chs.shape[0]):
model, mse, ch = fun(chs, n, X, y)
chs[n, :] = ch # update "unchanged" numbers
err.append(mse)
return err
def gen_best_k(chs, err, k):
idx = np.argpartition(err, k)[:k]
return chs[idx, :].copy()
def gen_reproduce(chs, npop=30, mutation=0.01):
pop_idx_f = np.random.choice(np.arange(chs.shape[0]), npop)
pop_idx_m = np.random.choice(np.arange(chs.shape[0]), npop)
pop_f = chs[pop_idx_f, :].copy()
pop_m = chs[pop_idx_m, :].copy()
cross = np.random.choice([False, True], pop_f.shape)
pop = np.where(cross, pop_f, pop_m)
mutation = np.random.rand(*pop_f.shape) < mutation
pop = np.where(mutation, pop*np.random.rand(), pop)
#print(pop.shape, chs.shape)
#pop = np.vstack((pop, chs))
return pop
def train(X, y, npop=30, k=3, n_iter=10, fun=None):
err, best = None, None
pop = np.random.normal(0, 7, (npop, 3))
for i in range(n_iter):
err = gen_eval(pop, X, y, fun=fun)
best = gen_best_k(pop, err, k)
pop = gen_reproduce(best, npop, mutation=0.1)
print('iter', i, 'err', min(err))
err_best = gen_eval(best, X, y)
return best, err_best
best, err = train(X, y, npop=60, n_iter=10)
one_best_idx = np.argsort(err)[0]
one_best = best[one_best_idx, :]
model = GenPerceptron(one_best.reshape(-1))
best, err
g_y = model.predict(g_X)
fig, ax = plt.subplots(figsize=(12, 7))
ax.plot(g_X[g_y == 0, 0], g_X[g_y == 0, 1], '.', c='navy', alpha=.1)
ax.plot(g_X[g_y == 1, 0], g_X[g_y == 1, 1], '.', c='crimson', alpha=.1)
ax.scatter(X[y == 0, 0], X[y == 0, 1], c='navy', label='Iris Setosa')
ax.scatter(X[y == 1, 0], X[y == 1, 1], c='crimson', label='Iris Versicolor')
ax.set(xlabel='Sepal Length', ylabel='Sepal Width')
ax.legend();
m2 = Perceptron()
m2.coef_ = np.array([[23.2, -38.7]])
m2.intercept_ = np.array([-5.])
m2.classes_ = np.array([0, 1])
m2.score(X, y)
import warnings
from sklearn.exceptions import ConvergenceWarning
# max_iter=1 makes the problem look harder
# but will give lots of warnings
warnings.filterwarnings('ignore', category=ConvergenceWarning)
def train_sklearn_perceptron(chs, n, X, y):
model = Perceptron(warm_start=True, max_iter=1)
model.coef_ = chs[n, :-1]
model.intercept_ = chs[n, -1]
model.fit(X, y)
ch = np.c_[model.coef_, model.intercept_]
y_hat = model.predict(X)
mse = ((y - y_hat)**2).mean()
return model, mse, ch
best, err = train(X, y, npop=10, n_iter=10, fun=train_sklearn_perceptron)
one_best_idx = np.argsort(err)[0]
one_best = best[one_best_idx, :]
model = GenPerceptron(one_best.reshape(-1))
best, err
g_y = model.predict(g_X)
fig, ax = plt.subplots(figsize=(12, 7))
ax.plot(g_X[g_y == 0, 0], g_X[g_y == 0, 1], '.', c='navy', alpha=.1)
ax.plot(g_X[g_y == 1, 0], g_X[g_y == 1, 1], '.', c='crimson', alpha=.1)
ax.scatter(X[y == 0, 0], X[y == 0, 1], c='navy', label='Iris Setosa')
ax.scatter(X[y == 1, 0], X[y == 1, 1], c='crimson', label='Iris Versicolor')
ax.set(xlabel='Sepal Length', ylabel='Sepal Width')
ax.legend();