Programming

Buisness Analytics

Table of Contents

Focus on understanding the Ideas. Your understanding of the Syntax will develop with time & practice

Python

  • Python is one way we can use a computer to perform certain tasks
  • For example, say we wanted to know the following:
3 + 4 = ?
  • Hopefully it is faster for us to do this in our head!
  • Python code is a series of steps that the computer executes (quote: LYAH)
  • Let's say that we wanted to know what the marginal value of an additional dollar saved was in four years times if compounded monthly at an annual 8% rate?

Do not worry about understanding what this code does for the moment!

  • Or let's say we want to understand how this varies with the underlying interest rate?

Still don't worry about understanding what this code does for the moment!

Takeaways

(1) We can use Python to Solve Problems

(2) Via Python, we can use other peoples' work to solve our problems

  • We don't have to write code to differentiate a function! We can rely on the smart folks at Google who have done this for us

(3) Via Python, we can solve a problem by 

  • Splitting the solution into components
  • Writing code/ using other people's code for each component
  • "Re-stacking" these components

Variables

Creating Variables

first_name = 'Lebron'
last_name = 'James'
print(first_name + ' ' + last_name)
a = 5 
b = 10 
print(a + b)
  • The '=' is used to assign a variable to a value

Integers

String (text!)

Creating Variables

  • Variables are mutable -- meaning that we can assign a variable to another value
a = 5 
b = 10 
a = 25
print(a + b)

Integers

first_name = 'Lebron'
last_name = 'James'
first_name = 'Bronny'
print(first_name + ' ' + last_name)

String (text!)

Deep Dive

What happens when we do the following?

a = 5 
import sys

a = 10
memory_location = id(a)
size_in_bytes = sys.getsizeof(a)

print(f"Memory location of a: {memory_location}")
print(f"Size of a: {size_in_bytes} bytes")
5

a

Memory

What happens when we do the following?

a = 5 
b = 5
a = 5 
b = 5 

print(f"Memory location of a: {id(a)}")
print(f"Memory location of b: {id(b)}")
print(a is b) 
print(a == b)
5

a

Memory

b

What happens when we do the following?

a = 257 
b = 257
a = 257 
b = 257 

print(f"Memory location of a: {id(a)}")
print(f"Memory location of b: {id(b)}")
print(a is b) 
print(a==b)
257

a

Memory

b

257

What happens when we do the following?

a = 257 
b = a 
a = 10
257

a

Memory

a = 257 
a = 257 
b = a
10
257

a

Memory

257

a

Memory

b

a = 257 
b = a
a = 257 
b = a
a = 10
257

a

Memory

b

10
257

a

Memory

b

10

Functions

Defining/Creating a Function

x \longmapsto x^2
def f(x):
  return x**2

(1) The `def' keyword tells us that we are defining a function

(2) `f' is the name of the function

(3) `x' is a placeholder for the input to the function

(4) The `:' indicates the beginning of a code block (in this context)

(5) The `return' keyword indicates what the function will return

  • The key word is knows. That's literally it. You may be initially surprised when you execute the code block that nothing else happens. But in Python's defense, you haven't told it to do anything else
def f(x):
  return x**2
  • When you write and then execute the following block of code, Python knows that a function named `f' exists, and it knows that given an input, it will attempt to square that input
  • There are really only two steps to working with a function

Working With Functions

  • We have to define the function. We have to tell python about the function: give it a name, express how the input(s) get transformed. 
def f(x):
  return x**2
  • We have to call the function. Calling a function on a given input will produce the output
x = 2
f(x)
>> 4

Deep Dive

  • Mathematical Functions transform "data"

What Do Mathematical Functions Do?

  • Given an x, it returns the corresponding y
\mathcal{X}
\mathcal{Y}
\mathcal{f}

Domain

Codomain

  • Functions transform "data"

Functions on the Computer

  • Given an x, it may (1) change the state of the system and (2) may return a value or None  (3) may return a different value each time it's called
\mathcal{X}
\mathcal{Y}
\mathcal{f}

Domain

Codomain

\cup \ \{\textrm{None} \}

Example # 1

def greeting(name):
  print("Hello " + name)
  
