<jupyter_start><jupyter_text>Class 4C: Introduction to Programming in PythonWe will begin soon! Until then, feel free to use the chat to socialize, and enjoy the music!             Photo by <NAME> from Pexels     October 1, 2021     <NAME>  Class Outline:- Digging Deeper into Python syntax    - Announcements (5 min)        - Thursday labs will be cancelled this week (Nat'l day of truth and reconciliation)        - Project 1 Milestone Feedback has now been released        - Project Details are also released        - Test details            - Test 1 will be from Friday 6 PM - Sunday 6 PM (48 hour window)            - You can start the test at any time during this window            - You will have 1 hour to do the test (Canvas Quiz)            - Content: Terminal & Git commands & Markdown syntax        - Gradescope and finding your grades    - Lists and tuples (15 min)    - String methods (5 min)    - Dictionaries (10 min)    - Conditionals (10 min)      Lists and Tuples- Lists and tuples allow us to store multiple things ("elements") in a single object.- The elements are _ordered_.<jupyter_code>my_list = [1, 2, "THREE", 4, 0.5]
print(my_list)
type(my_list)<jupyter_output><empty_output><jupyter_text>You can get the length of the list with `len`:<jupyter_code>len(my_list)
today = (1, 2, "THREE", 4, 0.5)
print(today)
type(today)
len(today)<jupyter_output><empty_output><jupyter_text>Indexing and Slicing Sequences- We can access values inside a list, tuple, or string using the bracket syntax. - Python uses zero-based indexing, which means the first element of the list is in position 0, not position 1.<jupyter_code>my_list
my_list[0]
my_list[4]
my_list[5]
today[4]<jupyter_output><empty_output><jupyter_text>We use negative indices to count backwards from the end of the list.<jupyter_code>my_list
my_list[-1]
my_list[len(my_list)-1]<jupyter_output><empty_output><jupyter_text>We use the colon `:` to access a subsequence. This is called "slicing".<jupyter_code>my_list[1: ]
my_list[1:3]<jupyter_output><empty_output><jupyter_text>- Above: note that the start is inclusive and the end is exclusive.- So `my_list[1:3]` fetches elements 1 and 2, but not 3.- In other words, it gets the 2nd and 3rd elements in the list. We can omit the start or end:<jupyter_code>my_list[0:3]
my_list[:3]
my_list[3:]
my_list[:] # *almost* same as my_list - more details next week (we might not, just a convenience thing)<jupyter_output><empty_output><jupyter_text>Strings behave the same as lists and tuples when it comes to indexing and slicing.<jupyter_code>alphabet = "abcdefghijklmnopqrstuvwyz"
alphabet[0]
alphabet[-1]
alphabet[-3]
alphabet[:5]
alphabet[12:20]<jupyter_output><empty_output><jupyter_text>List Methods (Functions)- A list is an object and it has methods for interacting with its data. - For example, `list.append(item)` appends an item to the end of the list. - See the documentation for more [list methods](https://docs.python.org/3/tutorial/datastructures.htmlmore-on-lists).<jupyter_code>primes = [2,3,5,7,11]
primes
len(primes)
primes.append(13)
primes
len(primes)
max(primes)
min(primes)
sum(primes)
my_list
my_list = [1, 2, 'THREE', 4, 0.5]
my_list.append(primes)
#my_list.extend(primes)
my_list
my_list[-1][-1]
[1,2,3] + ["Hello", 7]<jupyter_output><empty_output><jupyter_text>Mutable vs. Immutable Types- Strings and tuples are **immutable** types which means they cannot be modified. - Lists are **mutable** and we can assign new values for its various entries. - This is the main difference between lists and tuples.<jupyter_code>names_list = ["Indiana","Fang","Linsey"]
names_list
names_list[0] = "<NAME>y"
names_list
names_tuple = ("Indiana","Fang","Linsey")
names_tuple
names_tuple[0] = "Not cool guy"<jupyter_output><empty_output><jupyter_text>Same goes for strings. Once defined we cannot modifiy the characters of the string.<jupyter_code>my_name = "Firas"
my_name[-1] = 'q'
x = ([1,2,3],5)
x[1] = 7
x
x[0][1] = 4
x<jupyter_output><empty_output><jupyter_text>String Methods- There are various useful string methods in Python.<jupyter_code>all_caps = "HOW ARE YOU TODAY?"
print(all_caps)
new_str = all_caps.lower()
new_str<jupyter_output><empty_output><jupyter_text>Note that the method lower doesn't change the original string but rather returns a new one.<jupyter_code>all_caps<jupyter_output><empty_output><jupyter_text>There are *many* string methods. Check out the [documentation](https://docs.python.org/3/library/stdtypes.htmlstring-methods).<jupyter_code>all_caps.split()
all_caps.split()[3]
all_caps.count("O")<jupyter_output><empty_output><jupyter_text>One can explicitly cast a string to a list:<jupyter_code>caps_list = list(all_caps)
caps_list
len(all_caps)
all_caps = all_caps + 'O' + 'o' 
all_caps
all_caps.count('O')
len(caps_list)<jupyter_output><empty_output><jupyter_text>String formatting- Python has ways of creating strings by "filling in the blanks" and formatting them nicely. - There are a few ways of doing this. See [here](https://realpython.com/python-string-formatting/) and [here](https://stackoverflow.com/questions/5082452/string-formatting-vs-format) for some discussion.- F-Strings are the NEW and RECOMMENDED way of doing string formatting  F-Strings (aka magic)New formatting style (see [this article](https://realpython.com/python-f-strings/f-strings-a-new-and-improved-way-to-format-strings-in-python)):<jupyter_code>name = "Sasha"
age = 4

template_new = f"Hello, my name is {name}. I am {age} years old."
template_new<jupyter_output><empty_output><jupyter_text>DictionariesA dictionary is a mapping between key-values pairs.  Reminders: Bracket Notation- CURLY Brackets `{}` : create dictionaries- ROUND Brackets `()` : create tuples ; also use functions this way- SQUARE Brackets `[]`: create lists  ; also index/slice this way<jupyter_code>house = {'bedrooms': 3, 
         'bathrooms': 2, 
         'city': 'Vancouver', 
         'price': 2499999, 
         'date_sold': (1,3,2015)}

condo = {'bedrooms' : 2, 
         'bathrooms': 1, 
         'city'     : 'Burnaby', 
         'price'    : 899999, 
         'date_sold': (27,8,2011)
        }<jupyter_output><empty_output><jupyter_text>We can access a specific field of a dictionary with square brackets:<jupyter_code>house['price']
condo['price']
condo['city']<jupyter_output><empty_output><jupyter_text>We can also edit dictionaries (they are mutable):<jupyter_code>condo['price'] = 5 # price already in the dict
condo
condo['flooring'] = "wood"
condo<jupyter_output><empty_output><jupyter_text>A sometimes useful trick about default values:<jupyter_code>condo["bedrooms"]<jupyter_output><empty_output><jupyter_text>is shorthand for<jupyter_code>condo.get("bedrooms")<jupyter_output><empty_output><jupyter_text>With this syntax you can also use default values:<jupyter_code>condo.get("bedrooms", "unknown")
condo.get("fireplaces", "unknown")<jupyter_output><empty_output><jupyter_text>Empties<jupyter_code>lst = list() # empty list
lst
lst = [] # empty list
lst
tup = tuple() # empty tuple
tup
tup = () # empty tuple
tup
dic = dict() # empty dict
dic
dic = {} # empty dict
dic
st = set() # emtpy set
st<jupyter_output><empty_output><jupyter_text>Conditionals - [Conditional statements](https://docs.python.org/3/tutorial/controlflow.html) allow us to write programs where only certain blocks of code are executed depending on the state of the program. - Let's look at some examples and take note of the keywords, syntax and indentation. - Check out the [Python documentation](https://docs.python.org/3/tutorial/controlflow.html) and [Think Python (Chapter 5)](http://greenteapress.com/thinkpython/html/thinkpython006.html) for more information about conditional execution.<jupyter_code>name = "firas"

if name.lower() == 'firas':
    print("That's my name too!")
elif name.lower() == 'santa':
    print("That's a fun name.")
else:
    print(f"Hello {name}! That's a cool name.")

    print('Nice to meet you!')
name = input("What's your name?")

if name.lower() == 'firas':
    print("That's my name too!")
elif name.lower() == 'santa':
    print("That's a fun name.")
else:
    print(f"Hello {name}! That's a cool name.")

    print('Nice to meet you!')
bool(None)<jupyter_output><empty_output><jupyter_text>The main points to notice:* Use keywords `if`, `elif` and `else`* The colon `:` ends each conditional expression* Indentation (by 4 empty space) defines code blocks* In an `if` statement, the first block whose conditional statement returns `True` is executed and the program exits the `if` block* `if` statements don't necessarily need `elif` or `else`* `elif` lets us check several conditions* `else` lets us evaluate a default block if all other conditions are `False`* the end of the entire `if` statement is where the indentation returns to the same level as the first `if` keyword If statements can also be **nested** inside of one another:<jupyter_code>name = input("What's your name?")

if name.lower() == 'mike':
    print("That's my name too!")
elif name.lower() == 'santa':
    print("That's a funny name.")
else:
    print("Hello {0}! That's a cool name.".format(name))
    if name.lower().startswith("super"):
        print("Do you have superpowers?")

print('Nice to meet you!')<jupyter_output><empty_output><jupyter_text>Preview of next week: loading data with Pandas  Introducing DataFrames At the very basic level, Pandas objects can be thought of as enhanced versions of NumPy structured arrays in which the rows and columns are identified with labels rather than simple integer indices.As we will see during the course of this chapter, Pandas provides a host of useful tools, methods, and functionality on top of the basic data structures, but nearly everything that follows will require an understanding of what these structures are.Thus, before we go any further, let's introduce these three fundamental Pandas data structures: the ``Series``, ``DataFrame``, and ``Index``.We will start our code sessions with the standard NumPy and Pandas imports:```import numpy as npimport pandas as pd``` The fundamental structure in Pandas is the ``DataFrame``.Like the ``Series`` object discussed in the previous section, the ``DataFrame`` can be thought of either as a generalization of a NumPy array, or as a specialization of a Python dictionary.We'll now take a look at each of these perspectives.  Creating a DataFrameThere are several ways of creating DataFrames in Python using Pandas and though it can end up with the same end product, the method of creating them can depend on the format of your data.Let's look at a few examples:  DataFrame from URLIf your dataset exists on the web as a publicly accessible file, you can create a DataFrame directly from the URL to the CSV.- `read_csv(path)` is a function from the Pandas package that creates a DataFrame from a CSV file.     - The argument `path` can be a URL or a reference to a local file.<jupyter_code>import pandas as pd
pd.read_csv("https://github.com/firasm/bits/raw/master/fruits.csv")<jupyter_output><empty_output><jupyter_text>I can store the dataframe as an object like this:<jupyter_code>fruits = pd.read_csv("https://github.com/firasm/bits/raw/master/fruits.csv")

fruits<jupyter_output><empty_output><jupyter_text>Attribution*This notebook contains an excerpt from the [Python Data Science Handbook](http://shop.oreilly.com/product/0636920034919.do) by <NAME>; the content is available [on GitHub](https://github.com/jakevdp/PythonDataScienceHandbook).**The text is released under the [CC-BY-NC-ND license](https://creativecommons.org/licenses/by-nc-nd/3.0/us/legalcode), and code is released under the [MIT license](https://opensource.org/licenses/MIT). If you find this content useful, please consider supporting the work by [buying the book](http://shop.oreilly.com/product/0636920034919.do)!*  That's it!You're done for today!See you next class.  Extra Stuff  Inline if/else<jupyter_code>words = ["the", "list", "of", "words"]

x = "long list" if len(words) > 10 else "short list"
x
if len(words) > 10:
    x = "long list"
else:
    x = "short list"
x<jupyter_output><empty_output><jupyter_text>Sets- Another built-in Python data type is the `set`, which stores an _un-ordered_ list of _unique_ items.<jupyter_code>s = {2,3,5,5,11}
s
{1,2,3} == {3,2,1}
[1,2,3] == [3,2,1]
s.add(2) # does nothing
s
s[0]<jupyter_output><empty_output><jupyter_text>Above: throws an error because elements are not ordered.<jupyter_code>st = {} # NOT an empty set!
type(st)
st = {1}
type(st)<jupyter_output><empty_output><jupyter_text>Deleting fields in dictionaries We can delete fields entirely (though I rarely use this):<jupyter_code>del condo["city"]
condo
condo[5] = 443345
condo
condo[(1,2,3)] = 777
condo
condo["nothere"]
## RISE settings 

from IPython.display import IFrame

from traitlets.config.manager import BaseJSONConfigManager
from pathlib import Path
path = Path.home() / ".jupyter" / "nbconfig"
cm = BaseJSONConfigManager(config_dir=str(path))
tmp = cm.update(
        "rise",
        {
            "theme": "sky", #blood is dark, nice
            "transition": "fade",
            "start_slideshow_at": "selected",
            "autolaunch": False,
            "width": "100%",
            "height": "100%",
            "header": "",
            "footer":"",
            "scroll": True,
            "enable_chalkboard": True,
            "slideNumber": True,
            "center": False,
            "controlsLayout": "edges",
            "slideNumber": True,
            "hash": True,
        }
    )<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11438896673796002, 'fraction_numerical': 0.015782874843277526, 'mean_word_length': 4.7481983891479445, 'pattern_counts': {'":': 15, '<': 125, '<?xml version=': 0, '>': 127, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '30', 'dir': 'jupyter-structured-clean-dedup', 'id': '387396', 'license': 'MIT', 'n_tokens_mistral': 4537, 'n_tokens_neox': 4304, 'n_words': 1445, 'path': 'notes/week04/Class4C/Class4C.ipynb', 'repo_name': 'ubco-cmps/data301_course', 'size': '13586'}