From 487564d9dfbbb56d482a2298af142449ed9c10f2 Mon Sep 17 00:00:00 2001 From: Savinu Aththanayake <107975408+SaviNimz@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:37:55 +0530 Subject: [PATCH 1/5] add: Perceptron algorithm implementation --- machine_learning/perceptron.py | 130 +++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 machine_learning/perceptron.py diff --git a/machine_learning/perceptron.py b/machine_learning/perceptron.py new file mode 100644 index 000000000000..e0f043441a4c --- /dev/null +++ b/machine_learning/perceptron.py @@ -0,0 +1,130 @@ +""" +Perceptron Algorithm Implementation +""" +import numpy as np + + +class Perceptron: + """ + Perceptron Classifier + + Parameters: + ----------- + learning_rate : float + Learning rate (between 0.0 and 1.0) + epochs : int + Passes over the training dataset. + + Attributes: + ----------- + weights : numpy.ndarray + Weights after fitting. + bias : float + Bias unit after fitting. + errors : list + Number of misclassifications (updates) in each epoch. + + Examples: + --------- + >>> import numpy as np + >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> y = np.array([0, 0, 0, 1]) + >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) + >>> _ = perceptron.fit(X, y) + >>> perceptron.predict(X).tolist() + [0, 0, 0, 1] + """ + + def __init__(self, learning_rate: float = 0.01, epochs: int = 1000) -> None: + self.learning_rate = learning_rate + self.epochs = epochs + self.weights = np.zeros(1) + self.bias = 0.0 + self.errors = [] + + def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron": + """ + Fit training data. + + Parameters: + ----------- + X : shape = [n_samples, n_features] + Training vectors, where n_samples is the number of samples + and n_features is the number of features. + y : shape = [n_samples] + Target values. + + Returns: + -------- + self : object + + Examples: + --------- + >>> import numpy as np + >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> y = np.array([0, 0, 0, 1]) + >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) + >>> _ = perceptron.fit(X, y) + """ + n_samples, n_features = X.shape + self.weights = np.zeros(n_features) + self.bias = 0.0 + self.errors = [] + + for _ in range(self.epochs): + errors = 0 + for xi, target in zip(X, y): + # Calculate update + update = self.learning_rate * (target - self.predict(xi)) + self.weights += update * xi + self.bias += update + errors += int(update != 0.0) + self.errors.append(errors) + return self + + def predict(self, X: np.ndarray) -> np.ndarray: + """ + Return class label after unit step + + Examples: + --------- + >>> import numpy as np + >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> y = np.array([0, 0, 0, 1]) + >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) + >>> _ = perceptron.fit(X, y) + >>> perceptron.predict(X).tolist() + [0, 0, 0, 1] + """ + linear_output = np.dot(X, self.weights) + self.bias + return self.activation_function(linear_output) + + def activation_function(self, x: np.ndarray) -> np.ndarray: + """ + Step activation function: returns 1 if x >= 0, else 0 + + Examples: + --------- + >>> import numpy as np + >>> perceptron = Perceptron() + >>> perceptron.activation_function(np.array([0.5, -0.5, 0])).tolist() + [1, 0, 1] + """ + return np.where(x >= 0, 1, 0) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + # Example usage + X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + y = np.array([0, 0, 0, 1]) # AND gate + + perceptron = Perceptron(learning_rate=0.1, epochs=10) + perceptron.fit(X, y) + + print("Weights:", perceptron.weights) + print("Bias:", perceptron.bias) + print("Predictions:", perceptron.predict(X)) \ No newline at end of file From cba3b025f7ec1ad2269a4477ae4b30be3c8b7271 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 11:10:15 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- machine_learning/perceptron.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/machine_learning/perceptron.py b/machine_learning/perceptron.py index e0f043441a4c..3eeff75a2459 100644 --- a/machine_learning/perceptron.py +++ b/machine_learning/perceptron.py @@ -1,6 +1,7 @@ """ Perceptron Algorithm Implementation """ + import numpy as np @@ -127,4 +128,4 @@ def activation_function(self, x: np.ndarray) -> np.ndarray: print("Weights:", perceptron.weights) print("Bias:", perceptron.bias) - print("Predictions:", perceptron.predict(X)) \ No newline at end of file + print("Predictions:", perceptron.predict(X)) From 723908ef2413748d5ea709d71022726a6eadada5 Mon Sep 17 00:00:00 2001 From: Savinu Aththanayake <107975408+SaviNimz@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:46:03 +0530 Subject: [PATCH 3/5] fixed the linting errors --- machine_learning/perceptron.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/machine_learning/perceptron.py b/machine_learning/perceptron.py index 3eeff75a2459..d7b4f0d350e2 100644 --- a/machine_learning/perceptron.py +++ b/machine_learning/perceptron.py @@ -28,11 +28,11 @@ class Perceptron: Examples: --------- >>> import numpy as np - >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> samples = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) >>> y = np.array([0, 0, 0, 1]) >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) - >>> _ = perceptron.fit(X, y) - >>> perceptron.predict(X).tolist() + >>> _ = perceptron.fit(samples, y) + >>> perceptron.predict(samples).tolist() [0, 0, 0, 1] """ @@ -43,13 +43,13 @@ def __init__(self, learning_rate: float = 0.01, epochs: int = 1000) -> None: self.bias = 0.0 self.errors = [] - def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron": + def fit(self, samples: np.ndarray, y: np.ndarray) -> "Perceptron": """ Fit training data. Parameters: ----------- - X : shape = [n_samples, n_features] + samples : shape = [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : shape = [n_samples] @@ -62,19 +62,19 @@ def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron": Examples: --------- >>> import numpy as np - >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> samples = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) >>> y = np.array([0, 0, 0, 1]) >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) - >>> _ = perceptron.fit(X, y) + >>> _ = perceptron.fit(samples, y) """ - n_samples, n_features = X.shape + _, n_features = samples.shape self.weights = np.zeros(n_features) self.bias = 0.0 self.errors = [] for _ in range(self.epochs): errors = 0 - for xi, target in zip(X, y): + for xi, target in zip(samples, y): # Calculate update update = self.learning_rate * (target - self.predict(xi)) self.weights += update * xi @@ -83,21 +83,21 @@ def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron": self.errors.append(errors) return self - def predict(self, X: np.ndarray) -> np.ndarray: + def predict(self, samples: np.ndarray) -> np.ndarray: """ Return class label after unit step Examples: --------- >>> import numpy as np - >>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + >>> samples = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) >>> y = np.array([0, 0, 0, 1]) >>> perceptron = Perceptron(learning_rate=0.1, epochs=10) - >>> _ = perceptron.fit(X, y) - >>> perceptron.predict(X).tolist() + >>> _ = perceptron.fit(samples, y) + >>> perceptron.predict(samples).tolist() [0, 0, 0, 1] """ - linear_output = np.dot(X, self.weights) + self.bias + linear_output = np.dot(samples, self.weights) + self.bias return self.activation_function(linear_output) def activation_function(self, x: np.ndarray) -> np.ndarray: @@ -120,12 +120,12 @@ def activation_function(self, x: np.ndarray) -> np.ndarray: doctest.testmod() # Example usage - X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) + samples = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) y = np.array([0, 0, 0, 1]) # AND gate perceptron = Perceptron(learning_rate=0.1, epochs=10) - perceptron.fit(X, y) + perceptron.fit(samples, y) print("Weights:", perceptron.weights) print("Bias:", perceptron.bias) - print("Predictions:", perceptron.predict(X)) + print("Predictions:", perceptron.predict(samples)) From fe4b10efe0331ebca591b8d910b70a88b04bb9b5 Mon Sep 17 00:00:00 2001 From: Savinu Aththanayake <107975408+SaviNimz@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:48:47 +0530 Subject: [PATCH 4/5] add: Perceptron algorithm in machine_learning --- machine_learning/perceptron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine_learning/perceptron.py b/machine_learning/perceptron.py index d7b4f0d350e2..c0a0600f8faf 100644 --- a/machine_learning/perceptron.py +++ b/machine_learning/perceptron.py @@ -41,7 +41,7 @@ def __init__(self, learning_rate: float = 0.01, epochs: int = 1000) -> None: self.epochs = epochs self.weights = np.zeros(1) self.bias = 0.0 - self.errors = [] + self.errors: list[int] = [] def fit(self, samples: np.ndarray, y: np.ndarray) -> "Perceptron": """ From e73ffce126664273fe85ea10b6b0e2127232a31b Mon Sep 17 00:00:00 2001 From: Savinu Aththanayake <107975408+SaviNimz@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:28:27 +0530 Subject: [PATCH 5/5] added readable variable names --- machine_learning/perceptron.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/machine_learning/perceptron.py b/machine_learning/perceptron.py index c0a0600f8faf..c763b7f4c9f0 100644 --- a/machine_learning/perceptron.py +++ b/machine_learning/perceptron.py @@ -43,7 +43,7 @@ def __init__(self, learning_rate: float = 0.01, epochs: int = 1000) -> None: self.bias = 0.0 self.errors: list[int] = [] - def fit(self, samples: np.ndarray, y: np.ndarray) -> "Perceptron": + def fit(self, samples: np.ndarray, targets: np.ndarray) -> "Perceptron": """ Fit training data. @@ -52,7 +52,7 @@ def fit(self, samples: np.ndarray, y: np.ndarray) -> "Perceptron": samples : shape = [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. - y : shape = [n_samples] + targets : shape = [n_samples] Target values. Returns: @@ -74,7 +74,7 @@ def fit(self, samples: np.ndarray, y: np.ndarray) -> "Perceptron": for _ in range(self.epochs): errors = 0 - for xi, target in zip(samples, y): + for xi, target in zip(samples, targets): # Calculate update update = self.learning_rate * (target - self.predict(xi)) self.weights += update * xi @@ -100,9 +100,9 @@ def predict(self, samples: np.ndarray) -> np.ndarray: linear_output = np.dot(samples, self.weights) + self.bias return self.activation_function(linear_output) - def activation_function(self, x: np.ndarray) -> np.ndarray: + def activation_function(self, values: np.ndarray) -> np.ndarray: """ - Step activation function: returns 1 if x >= 0, else 0 + Step activation function: returns 1 if values >= 0, else 0 Examples: --------- @@ -111,7 +111,7 @@ def activation_function(self, x: np.ndarray) -> np.ndarray: >>> perceptron.activation_function(np.array([0.5, -0.5, 0])).tolist() [1, 0, 1] """ - return np.where(x >= 0, 1, 0) + return np.where(values >= 0, 1, 0) if __name__ == "__main__":