John Shovic

John Shovic, PhD, is a computer science faculty member at the University of Idaho specializing in robotics and artificial intelligence.

Articles From John Shovic

10 results
10 results
The Raspberry Pi: The Perfect PC Platform for Python

Article / Updated 07-10-2023

Before you can get going here, make sure you have your Raspberry Pi computer set up and running on your monitor, keyboard, and mouse. If not, go do that now The next few paragraphs are going to be lots more fun with a computer to work with! The Raspberry Pi is the perfect platform to do physical computing with Python because it has a multiscreen environment, lots of RAM and storage to play with and all the tools to build fun projects. A huge and powerful feature of the Raspberry Pi is the row of GPIO (general purpose input-output) pins along the top of the Raspberry Pi. It is a 40-pin header into which you can plug a large number of sensors and controllers to do amazing things to expand your Raspberry Pi. GPIO pins on the Raspberry Pi GPIO pins can be designated (using Python software) as input or output pins and used for many different purposes. There are two 5V power pins, two 3.3V power pins and a number of ground pins that have fixed uses. An GPIO pin output pin “outputs” a 1 or a 0 from the computer to the pin. Basically, A “1” is 3.3V and a “0” is 0V. You can think of them just as 1s and 0s. GPIO Python libraries There are a number of GPIO Python libraries that are usable for building projects. A good one to use is the gpiozero library that is installed on all Raspberry Pi desktop software releases. Check out the library documentation and installation instructions (if needed). Now let’s jump into the “Hello World” physical computing project with our Raspberry Pi. The hardware for “Hello World” on the Raspberry Pi To do this project, you’ll need some hardware. Because these instructions involve using Grove connectors, let's get the two pieces of Grove hardware that you need for this project: Pi2Grover: This converts the Raspberry Pi GPIO pin header to Grove connectors (ease of use and can’t reverse the power pins!). You can buy this either at shop.switchdoc.com or at Amazon.com. You can get $5.00 off the Pi2Grover board at shop.switchdoc.com by using the discount code PI2DUMMIES at checkout. Grove blue LED: A Grove blue LED module including Grove cable. You can buy this on shop.switchdoc.com or on amazon.com. How to assemble the Raspberry Pi’s hardware For a number of you readers, this will be the first time you have ever assembled a physical computer-based product. because of this, we’ll give you the step-by-step process: Identify the Pi2Grover board. Making sure you align the pins correctly gently press the Pi2Grover Board (Part A) onto the 40 pin GPIO connector on the Raspberry Pi. Gently finish pushing the Pi2Grover (Part A) onto the Raspberry Pi GPIO pins, making sure the pins are aligned. There will be no pins showing on either end and make sure no pins on the Raspberry Pi are bent. Plug one end of the Grove cable into the Grove blue LED board. If your blue LED is not plugged into the Grove blue LED board, then plug in the LED with the flat side aligned with the flat side of the outline on the board. Plug the other end of the Grove cable into the slot marked D12/D13 on the Pi2Grover board.You are now finished assembling the hardware. Now it’s time for the Python software.

View Article
What is a Python Module?

Article / Updated 01-25-2022

For all the hoopla about Python modules, a module is actually a pretty simple thing. In fact, a Python module is just a file with a .py extension that contains Python code. That’s it. So any time you write Python code and save it in a .py file, you’ve basically created a module. That’s not to say you always have to use that code as a module. It can certainly be treated as a standalone app. But if you wanted to create your own Python module, with just code that you need often in your own work, you could certainly do so. A Python module is also just a file with a .py filename extension. The name of the module is the same as the filename (without the .py). Like any .py file, the module contains Python code. As a working example, let’s suppose you want to have three functions to simplify formatting dates and currency values. You can make up any name you like for each function. For our working example, we’ll use these three names: to_date(<em>any_str</em>): Lets you pass in any string (any_str) date in mm/dd/yy or mm/dd/yyyy format and sends back a Python datetime.date that you can use for date calculations. mdy(<em>any_date</em>): Lets you pass in any Python date or datetime, and returns a string date formatted in mm/dd/yyyy format for display on the screen. to_curr(<em>any_num, len</em>): Lets you pass in any Python float or integer number and returns a string with a leading dollar sign, commas in thousands places, and two digits for the pennies. The len is an optional number for length. If provided, the return value will be padded on the left with spaces to match the length specified So here is all the code for that: # Contains custom functions for dates and currency values. import datetime as dt def to_date(any_str): """ Convert mm/dd/yy or mm/dd/yyyy string to datetime.date, or None if invalid date. """ try: if len(any_str) == 10: the_date = dt.datetime.strptime(any_str,'%m/%d/%Y').date() else: the_date = dt.datetime.strptime(any_str,'%m/%d/%y').date() except (ValueError, TypeError): the_date = None return the_date def mdy(any_date): """ Returns a string date in mm/dd/yyyy format. Pass in Python date or string date in mm/dd/yyyy format """ if type(any_date) == str: any_date = to_date(anydate) # Make sure its a dateime being forwarded if isinstance(any_date,dt.date): s_date = f"{any_date:'%m/%d/%Y'}" else: s_date = "Invalid date" return s_date def to_curr(anynum, len=0): """ Returns a number as a string with $ and commas. Length is optional """ s = "Invalid amount" try: x = float(anynum) except ValueError: x= None if isinstance(x,float): s = '$' + f"{x:,.2f}" if len > 0: s=s.rjust(len) return s You can create the same file yourself and name it myfunctions.py if you want to follow along. Notice that the file contains only functions. So if you run it, it won't do anything on the screen because there is no code in there that calls any of those functions. To use those functions in any Python app or program you write, first make sure you copy that myfunc.py file to the same folder as the rest of the Python code that you’re writing. Then, when you create a new page, you can import myfunc as a module just as you would any other module created by somebody else. Just use import myfunc You will have to use the module name in front of any of the functions that you call from that module. So if you want to make the code a little more readable, you can use this instead: import myfunc as my With that as your opening line, you can refer to any function in your custom Python module with my. as the prefix. For example, my.to_date() to call the to_date function. Here is a page that imports the module and then tests out all three functions using that my syntax: # Import all the code from myfunc.py as my. import myfunc as my # Need dates in this code from datetime import datetime as dt # Some simple test data. string_date="12/31/2019" # Convert string date to datetime.date print(my.to_date(string_date)) today = dt.today() # Show today's date in mm/dd/yyyy format. print(my.mdy(today)) dollar_amt=12345.678 # Show this big number in currency format. print(my.to_curr(dollar_amt)) You can also skip using the prefix if you import items by name. In this case, that means you could call to_date() and mdy() and to_curr() without using the my. prefix. The first line of code would need to be from myfunc import to_date, mdy, to_curr The rest of the code would be the same as in the previous example, except you can leave off the my. prefixes as in the following code: # Import all the code from myfunc.py by name. from myfunc import to_date, mdy, to_curr # Need dates in this code from datetime import datetime as dt # Some simple test data. string_date="12/31/2019" # Convert string date to datetime.date print(to_date(string_date)) today = dt.today() # Show today's date in mm/dd/yyyy format. print(mdy(today)) dollar_amt=12345.678 # Show this big number in currency format. print(to_curr(dollar_amt)) Check out these 10 amazing Python programming resources for more information.

View Article
Python All-in-One For Dummies Cheat Sheet

Cheat Sheet / Updated 04-20-2021

Python is a flexible programming language that has become increasingly popular in the past few years. This cheat sheet is designed to give you a handy resource for common Python data types, Python operators, and Python functions. It includes Python data types, operators, special characters, f-strings, and functions for working with robots.

View Cheat Sheet
What is I2C? Python Programming Basics for the Raspberry Pi

Article / Updated 08-05-2020

