<jupyter_start><jupyter_text>OBJECTIVEThis is a brief introduction to Jupyter notebooks and the basics of Python. There is so much more to both of these but this will get you off and running.  JUPYTER OVERVIEW Key concepts:* Key uses of Jupyter notebooks* When not to use* Sequential process: the good and the bad* Brief tour ---  MARKDOWN Here's a [link](https://dziganto.github.io/) to my blog. Let's **bold** some text. How about *italicize*. A picture? ![elmhurst college](http://static.panoramio.com/photos/large/61667921.jpg) Here's a **bulleted** list:* sub-bullet 1* sub-bullet 2* sub-bullet 3 Here's a **numbered** list:1. item 12. item 23. item 3 A little LaTeX: $e^{{i}{\pi}} + 1 = 0$ $$\frac{df}{dt} = \lim_{h \to 0} \frac{f(t+h)-f(t)}{h}$$ Lastly, let's include a gif:![Gif](https://media.giphy.com/media/Cm61Cmevc70Va/giphy.gif) ---<jupyter_code># Writing code
import this<jupyter_output>The Zen of Python, by <NAME>

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!<jupyter_text>---  PRINT<jupyter_code>print('This is a sentence.')
print("Here's a sentence with an apostrophe. Notice the double quotes around these sentences.")
print('Here is a quote:\n\n"Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal."')
print('Multiple')
print('print')
print('statements')
print('in')
print('one')
print('cell')<jupyter_output>Multiple
print
statements
in
one
cell<jupyter_text>---  COMMAND LINE<jupyter_code># python version
! python -V
# python path
! which python<jupyter_output>/Users/davidziganto/anaconda/bin/python<jupyter_text>---  NAMESPACE<jupyter_code>who # check variables and modules loaded into memory
whos # like 'who' but easier to read<jupyter_output>No variables match your requested type.<jupyter_text>We'll use *who* and *whos* again shortly. For now, just know what they are. ---  LOOPS  1) For Loop<jupyter_code>for i in range(10):
    print(i)
for i in range(3):
    print("i:{}".format(i))
    for j in range(1,3):
        print(" j:{}".format(j))<jupyter_output>i:0
 j:1
 j:2
i:1
 j:1
 j:2
i:2
 j:1
 j:2<jupyter_text>2) While Loop<jupyter_code>count = 1
while count <= 10:
    print('count|' * count)
    count += 1
else:
    print('\nThe End!')<jupyter_output>count|
count|count|
count|count|count|
count|count|count|count|
count|count|count|count|count|
count|count|count|count|count|count|
count|count|count|count|count|count|count|
count|count|count|count|count|count|count|count|
count|count|count|count|count|count|count|count|count|
count|count|count|count|count|count|count|count|count|count|

The End!<jupyter_text>---  CONDITIONAL STATEMENTS<jupyter_code>indicator = True
if indicator == True:
    print('Yay, the indicator is true!')
else:
    print('Nothing to see here. Move along.')
# same as above but Python defaults to True so no need to set equal to True
indicator = True
if indicator:
    print('Yay, the indicator is true!')
else:
    print('Nothing to see here. Move along.')
indicator = False
if indicator == True:
    print('Yay, the indicator is true!')
else:
    print('Nothing to see here. Move along.')<jupyter_output>Nothing to see here. Move along.<jupyter_text>Tangent: Truthiness<jupyter_code>indicator == True
indicator == False
indicator != False
True == 1
indicator == 1<jupyter_output><empty_output><jupyter_text>**[Your Turn]**Experiment to see which values are True and which False.<jupyter_code>indicator = 2
if indicator:
    print('Yay, the indicator is true!')
else:
    print('Nothing to see here. Move along.')<jupyter_output>Yay, the indicator is true!<jupyter_text>---  FUNCTIONS<jupyter_code>def print_function():
    '''this function prints 'hello world'.'''
    print('hello world')
print_function()
def print_input(text):
    '''this function prints the user's text.'''
    # error handling
    assert type(text) == str, "you must input text in string format!"
    print(text)
print_input('hi there')
print_input(21)
def print_input2(text):
    '''this function prints the user's text.'''
    # error handling
    if type(text) != str:
        text = str(text)
    assert type(text) == str, "wrong format!" # just to prove a point
    print(type(text))
