6
\$\begingroup\$

This is my finished perceptron written in python. Is there anything that I can improve/suggestions? I'm a beginner with python so anything would be helpful!

import random

class Train:    
    def __init__(self):
        self.train = [[10,5,3,False],[3,2,16,True],[4,15,11,False]]
        #Initialize training set
        self.fired = False #activate when over thresh 
        self.threshold = 1.0 
        self.x1 = 1 #weights
        self.x2 = -1 
        self.x3 = 0.5
        self.learningRate = 0.1 #not used
    #true if fired state == answers in training set
        self.correct = [False,False,False] 
        self.desire ='' #input value

    def trainIt(self):  
        #while one or more of the answers are wrong
        while self.correct[1] == False or self.correct[0] == False or self.correct[2] == False:
            for i in range(3):
                #Perceptron formula
                if self.train[i][0]*self.x1+self.train[i][1]*self.x2+self.train[i][2]*self.x3 < self.threshold:
                    #under thresh, dont fire
                    self.fired = False
                else:
                    #fire perceptron
                    self.fired = True   

                if self.fired == self.train[i][3]:
                    #if fired state is correct, log it
                    self.correct[i] = True
                else:
                    #my subsitution for the learning rate
                    self.x1 += random.randrange(-1,2)
                    self.x2 += random.randrange(-1,2)
                    self.x3 += random.randrange(-1,2)
            #prints weights
            print("W1: "+str(self.x1))
            print("W2: "+str(self.x2))
            print("W3: "+str(self.x3))

        self.Test()

    def Test(self):
        #random point to test perceptron!
        self.test = [3,20,8]
        #reset some values
        self.fired = False
        self.correct = [False,False,False]

        #fire if over threshold
        if self.test[0]*self.x1+self.test[1]*self.x2 < self.threshold:
            self.fired = False
        else:
            self.fired = True

        print("Test Result: "+str(self.fired))
        self.desire = input("Was this your desired result? ")
        #print the test result and ask the user if the perceptron was right. This would be useful in filtering spam
        if self.desire == 'N':
            #if it was not right, continue training
            print("Okay! Training...")
            self.trainIt()

#initialize object and call methods         
ptron = Train()
ptron.trainIt()
ptron.Test()
\$\endgroup\$
  • \$\begingroup\$ Generally you don't put a capital letter for a function name so I would probably modify def Test(self): to def test(self): \$\endgroup\$ – 13ros27 Dec 16 '17 at 15:15
  • \$\begingroup\$ Some python 'standards': space after #, funcion or variable name: function_name, class name: ClassName. You can search for more. \$\endgroup\$ – Raphael Nov 13 '19 at 19:51
4
\$\begingroup\$

Here's your code slightly changed. Please check python conventions, PEP8, etc. Also, learn how to name variables, functions, and classes. Furthermore, learn how to comment. Usually, you comment on the class and the method, the code inside them should be clear enough, you don't need to pollute with comments if you have good variable descriptions, for example.

If you need to comment inside methods, try to comment blocks of code and not almost every line with useless comments (obvious ones) like "set var to True".

One tip I can do to you is to look at opensource codes and check the code style. You will see they differ a little, and some even ignore Python conventions. Anyway, stick to the ones that try to follow PEP8.

Code with general comments

import random

# space after comments
# comment in the same line? double space  # comment
# CONSTANT = 1
# variable_name = function_name: Function and variable names should be lowercase, 
# with words separated by underscores as necessary to improve readability
# ClassName
# method_name.py
# 'if var == True:' >>> more pythonic is simply:
# 'if var:' or 'if not var:' for False condition

# comment me
class Train:    
    def __init__(self):
        self.train = [[10,5,3,False],[3,2,16,True],[4,15,11,False]]
        # Initialize training set
        self.fired = False  # activate when over thresh (threshold: don't be lazy :-) )
        self.threshold = 1.0 
        self.x1 = 1  # weights
        self.x2 = -1 
        self.x3 = 0.5
        self.learningRate = 0.1  # not used
        # true if fired state == answers in training set
        self.correct = [False,False,False] 
        self.desire = ''  # input value

    # comment me    
    def train_it(self):
        ''' 
        You can comment
        like this
        too
        ''' 
        # while one or more of the answers are wrong
        # while self.correct[1] == False or self.correct[0] == False or self.correct[2] == False:
        # use parenthesis to divide the logic, is easier to read and to understand
        while (not self.correct[1]) or (not self.correct[0]) or (not self.correct[2]):
            for i in range(3):
                # Perceptron formula
                # fire perceptron
                # You don't need the else in this case. However, leave it if it's more clear to you
                self.fired = True
                if (self.train[i][0]*self.x1+self.train[i][1]*self.x2+self.train[i][2]*self.x3 < self.threshold):
                # under threshold, dont fire
                    self.fired = False  

                if self.fired == self.train[i][3]:
                    # if fired state is correct, log it
                    self.correct[i] = True
                else:
                    # my subsitution for the learning rate
                    self.x1 += random.randrange(-1,2)
                    self.x2 += random.randrange(-1,2)
                    self.x3 += random.randrange(-1,2)

            # prints weights
            # using fstrings
            # prints should be in another method, learn about callback functions
            print(f"W1: {self.x1}")
            print(f"W2: {self.x2}")
            print(f"W3: {self.x3}")

        self.test()

    # what does this method do?             
    def test(self):
        # random point to test perceptron!
        self.test_lst = [3,20,8]
        # reset some values - useless comment!?
        self.fired = False
        self.correct = [False,False,False]

        # fire if over threshold
        self.fired = True
        if self.test_lst[0]*self.x1+self.test_lst[1]*self.x2 < self.threshold:
            self.fired = False

        print(f"Test Result: {self.fired}")
        self.desire = input("Was this your desired result? 'N' for NO. Anything else for YES: ")
        # print the test result and ask the user if the perceptron was right. 
        # This would be useful in filtering spam
        # You need to check if the input is 'N' or 'Y'
        if self.desire.lower() == 'n':
            #if it was not right, continue training
            print("Okay! Training...")
            self.train_it()