a = greeting('Bob')
print(a)
  • It changes the state of the system by printing a response
  • It returns `None'

Example # 2

def random_wage(avg_wage):
  return avg_wage * (1 + np.random.normal(0, 0.1))


a = random_wage(10)
b = random_wage(10)
print(a)
print(b)
  • It returns a different value for the same input each time you call it

Example # 3

a = 10 

def greeting(name):
  global a 
  a = 20 
  print("Hello " + name)

print(a)
greeting("Bob")
print(a)
  • It changes the state of the system by (1) changing the value of `a' and (2) printing a response

For Loops

Let's Say We Have the Following Code

my_list = [0, 1, 2, 3, 4, 5]

def f(x):
  return x**2

Task:

Print the square of each element in this list

Naive Approach

my_list = [0, 1, 2, 3, 4, 5]

def f(x):
  return x**2

print(f(my_list[0]))
print(f(my_list[1]))
print(f(my_list[2]))
print(f(my_list[3]))
print(f(my_list[4]))
print(f(my_list[5]))

Redundant!

  • We are calling the same "pair" of functions 6 times
  • The only thing that changes between functions calls is the input!

Indexing

For Loop #1

def f(x):
  return x**2

my_list = [0, 1, 2, 3, 4, 5]


for i in my_list:
  print(f(i))

"Easier" to write & read!

  • It tells us that for each element of `my_list', apply `f' to that element and print the result
(\textrm{time step} = 0)
i = 0 
print(f(i))
>> 0
(\textrm{time step} = 1)
i = 1 
print(f(i))
>> 1
(\textrm{time step} = 2)
i = 2 
print(f(i))
>> 4
(\textrm{time step} = 3)
i = 3 
print(f(i))
>> 9
(\textrm{time step} = 4)
i = 4 
print(f(i))
>> 16
(\textrm{time step} = 5)
i = 5 
print(f(i))
>> 25

Python

For Loop #2

def f(x):
  return x**2

my_list = [0, 1, 2, 3, 4, 5]

my_list_squared = []

for i in my_list:
  my_list_squared.append(f(i))

Create empty list

For each element of `my_list`, apply `f` to the element and then include the result as the last element of `my_list_squared`

For Loop #3

In Class Exercise: Given a list, print the square of only the even numbers

my_list = [0, 1, 2, 3, 4, 5]

def f(x):
  return x**2

for i in my_list:
  if i % 2 == 0:
  	print(f(i))

For Loop #4

In Class Exercise: Given a list, print the square of the even numbers and the cube of the odd numbers

my_list = [0, 1, 2, 3, 4, 5]

def f(x):
  return x**2

def g(x):
  return x**3

for i in my_list:
  if i % 2 == 0:
  	print(f(i))
  else:
    print(g(i))

For Loop #5

In Class Exercise: Given a list (could be a list of integers and/or strings), if it is an even number: print the square, if it is an odd number: print the cube, and if it is a string: print '!'

def f(x):
  return x**2 

def g(x):
  return x**3


my_list = ["a", 1, 0, "b", 27, 9]

for x in my_list:
  if type(x) == str:
    print("!")
  elif x % 2 == 0:
    print(f(x))
  elif x % 2 == 1:
    print(g(x))

For Loop #6

In Class Exercise: Given a list of strings find the first element which begins with the letter 'a'

my_list = ['car', 'boat', 'airplane', 'truck']

for i in my_list:
  if i[0] == 'a':
    print(i)
    break

Data Types

In Class Exercise: The following code doesn't work. Explain why

def f(x):
  return x**2 

def g(x):
  return x**3


my_list = ["a", 1, 0, "b", 27, 9]

for x in my_list:
  if x % 2 == 0:
    print(f(x))
  elif x % 2 == 1:
    print(g(x))
  else:
    print("!")

Original Code

def f(x):
  return x**2 

def g(x):
  return x**3


my_list = ["a", 1, 0, "b", 27, 9]

for x in my_list:
  if type(x) == str:
    print("!")
  elif x % 2 == 0:
    print(f(x))
  elif x % 2 == 1:
    print(g(x))

Adjusted Code

Data Types

  • A data type is a set of values

Integer (Int)

a = 1 
b = 10 
c = -8

String

a = 'Lebron' 
b = 'Bronny'
c = 'James'

Float

a = 1.0 
b = 10.2
c = -8.7

Boolean (Bool)

a = True
b = False 

Function

Same Function, Different Types

Data Types

1 + 2

Int

1.4 + 2.7

Float

True + False
>> 1

Bool

'Lebron ' + 'James'

String

Data Types

Int

Float

Bool

String

def add_one(x): 
  return x + 1

