162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
import sys
|
|
|
|
sys.path.insert(1, "../")
|
|
from utils.dataset4learners import *
|
|
from utils.utils import *
|
|
|
|
|
|
class LinearClassifier:
|
|
def learn(self, learning_rate, epochs):
|
|
raise NotImplementedError
|
|
|
|
def predict(self, x):
|
|
raise NotImplementedError
|
|
|
|
|
|
class PerceptionLinearLearner(LinearClassifier):
|
|
"""
|
|
Perception linear classifier: hard threshold
|
|
"""
|
|
|
|
def __init__(self, dataset, learning_rate=0.01, epochs=100):
|
|
self.idx_i = dataset.inputs
|
|
self.idx_t = dataset.target
|
|
self.examples = dataset.examples
|
|
self.num_examples = len(self.examples)
|
|
# initialize random weights
|
|
self.w = random_weights(
|
|
min_value=-0.5, max_value=0.5, num_weights=len(self.idx_i) + 1
|
|
)
|
|
# learning loop
|
|
self.learn(learning_rate, epochs)
|
|
|
|
def learn(self, learning_rate, epochs):
|
|
"""learning loop"""
|
|
|
|
def loss(example, w, idx_i, idx_t):
|
|
"""error: difference between estimation and true value"""
|
|
# Get input features and true target value
|
|
x = [example[i] for i in idx_i]
|
|
y = example[idx_t]
|
|
|
|
# Add bias term (1) to input features
|
|
x = [1] + x
|
|
|
|
# Calculate predicted value using dot product
|
|
prediction = np.dot(w, x)
|
|
|
|
# Return difference between prediction and true value
|
|
return prediction - y
|
|
|
|
def update(w, learning_rate, err, X_col, num_examples):
|
|
"""update weights"""
|
|
for i in range(len(w)):
|
|
w[i] = w[i] - learning_rate * (np.dot(err, X_col[i]) / num_examples)
|
|
|
|
def homogeneous(num_examples):
|
|
"""build homogeneous coordinates"""
|
|
# Initialize matrix with zeros
|
|
X = np.zeros((len(self.w), num_examples))
|
|
|
|
# Fill the matrix with features
|
|
for i, example in enumerate(self.examples):
|
|
# First row is bias terms (all 1s)
|
|
X[0][i] = 1
|
|
# Remaining rows are feature values
|
|
for j, idx in enumerate(self.idx_i, 1):
|
|
X[j][i] = example[idx]
|
|
|
|
return X
|
|
|
|
X_col = homogeneous(self.num_examples)
|
|
for epoch in range(epochs):
|
|
err = []
|
|
# pass over all examples
|
|
for example in self.examples:
|
|
err.append(loss(example, self.w, self.idx_i, self.idx_t))
|
|
|
|
# update weights
|
|
update(self.w, learning_rate, err, X_col, self.num_examples)
|
|
|
|
def predict(self, x):
|
|
"""make prediction"""
|
|
return int(np.dot(self.w, [1] + x))
|
|
|
|
|
|
class LogisticLinearLeaner(LinearClassifier):
|
|
def __init__(self, dataset, learning_rate=0.01, epochs=100):
|
|
self.idx_i = dataset.inputs
|
|
self.idx_t = dataset.target
|
|
self.examples = dataset.examples
|
|
self.num_examples = len(self.examples)
|
|
# initialize random weights
|
|
self.w = random_weights(
|
|
min_value=-0.5, max_value=0.5, num_weights=len(self.idx_i) + 1
|
|
)
|
|
# learning loop
|
|
self.learn(learning_rate, epochs)
|
|
|
|
def learn(self, learning_rate, epochs):
|
|
"""learning loop"""
|
|
|
|
def loss(example, w, idx_i, idx_t, h):
|
|
"""error: difference between estimation and true value"""
|
|
raise NotImplementedError
|
|
|
|
def update(w, learning_rate, err, h, X_col, num_examples):
|
|
"""update weights"""
|
|
for i in range(len(w)):
|
|
buffer = [x * y for x, y in zip(err, h)]
|
|
w[i] = w[i] - learning_rate * (np.dot(buffer, X_col[i]) / num_examples)
|
|
|
|
def homogeneous(num_examples):
|
|
"""build homogeneous coordinates"""
|
|
raise NotImplementedError
|
|
|
|
X_col = homogeneous(self.num_examples)
|
|
for epoch in range(epochs):
|
|
err = []
|
|
h = []
|
|
# pass over all examples
|
|
for example in self.examples:
|
|
err.append(loss(example, self.w, self.idx_i, self.idx_t, h))
|
|
|
|
# update weights
|
|
update(self.w, learning_rate, err, h, X_col, self.num_examples)
|
|
|
|
def predict(self, x):
|
|
"""make prediction"""
|
|
return int(np.dot(self.w, [1] + x))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
iris = DataSet(name="iris")
|
|
iris.classes_to_numbers()
|
|
|
|
tests = [
|
|
([5, 3, 1, 0.1], 0),
|
|
([5, 3.5, 1, 0], 0),
|
|
([6, 3, 4, 1.1], 1),
|
|
([6, 2, 3.5, 1], 1),
|
|
([7.5, 4, 6, 2], 2),
|
|
([7, 3, 6, 2.5], 2),
|
|
]
|
|
|
|
print(f"===================\nperceptron:")
|
|
perceptron = PerceptionLinearLearner(iris)
|
|
g = grade_learner(perceptron, tests)
|
|
print(f" learner grade: {g}")
|
|
# assert g > 1. / 2
|
|
e = err_ratio(perceptron, iris)
|
|
print(f" error ration: {e}")
|
|
# assert e < 0.4
|
|
|
|
print(f"===================\nlogistic:")
|
|
logisticer = LogisticLinearLeaner(iris)
|
|
g = grade_learner(logisticer, tests)
|
|
print(f" learner grade: {g}")
|
|
# assert g > 1. / 2
|
|
e = err_ratio(logisticer, iris)
|
|
print(f" error ration: {e}")
|
|
# assert e < 0.4
|