DS2000 (Spring 2019, NCH) :: Lecture 5b

0. Administrivia

  1. Due today @ 9pm: HW4 (submit via Blackboard)
  2. Due before Monday's lecture: pre-class quiz (via Blackboard; feel free to use book/notes/Python)
  3. Wednesday (in practicum): in-class quiz 3
  4. Due next Friday @ 9pm: HW5 (submit via Blackboard)

Problem: Simulate Many Coin Flips

Given a probability of flipping a head, number of flips, and a random seed, return how many heads were flipped.

In [2]:
import random
import statistics

def simulate_flips(n, heads_prob, seed):
    counter = 0
    
    random.seed(seed)
    for _ in range(n):
        if random.random() <= heads_prob:
            counter += 1
    
    return counter, n-counter

trials = 10
flips = 1000
heads_prob = 0.5

results = []

for iteration in range(1, trials+1):
    heads = simulate_flips(flips, heads_prob, 100 + iteration)[0]
    print("Trial {}: {} heads".format(iteration, heads))
    results.append(heads)

print("\nAverage={:.3f}, Std Dev={:.3f}".format(statistics.mean(results), statistics.stdev(results)))
Trial 1: 485 heads
Trial 2: 469 heads
Trial 3: 487 heads
Trial 4: 505 heads
Trial 5: 517 heads
Trial 6: 502 heads
Trial 7: 502 heads
Trial 8: 485 heads
Trial 9: 486 heads
Trial 10: 487 heads

Average=492.500, Std Dev=13.762

Problem: How Many Flips Until...

Given a probability of flipping a head, and a ranom seed, return how many flips are required before some number of tails are flipped.

In [3]:
import random

def flip_till_tails(max_tails, heads_prob, seed):
    total_counter = 0
    tail_counter = 0
    
    random.seed(seed)
    while tail_counter < max_tails:
        if random.random() > heads_prob:
            tail_counter += 1
        total_counter +=1
        
    return total_counter

for i in range(1, 21):
    print("# tails = {}, # flips = {}".format(i, flip_till_tails(i, 0.5, 123)))
# tails = 1, # flips = 5
# tails = 2, # flips = 7
# tails = 3, # flips = 9
# tails = 4, # flips = 17
# tails = 5, # flips = 21
# tails = 6, # flips = 24
# tails = 7, # flips = 26
# tails = 8, # flips = 27
# tails = 9, # flips = 29
# tails = 10, # flips = 30
# tails = 11, # flips = 32
# tails = 12, # flips = 34
# tails = 13, # flips = 35
# tails = 14, # flips = 36
# tails = 15, # flips = 39
# tails = 16, # flips = 40
# tails = 17, # flips = 41
# tails = 18, # flips = 42
# tails = 19, # flips = 43
# tails = 20, # flips = 44

Now how about sequential tails...

In [4]:
import random
import statistics

def flip_till_tail_string(max_tails, heads_prob, seed):
    total_counter = 0
    tail_counter = 0
    
    random.seed(seed)
    while tail_counter < max_tails:
        if random.random() <= heads_prob:
            tail_counter = 0
        else:
            tail_counter += 1
        total_counter += 1
        
    return total_counter

trials = 10
heads_prob = 0.5

for sequence_len in range(1, 11):
    print("== Sequence of Length {} ==".format(sequence_len))
    results = []
    for t in range(1, trials+1):
        flips = flip_till_tail_string(sequence_len, heads_prob, sequence_len*1000 + t)
        results.append(flips)
    print(results)
    
    avg = int("{:.0f}".format(statistics.mean(results)))
    stdev = int("{:.0f}".format(statistics.stdev(results)))
    
    print("Average={:,d}, Std Dev={:,d}\n".format(avg, stdev))
== Sequence of Length 1 ==
[1, 1, 3, 2, 2, 4, 1, 1, 4, 1]
Average=2, Std Dev=1

== Sequence of Length 2 ==
[5, 2, 3, 2, 18, 11, 3, 2, 3, 23]
Average=7, Std Dev=8