The first thing to know about I2C is that every device on the I2C bus has an address. For example, an HDC1080 temperature and humidity sensor that you can easily make has an address of 0x40. What does the “0x” mean in this address? It means that the number that follows is in hexadecimal notation, base 16 instead of base 10 (our normal numbering system). To understand this interface, let’s look at what an I2C bus is. An I2C bus is often used to communicate with chips or sensors that are on the same board or located physically close to the CPU. I2C was first developed by Phillips (now NXP Semiconductors). To get around licensing issues (that have largely gone away), often the bus will be called TWI (Two Wire Interface). SMBus, developed by Intel, is a subset of I2C that defines the protocols more strictly. Modern I2C systems take policies and rules from SMBus, sometimes supporting both with minimal reconfiguration needed. Both the Arduino and the Raspberry Pi support the I2C bus. I2C provides good support for slow, close peripheral devices that need to be addressed only occasionally. For example, a temperature-measuring device will generally only change very slowly and so is a good candidate for the use of I2C, whereas a camera will generate lots of data quickly and potentially changes often. I2C uses only two bidirectional open-drain lines (open-drain means the device can pull a level down to ground, but cannot pull the line up to Vdd. Hence the name open-drain. Thus a requirement of I2C bus is that both lines are pulled up to Vdd. This is an important area and not properly pulling up the lines is the first and most common mistake you make when you first use an I2C bus. The Pi2Grover board contains 10K Ohm pullup resistors so you should not have to worry about this. The two lines are SDA (serial data line) and the SCL (serial clock line). There are two types of devices you can connect to an I2C bus: Main devices and Secondary devices. Typically, you have one Main device (The Raspberry Pi, in our case) and multiple Secondary devices, each with their individual 7-bit address. When used on the Raspberry Pi, the Raspberry Pi acts as the Main and all other devices are connected as Secondaries. The I2C protocol uses three types of messages: Digital single message where a main writes data to a secondary Digital single message where a main reads data from a secondary Digital combined messages, where a main issues at least two reads and/or writes to one or more secondaries Lucky for you, most of the complexity of dealing with the I2C bus is hidden by Python drivers and libraries. Exploring I2C on the Raspberry Pi To use the I2C bus on the Raspberry Pi, you need to make sure that it is enabled in the operating system. Check out this tutorial from Adafrui9t on how to do just that. Did you do it right? The easy way to check for this is to type the following command in your terminal window: I2cdetect -y 1 If it returns: -bash: i2cdetect: command not found Then you have not enabled your I2C bus. Repeat the tutorial to fix this. On the other hand, if it returns: 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- Then you have been successful! Note that all dashes mean there are no sensors on the I2C bus. Next, you are going to add a simple one. Now, let’s talk about how to communicate with I2C devices in Python. Talking to I2C devices with Python In order to talk to an I2C device, you should have one on the bus. A good one to start with is the HDC1080 temperature and humidity sensor. (You can get one of these inexpensive sensors on store.switchdoc.com or on amazon.com. Note: If you buy one on Amazon, you will need a female-to-Grove patch cable. The SwitchDoc Labs HDC1080 already comes with a Grove connector. You will also need the Pi2Grover Raspberry Pi-to-Grove converter, which is also available on store.switchdoc.com or on amazon.com. Now let’s install the HDC1080 I2C sensor on our Raspberry Pi. Follow these steps: Shut down your Raspberry Pi. When the yellow LED has stopped blinking, unplug the power from your Raspberry Pi.Never plug anything into or pull anything out a Raspberry Pi without shutting the computer down. Exceptions to this are USB ports, audio cables, and Ethernet cables, which are designed to support “hot-plugging.” The rest of the Raspberry Pi is not. Plug a Grove cable into the HDC1080. This project calls for the SwitchDoc Labs HDC1080; if you are using an Amazon device, make sure to use a Grove patch cable. Always shut down your Raspberry Pi by first typing sudo halt on the command line (or by selecting Shutdown from the GUI menu). Wait until the yellow LED on the Raspberry Pi stops blinking before removing the power cord. This ensures that the SDCard on the Raspberry Pi has been prepared for shutdown and you won't corrupt it. Just unplugging your Raspberry Pi may not corrupt the card, but unplugging it without shutting it down increases the likelihood of corruption. Corrupting your SDCard may not be fatal, but repairing it is a long, technical, irritating process. Plug the other end of the Grove cable into one of the Grove connectors marked I2C on the Pi2Grover that plugged on top of your Raspberry Pi. Note: The I2C is a bus, which means you can use any of the four I2C connectors. Power up the Raspberry Pi and open a terminal window. Type into the terminal sudo i2cdetect -y 1 and you will be rewarded with this: 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- Remember the 0x40 address of the HDC1080? There it is in the output above. Next, you’ll use Python to read the temperature and humidity from this sensor. Reading temperature and humidity from an I2C device using Python The use of Python libraries are key to being productive in writing Python applications. Here, you will be using the SDL_Pi_HDC1080_Python3, available on github.com. To read the temperature and humidity, follow these steps: First, create a directory in your main directory: cd mkdir I2CTemperature cd I2CTemperature Now you are in the I2CTemperature directory. Before looking at the Python code for reading your temperature, install the library on our Raspberry Pi. You do this by “cloning” the library located at github.com by using the following command in your terminal window: git clone https://github.com/switchdoclabs/SDL_Pi_HDC1080_Python3.git Here git clone clones the git repository located at the address and copies it to your Raspberry Pi. If you enter ls in the terminal window, you will see the following output: Using nano (or your favorite text editor), open up a file called temperatureTest.py and enter the following code: import sys sys.path.append('./SDL_Pi_HDC1080_Python3') import time import SDL_Pi_HDC1080 # Main Program print print ("") print ("Read Temperature and Humidity from HDC1080 using I2C bus ") print ("") hdc1080 = SDL_Pi_HDC1080.SDL_Pi_HDC1080() while True: print ("-----------------") print ("Temperature = %3.1f C" % hdc1080.readTemperature()) print ("Humidity = %3.1f %%" % hdc1080.readHumidity()) print ("-----------------") time.sleep(3.0) You are now reading environmental data from an I2C device. Your Raspberry Pi is connected to the real world. Try this experiment. Blow on the HDC1080 sensor board and watch the humidity go up! You will see something like this: Read Temperature and Humidity from HDC1080 using I2C bus ----------------- Temperature = 24.2 C Humidity = 32.9 % ----------------- ----------------- Temperature = 24.2 C Humidity = 32.9 % ----------------- ----------------- Temperature = 24.2 C Humidity = 32.9 % ----------------- Breaking down the Python program The first line imports the Python sys library: import sys The next line tells Python to search the SDL_Pi_HDC1080_Python3 directory below our current directory so it can find our library: sys.path.append('./SDL_Pi_HDC1080_Python3') More imports: import time import SDL_Pi_HDC1080 This statement instantiates the hdc1080 object and initializes it: # Main Program print print ("") print ("Read Temperature and Humidity from HDC1080 using I2C bus ") print ("") hdc1080 = SDL_Pi_HDC1080.SDL_Pi_HDC1080() These statements read the temperature and humidity and print them out to the terminal window. Note: You see that all the complexity of using an I2C device is hidden by use of the HDC1080 library: while True: print ("-----------------") print ("Temperature = %3.1f C" % hdc1080.readTemperature()) print ("Humidity = %3.1f %%" % hdc1080.readHumidity()) Sleep for three seconds and then repeat: print ("-----------------") time.sleep(3.0) Now that you have this program, you could add all sorts of things to it, such as turning on a red LED if it gets too hot, or turning on a blue LED if it gets to cold. You could even tweet your temperature and humidity by using the Twitter Python library.

View Article
How to Define and Use Python Lists

Article / Updated 10-09-2019

The simplest data collection in Python is a list. A list is any list of data items, separated by commas, inside square brackets. Typically, you assign a name to the Python list using an = sign, just as you would with variables. If the list contains numbers, then don't use quotation marks around them. For example, here is a list of test scores: scores = [88, 92, 78, 90, 98, 84] If the list contains strings then, as always, those strings should be enclosed in single or double quotation marks, as in this example: To display the contents of a list on the screen, you can print it just as you would print any regular variable. For example, executing print(students) in your code after defining that list shows this on the screen. ['Mark', 'Amber', 'Todd', 'Anita', 'Sandy'] This may not be exactly what you had in mind. But don’t worry, Python offers lots of great ways to access data in lists and display it however you like. Referencing Python list items by position Each item in a list has a position number, starting with zero, even though you don’t see any numbers. You can refer to any item in the list by its number using the name for the list followed by a number in square brackets. In other words, use this syntax: <em>listname</em>[<em>x</em>] Replace <em><code>listname</code></em> with the name of the list you're accessing and replace <em><code>x</code></em> with the position number of item you want. Remember, the first item is always number zero, not one. For example, in the first line below, I define a list named <code>students</code>, and then print item number zero from that list. The result, when executing the code, is that the name <code>Mark</code> is displayed. students = ["Mark", "Amber", "Todd", "Anita", "Sandy"] print(students[0]) Mark When reading access list items, professionals use the word sub before the number. For example, students[0] would be spoken as students sub zero. This next example shows a list named scores. The print() function prints the position number of the last score in the list, which is 4 (because the first one is always zero). scores = [88, 92, 78, 90, 84] print(scores[4]) 84 If you try to access a list item that doesn't exist, you get an “index out of range” error. The index part is a reference to the number inside the square brackets. For example, the image below shows a little experiment in a Jupyter notebook where a list of scores was created and then the printing of score[5] was attempted. It failed and generated an error because there is no scores[5]. There's only scores[0], scores[1], scores[2], scores[3], and scores[4] because the counting always starts at zero with the first one on the list. Looping through a Python list To access each item in a list, just use a for loop with this syntax: for <em>x</em> in <em>list</em>: Replace >x with a variable name of your choosing. Replace list with the name of the list. An easy way to make the code readable is to always use a plural for the list name (such as students, scores). Then you can use the singular name (student, score) for the variable name. You don't need to use subscript numbers (numbers in square brackets) with this approach either. For example, the following code prints each score in the scores list: for score in scores: print(score) Remember to always indent the code that’s to be executed within the loop. This image shows a more complete example where you can see the result of running the code in a Jupyter notebook. Seeing whether a Python list contains an item If you want your code to check the contents of a list to see whether it already contains some item, use in <em>listname</em> in an if statement or a variable assignment. For example, the code in the image below creates a list of names. Then, two variables store the results of searching the list for the names Anita and Bob. Printing the contents of each variable shows True for the one where the name (Anita) is in the list. The test to see whether Bob is in the list proves False. Getting the length of a Python list To determine how many items are in a list, use the len() function (short for length). Put the name of the list inside the parentheses. For example, type the following code into a Jupyter notebook or Python prompt or whatever: students = ["Mark", "Amber", "Todd", "Anita", "Sandy"] print(len(students)) Running that code produces this output: 5 There are indeed five items in the list, though the last one is always one less than the number because Python starts counting at zero. So the last one, Sandy, actually refers to students[4] and not students[5]. Appending an item to the end of a Python list When you want your Python code to add a new item to the end of a list, use the .append() method with the value you want to add inside the parentheses. You can use either a variable name or a literal value inside the quotation marks. For instance, in the following image the line that reads students.append("Goober") adds the name Goober to the list. The line that reads students.append(new_student) adds whatever name is stored in the variable named new_student to the list. The .append() method always adds to the end of the list. So when you print the list you see those two new names at the end. You can use a test to see whether an item is in a list and then append it only when the item isn't already there. For example, the code below won’t add the name Amber to the list because that name is already in the list: student_name = "Amanda" #Add student_name but only if not already in the list. if student_name in students: print (student_name + " already in the list") else: students.append(student_name) print (student_name + " added to the list") Inserting an item into a Python list Although the append() method allows you to add an item to the end of a list, the insert() method allows you to add an item to the list in any position. The syntax for insert() is <em>listname</em>.insert(<em>position</em>, <em>item</em>) Replace listname with the name of the list, position with the position at which you want to insert the item (for example, 0 to make it the first item, 1 to make it the second item, and so forth). Replace item with the value, or the name of a variable that contains the value, that you want to put into the list. For example, the following code makes Lupe the first item in the list: #Create a list of strings (names). students = ["Mark", "Amber", "Todd", "Anita", "Sandy"] student_name = "Lupe" # Add student name to front of the list. students.insert(0,student_name) #Show me the new list. print(students) If you run the code, print(students) will show the list after the new name has been inserted, as follows: ['Lupe', 'Mark', 'Amber', 'Todd', 'Anita', 'Sandy'] Changing an item in a Python list You can change an item in a list using the = assignment operator (check out these common Python operators) just like you do with variables. Just make sure you include the index number in square brackets of the item you want to change. The syntax is: listname[index]=newvalue Replace listname with the name of the list; replace index with the subscript (index number) of the item you want to change; and replace newvalue with whatever you want to put in the list item. For example, take a look at this code: #Create a list of strings (names). students = ["Mark", "Amber", "Todd", "Anita", "Sandy"] students[3] = "Hobart" print(students) When you run this code, the output is as follows, because Anita's name has been changed to Hobart. ['Mark', 'Amber', 'Todd', 'Hobart', 'Sandy'] Combining Python lists If you have two lists that you want to combine into a single list, use the extend() function with the syntax: <em>original_list</em>.extend(<em>additional_items_list</em>) In your code, replace original_list with the name of the list to which you’ll be adding new list items. Replace additional_items_list with the name of the list that contains the items you want to add to the first list. Here is a simple example using lists named list1 and list2. After executing list1.extend(list2), the first list contains the items from both lists, as you can see in the output of the print() statement at the end. # Create two lists of Names. list1 = ["Zara", "Lupe", "Hong", "Alberto", "Jake"] list2 = ["Huey", "Dewey", "Louie", "Nader", "Bubba"] # Add list2 names to list1. list1.extend(list2) # Print list 1. print(list1) ['Zara', 'Lupe', 'Hong', 'Alberto', 'Jake', 'Huey', 'Dewey', 'Louie', 'Nader', 'Bubba'] Easy Parcheesi, no? Removing Python list items Python offers a remove() method so you can remove any value from the list. If the item is in the list multiple times, only the first occurrence is removed. For example, the following code shows a list of letters with the letter C repeated a few times. Then the code uses letters.remove("C") to remove the letter C from the list: # Remove "C" from the list. letters.remove("C") #Show me the new list. print(letters) When you actually execute this code and then print the list, you'll see that only the first letter C has been removed: ['A', 'B', 'D', 'C', 'E', 'C'] If you need to remove all of an item, you can use a while loop to repeat the .remove as long as the item still remains in the list. For example, this code repeats the .remove as long as the “C” is still in the list. #Create a list of strings. letters = ["A", "B", "C", "D", "C", "E", "C"] If you want to remove an item based on its position in the list, use pop() with an index number rather than remove() with a value. If you want to remove the last item from the list, use pop() without an index number. For example, the following code creates a list, one line removes the first item (0), and another removes the last item (pop() with nothing in the parentheses). Printing the list shows those two items have been removed: #Create a list of strings. letters = ["A", "B", "C", "D", "E", "F", "G"] #Remove the first item. letters.pop(0) #Remove the last item. letters.pop() #Show me the new list. print(letters) Running the code shows that the popping the first and last items did, indeed, work: ['B', 'C', 'D', 'E', 'F'] When you pop() an item off the list, you can store a copy of that value in some variable. For example this image shows the same code as above. However, it stores copies of what's been removed in variables named first_removed and last_removed. At the end it prints the Python list, and also shows which letters were removed. Python also offers a del (short for delete) command that deletes any item from a list based on its index number (position). But again, you have to remember that the first item is zero. So, let's say you run the following code to delete item number 2 from the list: # Create a list of strings. letters = ["A", "B", "C", "D", "E", "F", "G"] # Remove item sub 2. del letters[2] print(letters) Running that code shows the list again, as follows. The letter C has been deleted, which is the correct item to delete because letters are numbered 0, 1, 2, 3, and so forth. ['A', 'B', 'D', 'E', 'F', 'G'] You can also use del to delete an entire list. Just don’t use the square brackets and the index number. For example, the code you see below creates a list then deletes it. Trying to print the list after the deletion causes an error, because the list no longer exists when the print() statement is executed. Clearing out a Python list If you want to delete the contents of a list but not the list itself, use .clear(). The list still exists; however, it contains no items. In other words, it's an empty list. The following code shows how you could test this. Running the code displays [] at the end, which lets you know the list is empty: # Create a list of strings. letters = ["A", "B", "C", "D", "E", "F", "G"] # Clear the list of all entries. letters.clear() # Show me the new list. print(letters) [] Counting how many times an item appears in a Python list You can use the Python count() method to count how many times an item appears in a list. As with other list methods, the syntax is simple: <em>listname</em>.count(<em>x</em>) Replace listname with the name of your list, and x with the value you're looking for (or the name of a variable that contains that value). The code in the image below counts how many times the letter B appears in the list, using a literal B inside the parentheses of .count(). This same code also counts the number of C grades, but that value was stored in a variable just to show the difference in syntax. Both counts worked, as you can see in the output of the program at the bottom. One was added to count the F's, not using any variables. The F’s were counted right in the code that displays the message. There are no F grades, so this returns zero, as you can see in the output. When trying to combine numbers and strings to form a message, remember you have to convert the numbers to strings using the str() function. Otherwise, you get an error that reads something like can only concatenate str (not "int") to str. In that message, int is short for integer, and str is short for string. Finding a Python list item's index Python offers an .index() method that returns a number indicating the position, based on index number, of an item in a list. The syntax is: <em>listname</em>.index(<em>x</em>) As always, replace listname with name of the list you want to search. Replace x what whatever you're looking for (either as a literal or as a variable name, as always). Of course, there’s no guarantee that the item is in the list, and even if it is, there’s no guarantee that the item is in the list only once. If the item isn’t in the list, then an error occurs. If the item is in the list multiple times, then the index of the first matching item is returned. The following image shows an example where the program crashes at the line f_index = grades.index(look_for) because there is no F in the list. An easy way to get around that problem is to use an if statement to see whether an item is in the list before you try to get its index number. If the item isn't in the list, display a message saying so. Otherwise, get the index number and show it in a message. That code is as follows: # Create a list of strings. grades = ["C", "B", "A", "D", "C", "B", "C"] # Decide what to look for look_for = "F" # See if the item is in the list. if look_for in grades: # If it's in the list, get and show the index. print(str(look_for) + " is at index " + str(grades.index(look_for))) else: # If not in the list, don't even try for index number. print(str(look_for) + " isn't in the list.") Alphabetizing and sorting Python lists Python offers a sort() method for sorting lists. In its simplest form, it alphabetizes the items in the list (if they’re strings). If the list contains numbers, they’re sorted smallest to largest. For a simple sort like that, just use sort() with empty parentheses: <em>listname</em>.sort() Replace listname with the name of your list. The following image shows an example using a list of strings and a list of numbers. In the example, a new list was created for each of them simply by assigning each sorted list to a new list name. Then the code prints the contents of each sorted list. If your list contains strings with a mixture of uppercase and lowercase letters, and if the results of the sort don't look right, try replacing .sort() with .sort(key=lambda s:s.lower()) and then running the code again. Dates are a little trickier because you can’t just type them in as strings, like "12/31/2020". They have to be the date data type to sort correctly. This means using the datetime module and the date() method to define each date. You can add the dates to the list as you would any other list. For example, in the following line, the code creates a list of four dates, and the code is perfectly fine. dates = [dt.date(2020,12,31), dt.date(2019,1,31), dt.date(2018,2,28), dt.date(2020,1,1)] The computer certainly won't mind if you create the list this way. But if you want to make the code more readable to yourself or other developers, you may want to create and append each date, one at a time, so just so it’s a little easier to see what’s going on and so you don’t have to deal with so many commas in one line of code. The image below shows an example where an empty list named datelist was created: datelist = [] Then one date at a time was appended to the list using the dt.date(<em>year</em>,<em>month</em>,<em>day</em>) syntax. After the list is created, the code uses datelist.sort() to sort them into chronological order (earliest to latest). You don’t need to use print(datelist) in that code because that method displays the dates with the data type information included, like this: [datetime.date(2018, 2, 28), datetime.date(2019, 1, 31), datetime.date (2020, 1, 1), datetime.date(2020, 12, 31)] Not the easiest list to read. So, rather than print the whole list with one print() statement, you can loop through each date in the list, and printed each one formatted with the f-string %m/%d/%Y. This displays each date on its own line in mm/dd/yyyy format, as you can see at the bottom of the image above. If you want to sort items in reverse order, put reverse=True inside the sort() parentheses (and don't forget to make the first letter uppercase). The image below shows examples of sorting all three lists in descending (reverse) order using reverse=True. Reversing a Python list You can also reverse the order of items in a list using the .reverse method. This is not the same as sorting in reverse, because when you sort in reverse, you still actually sort: Z–A for strings, largest to smallest for numbers, latest to earliest for dates. When you reverse a list, you simply reverse the items in the list, no matter their order, without trying to sort them in any way. The following code shows an example in which you reverse the order of the names in the list and then print the list. The output shows the list items reversed from their original order: # Create a list of strings. names = ["Zara", "Lupe", "Hong", "Alberto", "Jake"] # Reverse the list names.reverse() # Print the list print(names) ['Jake', 'Alberto', 'Hong', 'Lupe', 'Zara'] Copying a Python list If you ever need to work with a copy of a list, use the .copy() method so as not to alter the original list,. For example, the following code is similar to the preceding code, except that instead of reversing the order of the original list, you make a copy of the list and reverse that one. Printing the contents of each list shows how the first list is still in the original order whereas the second one is reversed: # Create a list of strings. names = ["Zara", "Lupe", "Hong", "Alberto", "Jake"] # Make a copy of the list backward_names = names.copy() # Reverse the copy backward_names.reverse() # Print the list print(names) print(backward_names) ['Zara', 'Lupe', 'Hong', 'Alberto', 'Jake'] ['Jake', 'Alberto', 'Hong', 'Lupe', 'Zara'] For future references, the following table summarizes the methods you've learned about. Methods for Working with Lists Method What it Does append() Adds an item to the end of the list. clear() Removes all items from the list, leaving it empty. copy() Makes a copy of a list. count() Counts how many times an element appears in a list. extend() Appends the items from one list to the end of another list. index() Returns the index number (position) of an element within a list. insert() Inserts an item into the list at a specific position. pop() Removes an element from the list, and provides a copy of that item that you can store in a variable. remove() Removes one item from the list. reverse() Reverses the order of items in the list. sort() Sorts the list in ascending order. Put reverse=True inside the parentheses to sort in descending order.

View Article
How to Use Lambda Functions in Python

Article / Updated 10-09-2019

Python supports the concept of anonymous functions, also called lambda functions. The anonymous part of the name is based on the fact that the function doesn't need to have a name (but can have one if you want it to). The lambda part is based on the use of the keyword lambda to define them in Python. Lambda is also the 11th letter of the Greek alphabet. But the main reason that the name is used in Python is because the term lambda is used to describe anonymous functions in calculus. Now that we’ve cleared that up, you can use this info to spark enthralling conversation at office parties. The minimal syntax for defining a lambda expression (with no name) with Python is: Lambda arguments : expression When using it: Replace arguments with data being passed into the expression. Replace expression with an expression (formula) that defines what you want the lambda to return. A fairly common example of using that syntax is when you're trying to sort strings of text where some of the names start with uppercase letters and some start with lowercase letters, as in these names: Adams, Ma, diMeola, Zandusky Suppose you write the following code to put the names into a list, sort it, and then print the list, like this: names = ['Adams', 'Ma', 'diMeola', 'Zandusky'] names.sort() print(names) That output from this is: ['Adams', 'Ma', 'Zandusky', 'diMeola'] Having diMeola come after Zandusky seems wrong to some beginners. But computers don’t always see things the way we do. (Actually, they don’t “see” anything because they don’t have eyes or brains … but that’s beside the point.) The reason diMeola comes after Zandusky is because the sort is based on ASCII, which is a system in which each character is represented by a number. All the lowercase letters have numbers that are higher than uppercase numbers. So, when sorting, all the words starting with lowercase letters come after the words that start with an uppercase letter. If nothing else, it at least warrants a minor hmm. To help with these matters, the Python sort() method lets you include a key= expression inside the parentheses, where you can tell it how to sort. The syntax is: .sort(key = transform) The transform part is some variation on the data being sorted. If you're lucky and one of the built-in functions like len (for length) will work for you, then you can just use that in place of transform, like this: names.sort(key=len) Unfortunately for us, the length of the string doesn't help with alphabetizing. So when you run that, the order turns out to be: ['Ma', 'Adams', 'diMeola', 'Zandusky'] The sort is going from the shortest string (the one with the fewest characters) to the longest string. Not helpful at the moment. You can’t write key=lower or key=upper to base the sort on all lowercase or all uppercase letters either, because lower and upper aren't built-in functions (which you can verify pretty quickly by googling python 3.7 built-in functions). In lieu of a built-in function, you can use a custom function that you define yourself using def. For example, you can create a function named lower() that accepts a string and returns that string with all of its letters converted to lowercase. Here is the function: def lower(anystring): """ Converts string to all lowercase """ return anystring.lower() The name lower is made up, and anystring is a placeholder for whatever string you pass to it in the future. The return anystring.lower() returns that string converted to all lowercase using the .lower() method of the str (string) object. (Read about Python string methods for more information.) You can't use key=lower in the sort() parentheses because lower() isn't a built-in function. It’s a method … not the same. Kind of annoying with all these buzzwords. Suppose you write this function in a Jupyter cell or .py file. Then you call the function with something like print(lowercaseof('Zandusky')). What you get as output is that string converted to all lowercase, as you see below. Okay, so now you have a custom function to convert any string to all lowercase letters. How do you use that as a sort key? Easy, use key=transform the same as before, but replace transform with your custom function name. The function is named lowercaseof, so you'd use .sort(key= lowercaseof), as shown in the following: def lowercaseof(anystring): """ Converts string to all lowercase """ return anystring.lower() names = ['Adams', 'Ma', 'diMeola', 'Zandusky'] names.sort(key=lowercaseof) Running this code to display the list of names puts them in the correct order, because it based the sort on strings that are all lowercase. The output is the same as before because only the sorting, which took place behind the scenes, used lowercase letters. The original data is still in its original uppercase and lowercase letters. 'Adams', 'diMeola', 'Ma', 'Zandusky' If you’re still awake and conscious after reading all of this you may be thinking, “Okay, you solved the sorting problem. But I thought we were talking about lambda functions here. Where’s the lambda function?” There is no lambda function yet. But this is a perfect example of where you could use a lambda function, because the Python function you’re calling, lowercaseof(), does all of its work with just one line of code: return anystring.lower(). When your function can do its thing with a simple one-line expression like that, you can skip the def and the function name and just use this syntax: lambda parameters : expression Replace parameters with one or more parameter names that you make up yourself (the names inside the parentheses after def and the function name in a regular function). Replace expression with what you want the function to return without the word return. So in this example the key, using a lambda expression, would be: lambda anystring : anystring.lower() Now you can see why it's an anonymous function. The whole first line with function name lowercaseof() has been removed. So the advantage of using the lambda expression is that you don’t even need the external custom function at all. You just need the parameter followed by a colon and an expression that tells it what to return. The image below shows the complete code and the result of running it. You get the proper sort order without the need for a customer external function like lowercaseof(). You just use anystring : anystring.lower() (after the word lambda) as the sort key. Let’s also add that anystring is a longer parameter name than most Pythonistas would use. Python folks are fond of short names, even single-letter names. For example, you could replace anystring with s (or any other letter), as in the following, and the code will work exactly the same: names = ['Adams', 'Ma', 'diMeola', 'Zandusky'] names.sort(key=lambda s: s.lower()) print(names) Way back at the beginning of this tirade, it was mentioned that a lambda function doesn't have to be anonymous. You can give them names and call them as you would other functions. For example, here is a lambda function named currency that takes any number and returns a string in currency format (that is, with a leading dollar sign, commas between thousands, and two digits for pennies): currency = lambda n : f"${n:,.2f}" Here is one named percent that multiplies any number you send to it by 100 and shows it with two a percent sign at the end: percent = lambda n : f"{n:.2%}" The following image shows examples of both functions defined at the top of a Jupyter cell. Then a few print statements call the functions by name and pass some sample data to them. Each print() statements displays the number in the desired format. The reason you can define those as single-line lambdas is because you can do all the work in one line, f"${n:,.2f}" for the first one and f"{n:.2%}" for the second one. But just because you can do it that way, doesn't mean you must. You could use regular functions too, as follows: # Show number in currency format. def currency(n): return f"${n:,.2f}" def percent(n): # Show number in percent format. return f"{n:.2%}" With this longer syntax, you could pass in more information too. For example, you may default to a right-aligned format within a certain width (say 15 characters) so all numbers came out right-aligned to the same width. The image shows this variation on the two functions. In the image above, the second parameter is optional and defaults to 15 if omitted. So if you call it like this: print(currency(9999)) … you get $9,999.00 padding with enough spaces on the left to make it 15 characters wide. If you call it like this instead: print(currency(9999,20) … you still get $9,999.00 but padded with enough spaces on the left to make it 20 characters wide. The .ljust() used above is a Python built-in string method that pads the left side of a string with sufficient spaces to make it the specified width. There’s also an rjust() method to pad the right side. You can also specify a character other than a space. Google python 3 ljust rjust if you need more info. So there you have it, the ability to create your own custom functions in Python. In real life, what you want to do is, any time you find that you need access to the same chunk of code — the same bit of login — over and over again in your app, don’t simply copy/paste that chunk of code over and over again. Instead, put all that code in a function that you can call by name. That way, if you decide to change the Python stringcode, you don’t have to go digging through your app to find all the places that need changing. Just change it in the function where it’s all defined in one place.

View Article
Your Guide to the Python Standard Library

Article / Updated 10-09-2019

The Python standard library is basically all the stuff you get when you get the Python languages. That includes all the Python data types like string, integer, float, and Boolean. Every instance of those data types is actually an instance of a class defined in the Python standard library. For this reason, the terms type, instance, and object are often used interchangeably. An integer is a whole number; it’s also a data type in Python. But it exists because the standard library contains a class for integers, and every integer you create is actually an instance of that class and hence an object (because classes are the templates for things called objects). The type() function in Python usually identifies the type of a piece of data. For example, run these two lines of code at a Python prompt, in a Jupyter notebook or a .py file: x = 3 print(type(x)) The output is: <class 'int'> This is telling you that x is an integer, and also that it's an instance of the int class from the standard library. Running this code: x = 'howdy' print(type(x)) Produces this output: <class 'str'> That is, x contains data that’s the string data type, created by the Python str class. The same thing works for a float (a numeric value with a decimal point, like 3.14) and for Booleans (True or False). Python’s dir() function The Python standard library offers a dir() method that displays a list of all the attributes associated with a type. For example, in the previous example the result tells you that the data is the str data type. So you know that's a type, and thus in instance of a class called str (short for string). Entering this command: dir(str) Displays something like this: ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__','__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] The dunder named items (the names surrounded by double-underlines) usually represent something that’s built into Python and that plays some role in the Python language that you don’t necessarily access directly. These are often referred to as special variables or magic methods. For example, there’s an __add__ method that’s actually invoked by using the + (addition) operator to add two numbers or join together two strings. The regular functions don’t have the double underscores and are typically followed by parentheses. For example, take a look at these lines of code: x = "Howdy" print(type(x), x.isalpha(), x.upper()) The output from that code is: <class 'str'> True HOWDY The first part, <class 'str'> tells you that x contains a string. As such, you can use any of the attributes shown in the output of dir(str) on it. For example, the True is the output from x.isalpha() because x does contain alphabetic characters. The HOWDY is the output of x.upper(), which converts the string to all uppercase letters. Beginners often wonder what good seeing a bunch of names like 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', and so forth does for you when you don't know what the names mean or how to use them. Well, they don’t really help you much if you don’t pursue it any further. You can get some more detailed information by using help() rather than dir. Python’s help() function The Python prompt also offers a help() function with the syntax: help(<em>object</em>) To use it, replace <em>object</em> with the object type with which you're seeking help. For example, to get help with str objects (strings, which come from the str class) enter this command at the Python prompt: help(str) The output will be more substantial information about the topic in the parentheses. For example, where dir(str) lists the names of attributes of that type, help(dir) provides more detail about each item. For example, whereas dir(str) tells you that there's a thing called capitalize in the str class, help tells you a bit more about it, as follows: capitalize(self, /) Return a capitalized version of the string. More specifically, make the first character have upper case and the rest lower case. The word self there just means that whatever word you pass to capitalize is what gets capitalized. The / at the end marks the end of positional-only parameters, meaning that you can't use keywords with parameters after that like you can when defining your own functions. What usually works best for most people is a more in-depth explanation and one or more examples. For those, Google or a similar search engine is usually your best bet. Start the search with the word Python (so it knows what the search is in reference too) followed by the exact word with which your seeking assistance. For example, searching Google for python capitalize … provides links to lots of different resources for learning about the capitalize attribute of the str object, including examples of its use. If you get tired of pressing any key to get past More … at the end of every page in help, just press Ctrl+C. This gets you back to the Python prompt. Of course, a really good (albeit technical) resource for the Python standard library is the standard library documentation itself. This is always available at usually under the link Library Reference. But even that wording may change, so if in doubt, just google python standard library. Just be forewarned that it is huge and very technical. So don't expect to memorize or even understand it all right off the bat. Use it as an ongoing resource to learn about things that interest you as your knowledge of Python develops. The documentation that appears at docs.python.org will generally be for the current stable version. Links to older versions, and to any newer versions that may be in the works when you visit, are available from links at the left side of the page. Exploring Python built-in functions Both dir() and help() are examples of Python built-in functions. These are functions that are always available to you in Python, in any app you're creating as well as at the Python command prompt. These built-in functions are also a part of the standard library In fact, if you google Python built-in functions, some of the search results will point directly to the Python documentation. Clicking that link will open that section of the standard library documentation and displays a table of all the built-in functions. On that page, you can click the name of any function to learn more about it.

View Article
A Beginner’s Guide to Python Versions

Article / Updated 10-09-2019

Similar to other programming languages, Python has gone through a few iterations, otherwise known as versions. Before you can fully understand the possibilities of Python, you need to understand the different versions and know which version you are using. The different versions of Python roaming the world prompt many a beginner to wonder things like Why are there different versions of Python? How are they different? Which version of Python should I learn? All good questions, and let's start with the first. A version is kind of like a car year. You can go out a buy a 1968 Ford Mustang or a 1990 Ford Mustang or a 2000 Ford Mustangs, and a 2019 Ford Mustang, They’re all Ford Mustangs. The only difference is that the one with the highest year number is the most “current” Ford Mustang. That Mustang is different from the older models in that it has some improvements based on experience with earlier models, as well as features that are current with the times. Programming languages (and most other software products) work the same way. But as a rule programmers don’t ascribe year numbers to them, because they’re not released on a yearly basis. They’re released whenever they’re released. But the principle is the same. The version with the highest number is the newest, most recent “model,” sporting improvements based on experience with earlier versions, as well as features that are relevant to the current times. Just as we use a decimal point with money to separate dollars from cents, we use decimal points with version numbers to indicate “how much it’s changed.” When there’s a significant change, the whole version number is usually changed. More minor changes are expressed as decimal points. You can see how the version number increases along with the year in the following, which shows the release dates of various Python versions. A few releases have been skipped here because there is little reason to know or understand the differences between all the versions. The table is provided so you can see how newer versions have higher version numbers; that’s all that matters. Examples of Python Versions and Release Dates Version When Released Python 3.7 June 2018 Python 3.6 December 2016. Python 3.5 September 2015 Python 3.4 March 2014 Python 3.3 September 2012 Python 3.2 February 2011 Python 3.1 September 2012 Python 3.0 December 2008 Python 2.7 July 2010 Python 2.6 October 2008 Python 2.0 October 2000. Python 1.6 September 2000. Python 1.5 February 1998 Python 1.0 January 1994 If you paid close attention you may notice that Version 3.0 starts in December 2008, but Version 2.7 extends into 2010. So if versions are like car years, why the overlap? The car years analogy is just an analogy indicating that the larger the number, the more recent the version. But in Python it’s the most recent within the main Python version. When the first number changes, that’s usually a change that’s so significant, software written in prior versions may not even work in that version. If you happen to be a software company with a product, written in Python 2, on the market, and have millions of dollars invested in that product, you may not be too thrilled to have to start over from scratch to go with the current version. So “older versions” often continue to be supported and evolve, independent of the most recent version, to support developers and businesses that are already heavily invested in the previous version. The biggest question on most beginners minds is “what version should I learn?” The answer to that is simple … whatever is the most current version. You’ll know what that is because when you go to the Python.org website to download Python, they will tell you what the most current stable build (version) is. That’s the one they’ll recommend, and that’s the one you should use. The only reason to learn something like Version 2 or 2.7 or something else older would be if you’ve already been hired to work on some project, and that company requires you to learn and use a specific version. That sort of thing is rare, because as a beginner you’re not likely to already have a full-time job as a programmer. But in the messy real world there are companies heavily invested in some earlier version of a product, so when hiring, they’ll be looking for people with knowledge of that version. Most current programmers focus on versions of Python that are current in late 2018 and early 2019, from Python 3.7 and above. Don’t worry about version differences after the first and second digits. Version 3.7.2 is similar enough go version 3.7.1 that it’s not important, especially to a beginner. Likewise, Version 3.8 isn’t that big a jump from 3.7. So don’t worry about these miner version differences when first learning. Most of what’s in Python is the across all versions. So you need not worry about investing time in learning a version that’s obsolete or soon will be.

View Article
How to Build a Simple Neural Network in Python

Article / Updated 10-09-2019

You can use the Python language to build neural networks, from simple to complex. For you to build a neural network, you first need to decide what you want it to learn. For this simple Python tutorial, put your eyes on a pretty simple goal: implement a three-input XOR gate. (That’s an eXclusive OR gate.) The table below shows the function you’re going to implement in table form. The Truth Table (a Three-Input XOR Gate) for the Neural Network X1 X2 X3 Y1 0 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1 1 An Exclusive Or function returns a 1 only if all the inputs are either 0 or 1. The neural-net Python code Here, you will be using the Python library called NumPy, which provides a great set of functions to help organize a neural network and also simplifies the calculations. Our Python code using NumPy for the two-layer neural network follows. Using nano (or your favorite text editor), open up a file called “2LayerNeuralNetwork.py” and enter the following code: # 2 Layer Neural Network in NumPy import numpy as np # X = input of our 3 input XOR gate # set up the inputs of the neural network (right from the table) X = np.array(([0,0,0],[0,0,1],[0,1,0], \ [0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]), dtype=float) # y = our output of our neural network y = np.array(([1], [0], [0], [0], [0], \ [0], [0], [1]), dtype=float) # what value we want to predict xPredicted = np.array(([0,0,1]), dtype=float) X = X/np.amax(X, axis=0) # maximum of X input array # maximum of xPredicted (our input data for the prediction) xPredicted = xPredicted/np.amax(xPredicted, axis=0) # set up our Loss file for graphing lossFile = open("SumSquaredLossList.csv", "w") class Neural_Network (object): def __init__(self): #parameters self.inputLayerSize = 3 # X1,X2,X3 self.outputLayerSize = 1 # Y1 self.hiddenLayerSize = 4 # Size of the hidden layer # build weights of each layer # set to random values # look at the interconnection diagram to make sense of this # 3x4 matrix for input to hidden self.W1 = \ np.random.randn(self.inputLayerSize, self.hiddenLayerSize) # 4x1 matrix for hidden layer to output self.W2 = \ np.random.randn(self.hiddenLayerSize, self.outputLayerSize) def feedForward(self, X): # feedForward propagation through our network # dot product of X (input) and first set of 3x4 weights self.z = np.dot(X, self.W1) # the activationSigmoid activation function - neural magic self.z2 = self.activationSigmoid(self.z) # dot product of hidden layer (z2) and second set of 4x1 weights self.z3 = np.dot(self.z2, self.W2) # final activation function - more neural magic o = self.activationSigmoid(self.z3) return o def backwardPropagate(self, X, y, o): # backward propagate through the network # calculate the error in output self.o_error = y - o # apply derivative of activationSigmoid to error self.o_delta = self.o_error*self.activationSigmoidPrime(o) # z2 error: how much our hidden layer weights contributed to output # error self.z2_error = self.o_delta.dot(self.W2.T) # applying derivative of activationSigmoid to z2 error self.z2_delta = self.z2_error*self.activationSigmoidPrime(self.z2) # adjusting first set (inputLayer --> hiddenLayer) weights self.W1 += X.T.dot(self.z2_delta) # adjusting second set (hiddenLayer --> outputLayer) weights self.W2 += self.z2.T.dot(self.o_delta) def trainNetwork(self, X, y): # feed forward the loop o = self.feedForward(X) # and then back propagate the values (feedback) self.backwardPropagate(X, y, o) def activationSigmoid(self, s): # activation function # simple activationSigmoid curve as in the book return 1/(1+np.exp(-s)) def activationSigmoidPrime(self, s): # First derivative of activationSigmoid # calculus time! return s * (1 - s) def saveSumSquaredLossList(self,i,error): lossFile.write(str(i)+","+str(error.tolist())+'\n') def saveWeights(self): # save this in order to reproduce our cool network np.savetxt("weightsLayer1.txt", self.W1, fmt="%s") np.savetxt("weightsLayer2.txt", self.W2, fmt="%s") def predictOutput(self): print ("Predicted XOR output data based on trained weights: ") print ("Expected (X1-X3): \n" + str(xPredicted)) print ("Output (Y1): \n" + str(self.feedForward(xPredicted))) myNeuralNetwork = Neural_Network() trainingEpochs = 1000 #trainingEpochs = 100000 for i in range(trainingEpochs): # train myNeuralNetwork 1,000 times print ("Epoch # " + str(i) + "\n") print ("Network Input : \n" + str(X)) print ("Expected Output of XOR Gate Neural Network: \n" + str(y)) print ("Actual Output from XOR Gate Neural Network: \n" + \ str(myNeuralNetwork.feedForward(X))) # mean sum squared loss Loss = np.mean(np.square(y - myNeuralNetwork.feedForward(X))) myNeuralNetwork.saveSumSquaredLossList(i,Loss) print ("Sum Squared Loss: \n" + str(Loss)) print ("\n") myNeuralNetwork.trainNetwork(X, y) myNeuralNetwork.saveWeights() myNeuralNetwork.predictOutput() Breaking down the Python code for a neural network Some of the following Python code is a little obtuse the first time through, so here are some explanations. # 2 Layer Neural Network in NumPy import numpy as np If you get an import error when running the preceding code, install the NumPy Python library. To do so on a Raspberry Pi (or an Ubuntu system), type the following in a terminal window: sudo apt-get install python3-numpy Next, all eight possibilities of the X1–X3 inputs and the Y1 output are defined. # X = input of our 3 input XOR gate # set up the inputs of the neural network (right from the table) X = np.array(([0,0,0],[0,0,1],[0,1,0], \ [0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]), dtype=float) # y = our output of our neural network y = np.array(([1], [0], [0], [0], [0], \ [0], [0], [1]), dtype=float) In this part of your Python code, you pick a value to predict (this is the particular answer you want at the end). # what value we want to predict xPredicted = np.array(([0,0,1]), dtype=float) X = X/np.amax(X, axis=0) # maximum of X input array # maximum of xPredicted (our input data for the prediction) xPredicted = xPredicted/np.amax(xPredicted, axis=0) Save out our Sum Squared Loss results to a file for use by Excel per epoch. # set up our Loss file for graphing lossFile = open("SumSquaredLossList.csv", "w") FBuild the Neural_Network class for this problem. This image shows the network that is being built. You can see that each of the layers are represented by a line of Python code in the network. class Neural_Network (object): def __init__(self): #parameters self.inputLayerSize = 3 # X1,X2,X3 self.outputLayerSize = 1 # Y1 self.hiddenLayerSize = 4 # Size of the hidden layer Set all the network weights to random values to start. # build weights of each layer # set to random values # look at the interconnection diagram to make sense of this # 3x4 matrix for input to hidden self.W1 = \ np.random.randn(self.inputLayerSize, self.hiddenLayerSize) # 4x1 matrix for hidden layer to output self.W2 = \ np.random.randn(self.hiddenLayerSize, self.outputLayerSize) The feedForward function implements the feed-forward path through the neural network. This basically multiplies the matrices containing the weights from each layer to each layer and then applies the sigmoid activation function. def feedForward(self, X): # feedForward propagation through our network # dot product of X (input) and first set of 3x4 weights self.z = np.dot(X, self.W1) # the activationSigmoid activation function - neural magic self.z2 = self.activationSigmoid(self.z) # dot product of hidden layer (z2) and second set of 4x1 weights self.z3 = np.dot(self.z2, self.W2) # final activation function - more neural magic o = self.activationSigmoid(self.z3) return o And now add the backwardPropagate function that implements the real trial-and-error learning that our neural network uses. def backwardPropagate(self, X, y, o): # backward propagate through the network # calculate the error in output self.o_error = y - o # apply derivative of activationSigmoid to error self.o_delta = self.o_error*self.activationSigmoidPrime(o) # z2 error: how much our hidden layer weights contributed to output # error self.z2_error = self.o_delta.dot(self.W2.T) # applying derivative of activationSigmoid to z2 error self.z2_delta = self.z2_error*self.activationSigmoidPrime(self.z2) # adjusting first set (inputLayer --> hiddenLayer) weights self.W1 += X.T.dot(self.z2_delta) # adjusting second set (hiddenLayer --> outputLayer) weights self.W2 += self.z2.T.dot(self.o_delta) To train the network for a particular epoch, you need to call both the backwardPropagate and the feedForward functions each time you train the network. def trainNetwork(self, X, y): # feed forward the loop o = self.feedForward(X) # and then back propagate the values (feedback) self.backwardPropagate(X, y, o) The sigmoid activation function and the first derivative of the sigmoid activation function follows. def activationSigmoid(self, s): # activation function # simple activationSigmoid curve as in the book return 1/(1+np.exp(-s)) def activationSigmoidPrime(self, s): # First derivative of activationSigmoid # calculus time! return s * (1 - s) Next, save the epoch values of the loss function to a file for Excel and the neural weights. def saveSumSquaredLossList(self,i,error): lossFile.write(str(i)+","+str(error.tolist())+'\n') def saveWeights(self): # save this in order to reproduce our cool network np.savetxt("weightsLayer1.txt", self.W1, fmt="%s") np.savetxt("weightsLayer2.txt", self.W2, fmt="%s") Next, run the neural network to predict the outputs based on the current trained weights. def predictOutput(self): print ("Predicted XOR output data based on trained weights: ") print ("Expected (X1-X3): \n" + str(xPredicted)) print ("Output (Y1): \n" + str(self.feedForward(xPredicted))) myNeuralNetwork = Neural_Network() trainingEpochs = 1000 #trainingEpochs = 100000 The following is the main training loop that goes through all the requested epochs. Change the variable trainingEpochs above to vary the number of epochs you would like to train your network. for i in range(trainingEpochs): # train myNeuralNetwork 1,000 times print ("Epoch # " + str(i) + "\n") print ("Network Input : \n" + str(X)) print ("Expected Output of XOR Gate Neural Network: \n" + str(y)) print ("Actual Output from XOR Gate Neural Network: \n" + \ str(myNeuralNetwork.feedForward(X))) # mean sum squared loss Loss = np.mean(np.square(y - myNeuralNetwork.feedForward(X))) myNeuralNetwork.saveSumSquaredLossList(i,Loss) print ("Sum Squared Loss: \n" + str(Loss)) print ("\n") myNeuralNetwork.trainNetwork(X, y) Save the results of your training for reuse and predict the output of our requested value. myNeuralNetwork.saveWeights() myNeuralNetwork.predictOutput() Running the neural-network Python code At a command prompt, enter the following command: python3 2LayerNeuralNetworkCode.py You will see the program start stepping through 1,000 epochs of training, printing the results of each epoch, and then finally showing the final input and output. It also creates the following files of interest: txt: This file contains the final trained weights for input-layer-to-hidden-layer connections (a 4x3 matrix). txt: This file contains the final trained weights for hidden-layer-to-output-layer connections (a 1x4 matrix). csv: This is a comma-delimited file containing the epoch number and each loss factor at the end of each epoch. You can use this to graph the results across all epochs. Here is the final output of the program for the last epoch (999 since you start at 0). Epoch # 999 Network Input : [[0. 0. 0.] [0. 0. 1.] [0. 1. 0.] [0. 1. 1.] [1. 0. 0.] [1. 0. 1.] [1. 1. 0.] [1. 1. 1.]] Expected Output of XOR Gate Neural Network: [[1.] [0.] [0.] [0.] [0.] [0.] [0.] [1.]] Actual Output from XOR Gate Neural Network: [[0.93419893] [0.04425737] [0.01636304] [0.03906686] [0.04377351] [0.01744497] [0.0391143 ] [0.93197489]] Sum Squared Loss: 0.0020575319565093496 Predicted XOR output data based on trained weights: Expected (X1-X3): [0. 0. 1.] Output (Y1): [0.04422615]< At the bottom, you see our expected output is 0. 04422615, which is quite close, but not quite, the expected value of 0. If you compare each of the expected outputs to the actual output from the network, you see they all match pretty closely. And every time you run it the results will be slightly different because you initialize the weights with random numbers at the start of the run. The goal of a neural-network training is not to get it exactly right — only right within a stated tolerance of the correct result. For example, if you said that any output above 0.9 is a 1 and any output below 0.1 is a 0, then our network would have given perfect results. The Sum Squared Loss is a measure of all the errors of all the possible inputs. If you graph the Sum Squared Loss versus the epoch number, you get the graph shown in Figure 2-4. You can see that it gets better quite quickly and then it tails off. 1,000 epochs are fine for our stated problem. One more experiment. If you increase the number of epochs to 100,000, then the numbers are better still, but our results, according to our accuracy criteria (> 0.9 = 1 and < 0.1 = 0) were good enough in the 1,000 epoch run. Epoch # 99999 Network Input : [[0. 0. 0.] [0. 0. 1.] [0. 1. 0.] [0. 1. 1.] [1. 0. 0.] [1. 0. 1.] [1. 1. 0.] [1. 1. 1.]] Expected Output of XOR Gate Neural Network: [[1.] [0.] [0.] [0.] [0.] [0.] [0.] [1.]] Actual Output from XOR Gate Neural Network: [[9.85225608e-01] [1.41750544e-04] [1.51985054e-04] [1.14829204e-02] [1.17578404e-04] [1.14814754e-02] [1.14821256e-02] [9.78014943e-01]] Sum Squared Loss: 0.00013715041859631841 Predicted XOR output data based on trained weights: Expected (X1-X3): [0. 0. 1.] Output (Y1): [0.00014175] Using TensorFlow for the same neural network TensorFlow is a Python package that is also designed to support neural networks based on matrices and flow graphs similar to NumPy. It differs from NumPy in one major respect: TensorFlow is designed for use in machine learning and AI applications and so has libraries and functions designed for those applications. TensorFlow gets its name from the way it processes data. A tensor is a multidimensional matrix of data, and this is transformed by each TensorFlow layer it moves through. TensorFlow is extremely Python-friendly and can be used on many different machines and also in the cloud. Remember, neural networks are data-flow graphs and are implemented in terms of performing operations matrix of data and then moving the resulting data to another matrix. Because matrices are tensors and the data flows from one to another, you can see where the TensorFlow name comes from. TensorFlow is one of the best-supported application frameworks with APIs (application programming interfaces) gpt Python, C++, Haskell, Java, Go, Rust, and there's also a third-party package for R called tensorflow. Installing the TensorFlow Python library For Windows, Linux, and Raspberry Pi, check out the official TensorFlow link. TensorFlow is a typical Python3 library and API (applications programming interface). TensorFlow has a lot of dependencies that will be also installed by following the tutorial referenced above.

View Article
How to Import Python Modules

Article / Updated 09-25-2019

You'll hear the word module used in conjunction with Python all the time. If you think of the Python standard library as an actual physical library, and a package as being, perhaps, one book in that library, then you can think of a Python module as being one chapter in one book. In other words, a package may contain many modules, and a library may contain many packages. The module is a big part of what makes Python a modular language, because code is grouped together according to function. So in the one hand, you don’t have to import everything including the kitchen sink to use some code. By the same token, if you need to use several related things, such as functions for working with dates and times, you don’t have to import them all one at a time. Typically, importing just the whole module will get you what you need. For example, to work with dates and times, you don’t have to import every Python module out there. Nor do you need to import every possible little function and object one at a time. You just import the whole module, like datetime, to get lots of handy things for working with dates and times. There are actually a few ways to import functionality from modules. One of the most common is to simply import the whole Python module. To do that, you just follow the import command with the name of the Python module you want to import. For example, this imports the entire math module, which has lots of functions and stuff for doing math: import math After you import a Python module, the dir() and help() functions work on that too. For example, if you tried doing dir(math) or help(math) before import math, you'd get an error. That’s because that math package isn’t part of the standard library. However, if you do import math first, and then help(math), then it all works. There may be times where you don't really need the whole kit-and-caboodle. In those cases, you can import just what you need using a syntax like this: from math import pi In this example, you’re just importing one thing (pi), so you’re not bringing in unnecessary stuff. The second example is also handy because in your code you can refer to pi as just pi, you don't have to use math.pi. Here is some stuff you can try at the Python prompt, such as in a VS Code Terminal window, to see for yourself: Enter the command print(pi) and press Enter. Most likely you'll get an error that reads: NameError: name 'pi' is not defined In other words, pi isn’t part of the standard library that’s always available to your Python code. To use it, you have to import the math module. There are two ways to do that. You can import the whole thing by typing this at the Python prompt: import math But if you do that and then enter print(pi) … you'll get the same error again, even though you imported the math package. The reason for that is when you import an entire Python module and you want to use a part of it, you have to precede the part you want to use with the name of the module and a dot. For example, if you enter this command: print(math.pi) … you get the correct answer: 3.141592653589793 Be aware that when you import just part of a Python module, the help() and dir() functions for the whole module won't work. For example, if you’ve only executed from math import pi in your code and you attempt to execute a dir(math) or help(math) function, it won't work, because Python doesn’t have the entire module at its disposal. It only has at its disposal that which you imported, pi in this example. Usually help() and dir() are just things you use at the Python prompt for a quick lookup. They're not the kinds of things you’re likely to use when actually writing an app. So using from rather than import is actually more efficient because you're only bringing in what you need. As an added bonus, you don’t have to precede the function name with the module name and a dot. For example, when you import only pi from the math module, like this: from math import pi Then you can refer to pi in your code is simply pi, not math.pi. In other words, if you execute this function: print(pi) … you'll get the right answer: 3.141592653589793 This is because Python now “knows” of pi as being the thing named pi from the math module; you don't have to specifically tell it to use math.pi. You can also import multiple items from a package by listing their names, separated by commas, at the end of the from … command. For example, suppose you need pi and square roots in your app. You could import just those into your app using this syntax: from math import pi, sqrt Once again, because you used the from syntax for the import, you can refer to pi and sqrt() in your code by name without the leading module name. For example, after executing that from statement, this code: print(sqrt(pi)) … displays 1.7724538509055159 … which, as you may have guessed, is the square root of the number pi. You may also notice people importing a Python module like this: from math import * The asterisk is short for “everything.” So in essence, that command is exactly the same as import math, which also imports the entire math module. But this is a subtle difference: When you do from math import * you associate the name of everything in the math module with that Python module. So you can use those names without the math. prefix. In other words, after you execute this: from math import *<?pre> … you can do a command like print(pi) and it will work, even without using print(math.pi). Although it does seem like a smart and convenient thing to do, many Python programmers think that sort of thing isn't very Pythonic. If you’re importing lots of Python modules and using lots of different pieces of each, avoiding module names in code can make it harder for other programmers to read and make sense of that code. So although in a Zen of Python sense it may be frowned upon, technically it works and is an option for you.

View Article