print_input2(21)
def square_num(num):
    '''this function takes a number called num and square it.'''
    return num ** 2
x = square_num(4)
x
square_num(10)<jupyter_output><empty_output><jupyter_text>[Your Turn]Write a function called **fizzbuzz** that returns 'fizz' if a number is divisible by 3, 'buzz' if divisible by 5, 'fizzbuzz' if divisible by 15, or the number otherwise. Allow the user to input a number.<jupyter_code>def fizzbuzz(num):
    '''classic fizzbuzz function.'''
    # insert your code below
    if num % 3 == 0:
        return 'fizz'
    elif num % 5 == 0:
        return 'buzz'
# test your function with this code
for i in range(21):
    print(i, fizzbuzz(i))<jupyter_output>0 fizz
1 None
2 None
3 fizz
4 None
5 buzz
6 fizz
7 None
8 None
9 fizz
10 buzz
11 None
12 fizz
13 None
14 None
15 fizz
16 None
17 None
18 fizz
19 None
20 buzz<jupyter_text>DATA STRUCTURES  1) LIST* Mutable  * Mixed-typeLists are ordered sets of objects. They are powerful, flexible, and one of the most widely used data structures in all of Python.<jupyter_code>mylist = [99, 'text', 3.14159]
mylist
# print list items (BAD WAY - DON'T EVER DO THIS!!!)
for i in range(len(mylist)):
    print(mylist[i])
# Pythonic way to print list items
for item in mylist:
    print(item)
# enumerate if you need item AND index value
for i, item in enumerate(mylist):
    print('i: {} | item: {}'.format(i, item))
# you can set starting index
for i, item in enumerate(mylist, 1):
    print('i: {} | item: {}'.format(i, item))
# append to list
mylist.append('new text')
mylist
# delete 2nd item
mylist.pop(1)
mylist
# delete last item
mylist.pop()
mylist
# update value of 2nd item
mylist[1] = 2.71828
mylist<jupyter_output><empty_output><jupyter_text>[Your Turn] Create a list called **alphanums** that is composed of lists. Specifically, make a list of the letters **A-E** with corresponding location in alphabet. Example: **['A', 1], ['B', 2]**. Iterate over this list of lists returning only the letters from each sublist.  LIST COMPREHENSION w/even numbers<jupyter_code># typical list with for loop and if statement
mylist2 = []
for i in range(10):
    if i%2 == 0:
        mylist2.append(i)
mylist2
mylist3 = [i for i in range(10) if i%2 == 0]
mylist3
# check if same values
mylist2 == mylist3
# check if same object
mylist2 is mylist3<jupyter_output><empty_output><jupyter_text>[Your Turn - Advanced Fizzbuzz (Optional)] Can you write a list expression that returns 'fizz' if a number is divisible by 3, 'buzz' if divisible by 5, 'fizzbuzz' if divisible by 15, or the number otherwise? Do this for numbers 1-20.<jupyter_code>['fizzbuzz' if i%15==0 else 'fizz' if i%3==0 else 'buzz' if i%5==0 else i for i in range(1, 21)]<jupyter_output><empty_output><jupyter_text>1b) GENERATOR COMPREHENSION - Memory Efficient<jupyter_code># generator version of fizzbuzz
def fizzbuzz_gen():
    i = 1
    while True:
        if i%15 == 0:
            yield 'fizzbuzz'
        elif i%5 == 0:
            yield 'buzz'
        elif i%3 == 0:
            yield 'fizz'
        else:
            yield i
        i += 1
fbg = fizzbuzz_gen()
type(fbg)
for _ in range(21):
    print(next(fbg))<jupyter_output>1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz<jupyter_text>2) TUPLE * Immutable* Mixed-typeTuples are often described as immutable lists. Because tuples are immutable they are often faster than lists. Tuples are perfect if you want to ensure the values don't change too. So if you're looking for flexibility, go with a list. Otherwise, go with a tuple.<jupyter_code>myfirstuple = (99, 'text', 3.14159)