In Class Exercise: Write a function that adds one to the input 

Errors

Data Types

Int

Float

Bool

String

def add_one(x : int) -> int: 
  return x + 1

We can use Type Hints to inform the user (our future selves) of the type of inputs that our function takes and the type of output it produces

Input Type

Output Type

Data Types

Int

Float

Bool

String

In Class Exercise: Using type hints, write a function that takes an integer and a string as inputs and prints the string the number of times that the integer specifies. Include spaces!

def repeat_string(x : int, y : str) -> None:
  print((y + ' ')*x)

Type Casting

Int

Float

int(2.0)

Int

Float

float(25)
import jax 

def f(x):
  return x**2

jax.grad(f)(1)

Type Error

import jax 

def f(x):
  return x**2

jax.grad(f)(float(1))

Type Casting

Type Casting

Int

Bool

int(True)

String

Float

float('25')

Infix Functions

'Lebron ' > 'Bronny'
(-1 < 2) & (2 >= 3)
(-1 < 2) | (2 >= 3)
(-1 < 2) or ('String'/2)
(-1 < 2) and (2 >= 3)

Conditionals

Conditionals

  • There are multiple instance throughout our day when what we do next depends on something in the current moment
  • If it's cold in the morning, we will wear a sweatshirt, but if it's warm then we won't
  • If we have homework due tonight, we'll go to the library. If not, we'll hang out with friends

Examples

  • There's almost an 'If/Else' pattern that jumps out from these examples!

Conditionals

  • We'll want to be able to mimic the same type of behavior in our code. 
  • If a certain condition is True, then we'll want to execute one block of code
  • But if a condition is not True, then we'll want to execute a different block of code
  • To make things concrete, let's tackle the following example
print("You won the lottery!")
print("Try again!")

Check if their ticket matches the drawn number

def lottery(ticket, drawn_numbers):

Let's say we want to create a function that captures the following idea

Match

Didn't Match

Example

The New Part

We can express this in Python

if condition:
  print("You won the lottery!")
else:
  print("Try again!")

We can express this in Python

What should the condition be?

ticket == drawn_number

Evaluates to either True or False

Check if their ticket matches the drawn number

Putting it All Together

print("You won the lottery!")
print("Try again!")

Check if their ticket matches the drawn number

def(ticket, drawn_numbers):

Match

Didn't Match

def lottery(ticket, drawn_number):
  
  if ticket == drawn_number:
    print("You won the lottery")
   
  else:
    print("Try again!")
my_ticket = 4
wed_draw = 4

lottery(my_ticket, wed_draw)
print("You won the lottery!")
if 4 == 4:
lottery(4, 4)

Walk Through

my_ticket = 8 
wed_draw = 3

lottery(my_ticket, wed_draw)
print("Try again!")
if 8 == 3:
lottery(8, 3)
else:

Walk Through

Let's say though that given the score in soccer, we want to report which team won

Motivation

home_score > away_score

home_score == away_score

print("The Home team won!")

Compare the home_score to the away_score

def game(home_score, away_score):
print("Tie!")
print("The Away team won!")

home_score < away_score

If Condition

elif Condition

else Condition

def game(home_score, away_score):
  
  if home_score > away_score:
    print("The Home Team Won!")
  
  elif home_score < away_score:
    print("The Away Team Won")  
  
  else:  
    print("A Tie!")

Putting it All Together

h_score = 3
a_score = 4

game(h_score, a_score)
print("The Home Team Won!")
if 4 > 3:
game(4, 3)

Walk Through

h_score = 1
a_score = 2

game(h_score, a_score)
print("The Away Team Won!")
if 1 > 2:
game(1, 2)

Walk Through

elif 1 < 2:
h_score = 2
a_score = 2

game(h_score, a_score)
print("The Away Team Won!")
if 2 > 2:
game(2, 2)

Walk Through

elif 2 < 2:
else:

Fun Example

Analyst

Associate

Vice President

Managing Director

Partner

Global Head of Cardboard Packaging Investment Banking

Titles

Americas Head of Exotic Volatility Trading in Stocks Starting with ‘P’

 Global head of "whatever the weird trad was"

Head of Macro

  • There are a lot of times where what we would like to do next depends on the current context
  • As a fun example, let's say we worked at Greenlight Capital Inc. with James Fishback. And more specifically we were introducing him to some other person.
  • If that other person also worked at GreenLight Capital Inc. then we would want to introduce James by his role: Research Analyst
  • If the other person was a client, then we would want to introduce James as "Head of Macro" (as Matt Levine say, so that everyone is Happy!)
  • Via conditionals, we can express this idea in Python