# main function called when module executed directly
# ex. python3 this_module.py
def main():
    # initialize object and call methods - this type of comment is useless in my opinion.       
        ptron = Train()
        ptron.train_it()
        ptron.test()

# If you execute this_module.py, main() will be called
# If you import this_module, you need to initialize the object Train() 
# in the module that is calling this one: 
# import this_module or from this_module import Train
# then just use Train: ptron = Train() etc.
if __name__ == '__main__':
    main()

Code without general comments

import random

# Comment me
class Train:    
    def __init__(self):
        self.train = [[10, 5, 3, False], 
                      [3, 2, 16, True], 
                      [4, 15, 11, False]]
        # Initialize training set
        self.fired = False
        self.threshold = 1.0 
        self.weight = 1
        self.x2 = -1 
        self.x3 = 0.5
        self.correct = [False, False, False] 
        self.input_val = ''

    # Comment me    
    def train_it(self):
        # while one or more of the answers are wrong
        while not all(self.correct):
            # Perceptron formula
            for i in range(3):
                self.fired = True  # fire perceptron

                # under threshold, dont fire
                if ((self.train[i][0] * self.weight)
                   + (self.train[i][1] * self.x2)
                   + (self.train[i][2] * self.x3) < self.threshold):
                    self.fired = False  

                # if fired state is correct, log it
                if self.fired == self.train[i][3]:
                    self.correct[i] = True
                else:
                    # my subsitution for the learning rate
                    self.weight += random.randrange(-1,2)
                    self.x2 += random.randrange(-1,2)
                    self.x3 += random.randrange(-1,2)

            print(f"W1: {self.weight}")
            print(f"W2: {self.x2}")
            print(f"W3: {self.x3}")

        self.test()

    # Comment me            
    def test(self):
        self.test_lst = [3, 20, 8]  # random point to test perceptron!
        self.fired = False
        self.correct = [False, False, False]

        self.fired = True
        # under threshold, dont fire
        if ((self.test_lst[0]*self.weight)
           + (self.test_lst[1]*self.x2) < self.threshold):
            self.fired = False

        print(f"Test Result: {self.fired}")

        input_str = "Was this your desired result? "
        input_str += "'N' for NO. Anything else for YES: "
        self.input_val = input(input_str)

        # print the test result and ask the user if the perceptron was right. 
        # this would be useful in filtering spam
        if self.input_val.lower() == 'n':
            print("Okay! Training...")  # if it was not right, continue training
            self.train_it()


# main function called when module executed directly
# ex. python3 this_module.py
def main(): 
        ptron = Train()
        ptron.train_it()
        ptron.test()


if __name__ == '__main__':
    main()

PS: while self.correct[1] == False or self.correct[0] == False or self.correct[2] == False: was replaced to while not all(self.correct):

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hello Raphael, this is a pretty good first answer, good job! If I might add, I think it'd be easier to see what improvements you propose if they weren't embedded as comments inside the code. You're free to follow this tip or not, either way I think you did great. \$\endgroup\$ – IEatBagels Nov 13 '19 at 21:03
  • \$\begingroup\$ Thanks for all the activity! In the past two years I have learned about torch and tensorflow, which make this stuff a lot easier, but it is awesome to see a perceptron built from scratch, the right way. I appreciate your answer a lot. \$\endgroup\$ – iamPres Nov 14 '19 at 0:05
  • 1
    \$\begingroup\$ @IEatBagels Thanks, I will follow your tip and post the clean code this evening. iamPres You're welcome. I'm a python beginner too, so these kinds of questions are great for me as they serve as exercises. \$\endgroup\$ – Raphael Nov 14 '19 at 10:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.