From 685b17ac070e08069ea805cdcdd4353e3f58d432 Mon Sep 17 00:00:00 2001 From: Janith Wanniarachchi Date: Tue, 29 Oct 2019 01:09:44 +0530 Subject: [PATCH 1/3] :white_check_mark: added tests for Perceptron in Neural Networks --- neural_network/perceptron.py | 99 ++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/neural_network/perceptron.py b/neural_network/perceptron.py index 5feb8610a911..65ce752ff8df 100644 --- a/neural_network/perceptron.py +++ b/neural_network/perceptron.py @@ -10,20 +10,44 @@ """ import random - +import doctest class Perceptron: - def __init__(self, sample, exit, learn_rate=0.01, epoch_number=1000, bias=-1): + def __init__(self, sample, target, learning_rate=0.01, epoch_number=1000, bias=-1): + """ + Initializes a Perceptron network for oil analysis + :param sample: sample dataset of 3 parameters with shape [30,3] + :param target: target variable for classification with two possible states -1 or 1 + :param learning_rate: learning rate used in optimizing. + :param epoch_number: number of epochs to train network on. + :param bias: bias value for the network. + """ self.sample = sample - self.exit = exit - self.learn_rate = learn_rate + if len(self.sample) == 0: + raise AttributeError("Sample data can not be empty") + self.target = target + if len(self.target) == 0: + raise AttributeError("Target data can not be empty") + if len(self.sample) != len(self.target): + raise AttributeError("Sample data and Target data do not have matching lengths") + self.learning_rate = learning_rate self.epoch_number = epoch_number self.bias = bias self.number_sample = len(sample) - self.col_sample = len(sample[0]) + self.col_sample = len(sample[0]) # number of columns in dataset self.weight = [] def training(self): + """ + Trains perceptron for epochs <= given number of epochs + :return: None + >>> data = [[2.0149, 0.6192, 10.9263]] + >>> targets = [-1] + >>> perceptron = Perceptron(data,targets) + >>> perceptron.training() # doctest:+ELLIPSIS + ('\\nEpoch:\\n', ...) + ... + """ for sample in self.sample: sample.insert(0, self.bias) @@ -35,31 +59,45 @@ def training(self): epoch_count = 0 while True: - erro = False + has_misclassified = False for i in range(self.number_sample): u = 0 for j in range(self.col_sample + 1): u = u + self.weight[j] * self.sample[i][j] y = self.sign(u) - if y != self.exit[i]: - + if y != self.target[i]: for j in range(self.col_sample + 1): - self.weight[j] = ( - self.weight[j] - + self.learn_rate * (self.exit[i] - y) * self.sample[i][j] + self.weight[j] + + self.learning_rate * (self.target[i] - y) * self.sample[i][j] ) - erro = True + has_misclassified = True # print('Epoch: \n',epoch_count) epoch_count = epoch_count + 1 # if you want controle the epoch or just by erro - if erro == False: + if not has_misclassified: print(("\nEpoch:\n", epoch_count)) print("------------------------\n") # if epoch_count > self.epoch_number or not erro: break def sort(self, sample): + """ + :param sample: example row to classify as P1 or P2 + :return: None + >>> data = [[2.0149, 0.6192, 10.9263]] + >>> targets = [-1] + >>> perceptron = Perceptron(data,targets) + >>> perceptron.training() # doctest:+ELLIPSIS + ('\\nEpoch:\\n', ...) + ... + >>> perceptron.sort([-0.6508, 0.1097, 4.0009]) # doctest:+ELLIPSIS + ('Sample: ', ...) + classification: P1 + + """ + if len(self.sample) == 0: + raise AttributeError("Sample data can not be empty") sample.insert(0, self.bias) u = 0 for i in range(self.col_sample + 1): @@ -75,6 +113,20 @@ def sort(self, sample): print("classification: P2") def sign(self, u): + """ + threshold function for classification + :param u: input number + :return: 1 if the input is greater than 0, otherwise -1 + >>> data = [[0],[-0.5],[0.5]] + >>> targets = [1,-1,1] + >>> perceptron = Perceptron(data,targets) + >>> perceptron.sign(0) + 1 + >>> perceptron.sign(-0.5) + -1 + >>> perceptron.sign(0.5) + 1 + """ return 1 if u >= 0 else -1 @@ -144,15 +196,22 @@ def sign(self, u): 1, ] -network = Perceptron( - sample=samples, exit=exit, learn_rate=0.01, epoch_number=1000, bias=-1 -) - -network.training() if __name__ == "__main__": + doctest.testmod() + + network = Perceptron( + sample=samples, target=exit, learning_rate=0.01, epoch_number=1000, bias=-1 + ) + network.training() + print("Finished training perceptron") + print("Enter values to predict or q to exit") while True: sample = [] - for i in range(3): - sample.insert(i, float(input("value: "))) + for i in range(len(samples[0])): + observation = input("value: ").strip() + if observation == "q": + break + observation = float(observation) + sample.insert(i, observation) network.sort(sample) From 180ef98a496713926ddb091e1568e2188f0b110c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 29 Oct 2019 03:17:08 +0100 Subject: [PATCH 2/3] Space --- neural_network/perceptron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neural_network/perceptron.py b/neural_network/perceptron.py index 65ce752ff8df..cca49241ec54 100644 --- a/neural_network/perceptron.py +++ b/neural_network/perceptron.py @@ -44,7 +44,7 @@ def training(self): >>> data = [[2.0149, 0.6192, 10.9263]] >>> targets = [-1] >>> perceptron = Perceptron(data,targets) - >>> perceptron.training() # doctest:+ELLIPSIS + >>> perceptron.training() # doctest: +ELLIPSIS ('\\nEpoch:\\n', ...) ... """ From 1ad9be5de4b960cb86d1a468c645bbeea5e45f58 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 29 Oct 2019 11:53:09 +0100 Subject: [PATCH 3/3] Format code with psf/black --- neural_network/perceptron.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/neural_network/perceptron.py b/neural_network/perceptron.py index cca49241ec54..d64c0a5c4341 100644 --- a/neural_network/perceptron.py +++ b/neural_network/perceptron.py @@ -1,23 +1,21 @@ """ - Perceptron w = w + N * (d(k) - y) * x(k) - Using perceptron network for oil analysis, - with Measuring of 3 parameters that represent chemical characteristics we can classify the oil, in p1 or p2 + Using perceptron network for oil analysis, with Measuring of 3 parameters + that represent chemical characteristics we can classify the oil, in p1 or p2 p1 = -1 p2 = 1 - """ import random -import doctest + class Perceptron: def __init__(self, sample, target, learning_rate=0.01, epoch_number=1000, bias=-1): """ Initializes a Perceptron network for oil analysis :param sample: sample dataset of 3 parameters with shape [30,3] - :param target: target variable for classification with two possible states -1 or 1 + :param target: variable for classification with two possible states -1 or 1 :param learning_rate: learning rate used in optimizing. :param epoch_number: number of epochs to train network on. :param bias: bias value for the network. @@ -29,7 +27,9 @@ def __init__(self, sample, target, learning_rate=0.01, epoch_number=1000, bias=- if len(self.target) == 0: raise AttributeError("Target data can not be empty") if len(self.sample) != len(self.target): - raise AttributeError("Sample data and Target data do not have matching lengths") + raise AttributeError( + "Sample data and Target data do not have matching lengths" + ) self.learning_rate = learning_rate self.epoch_number = epoch_number self.bias = bias @@ -37,7 +37,7 @@ def __init__(self, sample, target, learning_rate=0.01, epoch_number=1000, bias=- self.col_sample = len(sample[0]) # number of columns in dataset self.weight = [] - def training(self): + def training(self) -> None: """ Trains perceptron for epochs <= given number of epochs :return: None @@ -68,8 +68,10 @@ def training(self): if y != self.target[i]: for j in range(self.col_sample + 1): self.weight[j] = ( - self.weight[j] - + self.learning_rate * (self.target[i] - y) * self.sample[i][j] + self.weight[j] + + self.learning_rate + * (self.target[i] - y) + * self.sample[i][j] ) has_misclassified = True # print('Epoch: \n',epoch_count) @@ -81,7 +83,7 @@ def training(self): # if epoch_count > self.epoch_number or not erro: break - def sort(self, sample): + def sort(self, sample) -> None: """ :param sample: example row to classify as P1 or P2 :return: None @@ -91,7 +93,7 @@ def sort(self, sample): >>> perceptron.training() # doctest:+ELLIPSIS ('\\nEpoch:\\n', ...) ... - >>> perceptron.sort([-0.6508, 0.1097, 4.0009]) # doctest:+ELLIPSIS + >>> perceptron.sort([-0.6508, 0.1097, 4.0009]) # doctest: +ELLIPSIS ('Sample: ', ...) classification: P1 @@ -112,7 +114,7 @@ def sort(self, sample): print(("Sample: ", sample)) print("classification: P2") - def sign(self, u): + def sign(self, u: float) -> int: """ threshold function for classification :param u: input number @@ -198,6 +200,8 @@ def sign(self, u): if __name__ == "__main__": + import doctest + doctest.testmod() network = Perceptron(