if other_person == 'colleague':
  print("This is James, a Research Analyst")
 
else:
  print("This is James, Head of Macro")

Head of Macro

(1) `if' keyword signifies that the following is a conditional

(2) `==' is an infix function that returns True or False

(3) `:' denotes that the following will be an indented line code block

(4) `else:' says run this code block if the first condition was False

Options

if (option == 'call') & (strike_price < stock_price):
  profit = stock_price - strike_price - payment 
 
elif (option == 'put') & (strike_price > stock_price):
  profit = strike_price - stock_price - payment 
 
else:
  profit = - payment

Lists

Lists

companies = ["Microsoft", "GE", "Intel"]
  • A list is an order set of elements
  • We can create a list in Python using square brackets and separating the elements in the list by commas

Append

companies.append("Uber")
print(companies) # Output: ["Microsoft", "GE", "Intel", "Uber"]
  • We can add elements to the end of a list using the `append` function

Consider

What happens if you were to execute this code multiple times in a row?

Index

  • We can also select elements from a list as follows
a = companies[2]
print(a) # Output: 'Intel'
  • Python does Zero-based indexing which means:
print(companies[0]) # Output: 'Microsoft'

Index

  • We can also select elements by referencing their relative position from the end of the list
companies = ["Microsoft", "GE", "Intel","Uber"]
-3
-2
-1
-4
0
1
2
3
print(companies[-3]) # Output: 'GE'

Slicing

  • We can select multiple elements from a list by specifying the position that we would like to slice from, a colon, and the position that we would like to slice up to, but not include
print(companies[1:3]) # Output: ['GE', 'Intel']
  • The `1` says to select elements from the list starting from the 1st position
  • The `3` says to select the elements up to, but not including the 3rd position

Slicing

  • When slicing a list we can omit either of the numbers
print(companies[:2]) # Output: ['Microsoft', GE']
print(companies[0:2]) # Output: ['Microsoft', GE']
  • To select the first two elements from a list 
print(companies[-3:])                # Output: ['GE', 'Intel', 'Uber']
print(companies[-3:len(companies)])  # Output: ['GE', 'Intel', 'Uber']
  • To select the last three elements from a list 

Check Your Understanding

#2 Create the same slice of the list using only negative integers

companies[:2]

#1 Create the same slice of the list using only positive integers

companies[-3:]

Lists of Lists

  • We can create lists in Python where each element is a list
companies =  ['Apple', 'Microsoft', 'Google', 'Amazon', 'Facebook', 'Tesla', 'IBM', 'Netflix', 'Samsung', 'Intel']
current_thoughts = [companies[:3], [companies[4], companies[7]], companies[8:]] 

Wouldn't it be great to have labels associated with each inner list?

Check Your Understanding

True/False

companies[0] == companies[:1]

Extending

m_2000.extend(['BP', 'Royal Dutch Shell', 'IBM'])

Remove by Value

m_2000.remove('BP')

Remove by Index

m_2000.pop(2)
>> cisco

Checking Membership

'uber' in m_2000
>> False

Lists

m_2000.sort()

Sorting

Length

len(m_2000)
>> 7

Comparing Lists

[3, 4, 3] < [3, 4, 4]
>> True

Dictionary

Dictionaries

  • A dictionary is an ordered set of `key:value` pairs
  • We can create a dictionary in Python using curly brackets and separating the elements by commas
current_thoughts = {'prioritize' :companies[:3],
                    'wait_to_apply': [companies[4], companies[7]],
                    'ignore': companies[8:]}

Adding Elements to a Dictionary

current_thoughts['research_more'] = companies[1:4]
  • We can add elements to a dictionary by indexing the dictionary a new key and assigning it a value/list

Consider

What happens if you were to execute this code multiple times in a row?

Worked Example

People Learn Differently

Want to learn about each function associated with Lists in Python before using them!

Will learn the relevant functions associated with Lists as they arise in real world coding problems

Our Approach

Understanding

  • You don't need to understand every detail in every line of the Python code
  • We want to understand the Structure of the Code
  • How do the lines of code relate to each other
  • Why is the code written in one way vs another way

Worked Example

Note some of the quotes and exercises are adopted from 

Which is not a book about Python