myfirstuple
myfirstuple[1]
myfirstuple[1] = 0<jupyter_output><empty_output><jupyter_text>--- Let's check our namespace now.<jupyter_code>whos
# delete something from namespace
del indicator
whos
# delete multiple items
del i,j
whos<jupyter_output>Variable         Type         Data/Info
---------------------------------------
count            int          11
fbg              generator    <generator object fizzbuzz_gen at 0x1055474c0>
fizzbuzz         function     <function fizzbuzz at 0x105578950>
fizzbuzz_gen     function     <function fizzbuzz_gen at 0x104280488>
item             float        3.14159
myfirstuple      tuple        n=3
mylist           list         n=2
mylist2          list         n=5
mylist3          list         n=5
print_function   function     <function print_function at 0x1055061e0>
print_input      function     <function print_input at 0x1054f4d08>
print_input2     function     <function print_input2 at 0x1055780d0>
square_num       function     <function square_num at 0x105578400>
this             module       <module 'this' from '/Use<...>a/lib/python3.5/this.py'>
x                int          16<jupyter_text>---  3) DICTIONARY * Keys are immutable* Values are mutable* Keys mapped to values via hashing* Incredibly fast lookups (constant time)* Significant memory overhead (to store hash table)Dictionaries are unordered sets. Items in a dictionary are accessed via keys (not by index as in a list). Each key of the dictionary must be immutable and is mapped to a value. The values of a dictionary can be any Python data type. In other words, dictionaries are unordered key-value pairs.<jupyter_code>mydict = {'a':1, 'b':2, 'c':['apple', 'orange', 'banana']}
mydict
mydict['a']
mydict['c']
mydict['c'][1]
# slicing from index to end
mydict['c'][1:]
# slicing from start to index
mydict['c'][:1]
# dictionary comprehension
mydict2 = {key: i**2 for key, i in zip(list('ABCDE'), range(5))}
mydict2<jupyter_output><empty_output><jupyter_text>4) SET * Mutable* Unique values* Great for testing membershipA set is an ordered collection of unique and immutable objects. It's highly optimized for testing membership. So if you're thinking about using "in" to test membership, think again - sets are much, much faster!<jupyter_code>list_of_duplicates = [1, 2, 2, 2, 3, 4, 5, 5]
list_of_duplicates
2 in list_of_duplicates
myset = set(list_of_duplicates)
myset
2 in myset<jupyter_output><empty_output><jupyter_text>ARRAYS & NUMPY * Mutable* Single-type* Fast loading/savingAn array is much more efficient than a list if you're only looking to store a single object type like an integer, float, or string.<jupyter_code>import numpy as np
myfirstarray = np.arange(101)
myfirstarray
# vectorized version of even numbers (FAST!!!)
myfirstarray[myfirstarray%2 == 0]
# vectorized version of numbers between 25 and 75 exclusive (FAST!!!)
myfirstarray[(myfirstarray>25) & (myfirstarray<75)]
# vectorized version of even numbers between 25 and 75 exclusive (FAST!!!)
myfirstarray[(myfirstarray>25) & (myfirstarray<75) & (myfirstarray%2==0)]
np.random.seed(42)
matrix = np.random.randint(low=1, high=100, size=100).reshape(25,4)
matrix
matrix.shape<jupyter_output><empty_output><jupyter_text>TIMEIT A quick and easy way to test how long code takes to run.<jupyter_code>testlist = list(range(int(1e6)))
len(testlist)
testarray = np.arange(1e6)
testarray.shape
%%timeit
[i for i in testlist if i%2==0]
%%timeit
testarray[testarray%2==0]<jupyter_output>13.5 ms ± 206 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
{'fraction_non_alphanumeric': 0.10936987200525107, 'fraction_numerical': 0.02912701017394158, 'mean_word_length': 4.226843910806175, 'pattern_counts': {'":': 0, '<': 86, '<?xml version=': 0, '>': 85, 'https://': 2, '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': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '462911', 'license': 'MIT', 'n_tokens_mistral': 4272, 'n_tokens_neox': 4033, 'n_words': 1456, 'path': 'notebooks/Python/Demos/Python_101_Student.ipynb', 'repo_name': 'ashishpatel26/Data_Science_Fundamentals', 'size': '12192'}