== Sequence of Length 3 ==
[11, 8, 3, 6, 14, 3, 16, 9, 5, 3]
Average=8, Std Dev=5

== Sequence of Length 4 ==
[7, 4, 34, 49, 4, 100, 8, 98, 57, 4]
Average=36, Std Dev=38

== Sequence of Length 5 ==
[18, 18, 95, 267, 109, 35, 146, 154, 99, 7]
Average=95, Std Dev=81

== Sequence of Length 6 ==
[183, 159, 19, 125, 53, 156, 34, 11, 33, 56]
Average=83, Std Dev=66

== Sequence of Length 7 ==
[161, 530, 386, 56, 606, 99, 255, 119, 738, 368]
Average=332, Std Dev=234

== Sequence of Length 8 ==
[398, 716, 97, 403, 418, 50, 702, 163, 108, 1021]
Average=408, Std Dev=322

== Sequence of Length 9 ==
[11, 207, 792, 735, 753, 409, 1356, 802, 2030, 3181]
Average=1,028, Std Dev=949

== Sequence of Length 10 ==
[356, 5783, 176, 2331, 3939, 594, 650, 1076, 4999, 170]
Average=2,007, Std Dev=2,140

Problem: Palindrome Flip

One way to make a palindrome from a word is to append the reverse of itself on the end. Given a list of words, return a list of the palindrome-flip of those words.

In [5]:
def palindrome_flip(word):
    return "{}{}".format(word, word[::-1])

def palindrome_flips(list_o_words):
    return [palindrome_flip(word) for word in list_o_words]

print(palindrome_flip("howdy"))
print(palindrome_flips(["aye", "bee", "kay"]))
howdyydwoh
['ayeeya', 'beeeeb', 'kayyak']

Problem: Person Generator

Generate a data set of names (first name + first-name-son), age (uniform in [10, 100]), height (normal around 5'5)

In [6]:
import random

f_names = ['Liam', 'Noah', 'William', 'James', 'Logan', 'Emma', 'Olivia', 'Ava', 'Isabella', 'Sophia']

def make_name():
    name = f_names[random.randint(0, len(f_names)-1)]
    return name, "{}son".format(name)

def make_person():
    height = random.gauss(65, 5)
    return make_name() + (random.randint(10, 100), int(height // 12), int(height % 12))

def make_people(seed, n):
    random.seed(seed)
    return [make_person() for _ in range(n)]

for person in make_people(321, 10):
    print(person)
('Isabella', 'Isabellason', 66, 5, 4)
('Emma', 'Emmason', 41, 5, 7)
('Olivia', 'Oliviason', 68, 5, 10)
('James', 'Jamesson', 11, 5, 2)
('Olivia', 'Oliviason', 14, 5, 5)
('Olivia', 'Oliviason', 84, 4, 6)
('James', 'Jamesson', 21, 6, 2)
('James', 'Jamesson', 36, 4, 7)
('Isabella', 'Isabellason', 53, 6, 0)
('Noah', 'Noahson', 42, 5, 2)

Problem: Search & Replace

Given a space-separated source, and search+replacement strings, replace all instances of search with replace

In [7]:
def do_replace(word, search, replace):
    if word == search:
        return replace
    else:
        return word

def search_n_replace(source, search, replace):
    return " ".join([do_replace(word, search, replace) for word in source.split(" ")])

print(search_n_replace("hi there how are you today are you doing well", "are", "etes"))
hi there how etes you today etes you doing well

Problem: Find Last

Find the location of the last occurrence of a string in a space-separated string

In [8]:
def find_last(haystack, needle):
    rwords = list(reversed(haystack.split(" ")))
    rlens = [len(word) for word in rwords]
    
    for index, word in enumerate(rwords):
        if word == needle:
            return -(sum(rlens[:index]) + index)

source = "well this is awkward and this is not fun"
print(source[find_last(source, "this"):])
 is not fun