NB 1
NB 1
dictionary vs. reg dictionary for counting, vector compression and decompression. The last part
contains GRADES, the nested list of students, exams and grades, and their associated exercises
(nested list indexing and reference, dictionary comprehension, mapping, enumerate, get and sort).
0-basics (Score: 10.0 / 10.0)
1. Test cell (Score: 1.0 / 1.0)
2. Test cell (Score: 1.0 / 1.0)
3. Test cell (Score: 1.0 / 1.0)
4. Test cell (Score: 2.0 / 2.0)
5. Test cell (Score: 1.0 / 1.0)
6. Test cell (Score: 1.0 / 1.0)
7. Test cell (Score: 1.0 / 1.0)
8. Test cell (Score: 2.0 / 2.0)
Important note! Before you turn in this lab notebook, make sure everything runs as expected:
Make sure you fill in any place that says YOUR CODE HERE or "YOUR ANSWER HERE."
Regarding the first goal, these initial notebooks cover material we think you should already know from Chris Simpkins's
(https://www.cc.gatech.edu/~simpkins/) Python Bootcamp (https://www.cc.gatech.edu/~simpkins/teaching/python-bootcamp/syllabus
It is based specifically on his offering to incoming students of the Georgia Tech MS Analytics in Fall 2016
(https://www.cc.gatech.edu/~simpkins/teaching/python-bootcamp/august2016.html).
Regarding the second goal, you'll observe that the bootcamp has each student install and work directly with the Python interpreter, wh
runs locally on his or her machine (e.g., see Slide 5 of Chris's intro (https://www.cc.gatech.edu/~simpkins/teaching/python-
bootcamp/slides/intro-python.html)). But in this course, we are using Jupyter Notebooks as the development environment. You can thin
Jupyter notebook as a web-based "skin" for running a Python interpreter---possibly hosted on a remote server, which is the case in this
course. Here is a good tutorial on Jupyter (https://www.datacamp.com/community/tutorials/tutorial-jupyter-notebook).
Study hint: Read the test code! You'll notice that most of the exercises below have a place for you to code up your answer followed b
"test cell." That's a code cell that checks the output of your code to see whether it appears to produce correct results. You can often le
lot by reading the test code. In fact, sometimes it gives you a hint about how to approach the problem. As such, we encourage you to t
read the test cells even if they seem cryptic, which is deliberate!
Exercise 0 (1 point). Run the code cell below. It should display the output string, Hello, world!.
print("Hello, world!")
Hello, world!
Exercise 1 (x_float_test: 1 point). Create a variable named x_float whose numerical value is one (1) and whose type is floating-p
x_float = 1.0
In [3]: Grade cell: x_float_test Score: 1.0 / 1.0
(Passed!)
Exercise 2 (strcat_ba_test: 1 point). Complete the following function, strcat_ba(a, b), so that given two strings, a and b, it ret
the concatenation of b followed by a (pay attention to the order in these instructions!).
a = random_string(5)
b = random_string(3)
c = strcat_ba(a, b)
print('strcat_ba("{}", "{}") == "{}"'.format(a, b, c))
assert len(c) == len(a) + len(b)
assert c[:len(b)] == b
assert c[-len(a):] == a
print("\n(Passed!)")
(Passed!)
Exercise 3 (strcat_list_test: 2 points). Complete the following function, strcat_list(L), which generalizes the previous funct
given a list of strings, L[:], returns the concatenation of the strings in reverse order. For example:
def strcat_list(L):
assert type(L) is list
return ''.join(L[::-1])
print('L == {}'.format(L))
print('strcat_list(L) == \'{}\''.format(Lc))
assert all([Lc[i*n:(i+1)*n] == L[nL-i-1] for i, x in zip(range(nL), L)])
print("\n(Passed!)")
(Passed!)
Exercise 4 (floor_fraction_test: 1 point). Suppose you are given two variables, a and b, whose values are the real numbers,
(non-negative) and (positive). Complete the function, floor_fraction(a, b) so that it returns , that is, the floor of . Th
of the returned value must be int (an integer).
def is_number(x):
"""Returns `True` if `x` is a number-like type, e.g., `int`, `float`, `Decimal()
..."""
from numbers import Number
return isinstance(x, Number)
(Passed!)
Exercise 5 (ceiling_fraction_test: 1 point). Complete the function, ceiling_fraction(a, b), which for any numeric inputs,
b, corresponding to real numbers, and , returns , that is, the ceiling of . The type of the returned value must be int.
(Passed!)
Exercise 6 (report_exam_avg_test: 1 point). Let a, b, and c represent three exam scores as numerical values. Complete the functio
report_exam_avg(a, b, c) so that it computes the average score (equally weighted) and returns the string, 'Your average sco
is: XX', where XX is the average rounded to one decimal place. For example:
d f t ( b )
def report_exam_avg(a, b, c):
assert is_number(a) and is_number(b) and is_number(c)
m = (a + b + c) / 3
return 'Your average score: {:.1f}'.format(m)
print("\n(Passed!)")
(Passed!)
Exercise 7 (count_word_lengths_test: 2 points). Write a function count_word_lengths(s) that, given a string consisting of wo
separated by spaces, returns a list containing the length of each word. Words will consist of lowercase alphabetic characters, and they
be separated by multiple consecutive spaces. If a string is empty or has no spaces, the function should return an empty list.
count_word_lengths('the quick brown fox jumped over the lazy dog') == [3, 5, 5, 3, 6, 4,
, 4, 3]`
the input string consists of nine (9) words whose respective lengths are shown in the list.
def count_word_lengths(s):
assert all([x.isalpha() or x == ' ' for x in s])
assert type(s) is str
return [len(x) for x in s.split()]
# Test 1: Example
qbf_str = 'the quick brown fox jumped over the lazy dog'
qbf_lens = count_word_lengths(qbf_str)
print("Test 1: count_word_lengths('{}') == {}".format(qbf_str, qbf_lens))
assert qbf_lens == [3, 5, 5, 3, 6, 4, 3, 4, 3]
def random_letter_or_space(pr_space=0.15):
from random import choice, random
is_space = (random() <= pr_space)
if is_space:
return ' '
return random_letter()
S_LEN = 40
W_SPACE = 1 / 6
rand_str = random_string(S_LEN, fun=random_letter_or_space)
rand_lens = count_word_lengths(rand_str)
print("Test 2: count_word_lengths('{}') == '{}'".format(rand_str, rand_lens))
c = 0
while c < len(rand_str) and rand_str[c] == ' ':
c += 1
for k in rand_lens:
print(" => '{}'".format (rand_str[c:c+k]))
assert (c+k) == len(rand_str) or rand_str[c+k] == ' '
c += k
while c < len(rand_str) and rand_str[c] == ' ':
c += 1
print("\n(Passed!)")
Test 1: count_word_lengths('the quick brown fox jumped over the lazy dog') == [3, 5,
3, 6, 4, 3, 4, 3]
Test 2: count_word_lengths(' k piiwa ewumu zuhhtf faq udz rrhl ed q') == '[1, 5, 5,
3, 3, 4, 2, 1]'
=> 'k'
=> 'piiwa'
If we wanted to count the number of times
=> 'ewumu' a word appears in a string: dictionary
=> 'zuhhtf'
=> 'faq'
=> 'udz'
=> 'rrhl'
=> 'ed'
=> 'q'
Test 3: Empty strings...
(Passed!)
In [16]: oanttomniff
Important note! Before you turn in this lab notebook, make sure everything runs as expected:
Make sure you fill in any place that says YOUR CODE HERE or "YOUR ANSWER HERE."
Exercise 0 (minmax_test: 1 point). Complete the function minmax(L), which takes a list L and returns a pair---that is, 2-element Pyt
tuple, or "2-tuple"---whose first element is the minimum value in the list and whose second element is the maximum. For instance:
def minmax(L):
assert hasattr(L, "__iter__")
return (min(L), max(L))
L = [8, 7, 2, 5, 1]
mmL = minmax(L)
mmL_true = (1, 8)
print("minmax({}) -> {} [True: {}]".format(L, mmL, mmL_true))
assert type(mmL) is tuple and mmL == (1, 8)
print("\n(Passed!)")
(Passed!)
Exercise 1 (remove_all_test: 2 points). Complete the function remove_all(L, x) so that, given a list L and a target value x, it re
a copy of the list that excludes all occurrences of x but preserves the order of the remaining elements. For instance:
My solution
Note. Your implementation should not modify the list being passed into remove_all.
# Test 1: Example
test_it([1, 2, 3, 2, 4, 8, 2], 2, [1, 3, 4, 8])
print("\n(Passed!)")
(Passed!)
Exercise 2 (compress_vector_test: 2 points). Suppose you are given a vector, x, containing real values that are mostly zero. For
instance:
x = [0.0, 0.87, 0.0, 0.0, 0.0, 0.32, 0.46, 0.0, 0.0, 0.10, 0.0, 0.0]
Complete the function, compress_vector(x), so that returns a dictionary d with two keys, d['inds'] and d['vals'], which are l
that indicate the position and value of all the non-zero entries of x. For the previous example,
d['inds'] = [1, 5, 6, 9]
d['vals'] = [0.87, 0.32, 0.46, 0.10]
Note 2. If x contains only zero entries, d['inds'] and d['vals'] should be empty lists.
def compress_vector(x):
assert type(x) is list
d = {'inds': [], 'vals': []}
for i, v in enumerate(x):
if v != 0.0:
d['inds'].append(i)
d['vals'].append(v)
return d
# Test 1: Example
x = [0.0, 0.87, 0.0, 0.0, 0.0, 0.32, 0.46, 0.0, 0.0, 0.10, 0.0, 0.0]
check_compress_vector(x)
print("\n(Passed!)")
Testing `compress_vector(x=[0.0, 0.87, 0.0, 0.0, 0.0, 0.32, 0.46, 0.0, 0.0, 0.1, 0.0
0])`:
`x` has 8 zero entries.
x (after call): [0.0, 0.87, 0.0, 0.0, 0.0, 0.32, 0.46, 0.0, 0.0, 0.1, 0.0, 0
d: {'vals': [0.87, 0.32, 0.46, 0.1], 'inds': [1, 5, 6, 9]}
Testing `compress_vector(x=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.37, 0.0, 0
0.0, 0.81, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])`:
`x` has 18 zero entries.
x (after call): [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.37, 0.0, 0.0
0, 0.81, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
d: {'vals': [0.37, 0.81], 'inds': [9, 13]}
Testing `compress_vector(x=[0.0, 0.0, 0.49, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0
0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.0, 0.71])`:
`x` has 17 zero entries.
x (after call): [0.0, 0.0, 0.49, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.0, 0.71]
d: {'vals': [0.49, 0.3, 0.71], 'inds': [2, 14, 19]}
Testing `compress_vector(x=[0.0, 0.0, 0.0, 0.0, 0.0, 0.37, 0.61, 0.0, 0.0, 0.0, 0.0,
3, 0.0, 0.0, 0.32, 0.0, 0.0, 0.0, 0.0, 0.0])`:
`x` has 16 zero entries.
x (after call): [0.0, 0.0, 0.0, 0.0, 0.0, 0.37, 0.61, 0.0, 0.0, 0.0, 0.0, 0.4
0.0, 0.0, 0.32, 0.0, 0.0, 0.0, 0.0, 0.0]
d: {'vals': [0.37, 0.61, 0.43, 0.32], 'inds': [5, 6, 11, 14]}
Testing `compress_vector(x=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])`:
`x` has 10 zero entries.
x (after call): [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
d: {'vals': [], 'inds': []}
(Passed!)
Repeated indices. Consider the compressed vector data structure, d, in the preceding exercise, which stores a list of indices (d['ind
and a list of values (d['vals']).
Suppose we allow duplicate indices, possibly with different values. For example:
d['inds'] == [0, 3, 7, 3, 3, 5, 1]
d['vals'] == [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
In this case, the index 3 appears three times. (Also note that the indices d['ind'] need not appear in sorted order.)
Let's adopt the convention that when there are repeated indices, the "true" value there is the sum of the individual values. In other word
true vector corresponding to this example of d would be:
# ind: 0 1 2 3* 4 5 6 7
x == [1.0, 7.0, 0.0, 11.0, 0.0, 6.0, 0.0, 3.0]
Exercise 3 (decompress_vector_test: 2 points). Complete the function decompress_vector(d) that takes a compressed vector
which is a dictionary with keys for the indices (inds) and values (vals), and returns the corresponding full vector. For any repeated ind
the values should be summed.
The function should accept an optional parameter, n, that specifies the length of the full vector. You may assume this length is at least
max(d['inds'])+1.
x = [0.0] * n
callinds I de
for i v inzip
for i v in zip(d['inds']
vals
d['vals']):
for i, v in zip(d[ inds ], d[ vals ]):
x[i] += v
return x
# Test 1: Example
d = {}
d['inds'] = [0, 3, 7, 3, 3, 5, 1]
d['vals'] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
x_true = [1.0, 7.0, 0.0, 11.0, 0.0, 6.0, 0.0, 3.0]
check_decompress_vector(d, x_true)
print("\n(Passed!)")
(Passed!)
Exercise 4 (find_common_inds_test: 1 point). Suppose you are given two compressed vectors, d1 and d2, each represented as
described above and possibly with repeated indices. Complete the function find_common_inds(d1, d2) so that it returns a list of t
indices they have in common.
d1 == {'inds': [9, 9, 1, 9, 8, 1], 'vals': [0.28, 0.84, 0.71, 0.03, 0.04, 0.75]}
d2 == {'inds': [0, 9, 9, 1, 3, 3, 9], 'vals': [0.26, 0.06, 0.46, 0.58, 0.42, 0.21, 0.53, 0.76
]}
Then:
Note 1. The returned list must not have duplicate indices, even if the inputs do. In the example, the index 9 is repeated in
both d1 and d2, but the output includes just one 9.
Note 2. In the returned list, the order of indices does not matter. For instance, the example shows [1, 9] but [9, 1] would
also be valid.
# Test 1: Example
d1 = {'inds': [9, 9, 1, 9, 8, 1], 'vals': [0.28, 0.84, 0.71, 0.03, 0.04, 0.75]}
d2 = {'inds': [0, 9, 9, 1, 3, 3, 9], 'vals': [0.26, 0.06, 0.46, 0.58, 0.42, 0.21, 0.
0.76]}
ans = [1, 9]
check_find_common_inds(d1, d2, ans)
print("\n(Passed!))")
(Passed!))
In [11]:
Python review: More exercises
This notebook continues the review of Python basics. A key concept is that of a nested data structure. For example, the first code cell will defin
"array" as a list of lists.
Consider the following dataset of exam grades, organized as a 2-D table and stored in Python as a "list of lists" under the variable name, grad
In [2]: grades = [
# First line is descriptive header. Subsequent lines hold data
['Student', 'Exam 1', 'Exam 2', 'Exam 3'],
['Thorny', '100', '90', '80'],
['Mac', '88', '99', '111'],
['Farva', '45', '56', '67'],
['Rabbit', '59', '61', '67'],
['Ursula', '73', '79', '83'],
['Foster', '89', '97', '101']
]
grades
Exercise 0 (students_test: 1 point). Complete the function get_students which takes a nested list grades as a parameter and reutrns a
students, which holds the names of the students as they from "top to bottom" in the table.
Note: the parameter grades will be similar to the table above in structure, but the data will be different.
The demo cell below should display ['Thorny', 'Mac', 'Farva', 'Rabbit', 'Ursula', 'Foster'].
The test cell below will check your solution against several randomly generated test cases. If your solution does not pass the test (or if you're ju
you can look at the variables used in the latest test run. They are automatically imported for you as part of the test.
input_vars - Dictionary containing all of the inputs to your function. Keys are the parameter names.
original_input_vars - Dictionary containing a copy of all the inputs to your function. This is useful for debugging failures related to yo
solution modifying the input. Keys are the parameter names.
returned_output_vars - Dictionary containing the outputs your function generated. If there are multiple outputs, the keys will match th
mentioned in the exercrise instructions.
true_output_vars - Dictionary containing the outputs your function should have generated. If there are multiple outputs, the keys will m
names mentioned in the exercrise instructions.
All of the test cells in this notebook will use the same format, and you can expect a similar format on your exams as well.
In [6]: input_vars
Exercise 1 (assignments_test: 1 point). Complete the function get_assignments. The function takes grades (a nested list structured sim
grades above) as a parameter. It should return a new list assignments which holds the names of the class assignments. (These appear in the
header element of grades.)
The demo cell below should display ['Exam 1', 'Exam 2', 'Exam 3']
The following test cell will check your function against several randomly generated test cases.
Exercise 2 (grade_lists_test: 1 point). Complete the function for build_grade_lists, again taking grades as a parameter. The functio
return a new dictionary, named grade_lists, that maps names of students to lists of their exam grades. The grades should be converted from
integers. For instance, grade_lists['Thorny'] == [100, 90, 80].
Exercise 3 (grade_dicts_test: 2 points). Complete the function build_grade_dicts, again taking grades as a parameter and returning
dictionary, grade_dicts, that maps names of students to dictionaries containing their scores. Each entry of this scores dictionary should be k
assignment name and hold the corresponding grade as an integer. For instance, grade_dicts['Thorny']['Exam 1'] == 100. You may fi
to earlier exercises useful for completing this one. Feel free to use them!
{'Thorny': {'Exam 1': 100, 'Exam 2': 90, 'Exam 3': 80},
'Mac': {'Exam 1': 88, 'Exam 2': 99, 'Exam 3': 111},
'Farva': {'Exam 1': 45, 'Exam 2': 56, 'Exam 3': 67},
'Rabbit': {'Exam 1': 59, 'Exam 2': 61, 'Exam 3': 67},
'Ursula': {'Exam 1': 73, 'Exam 2': 79, 'Exam 3': 83},
'Foster': {'Exam 1': 89, 'Exam 2': 97, 'Exam 3': 101}}
Out[14]: {'Thorny': {'Exam 1': 100, 'Exam 2': 90, 'Exam 3': 80},
'Mac': {'Exam 1': 88, 'Exam 2': 99, 'Exam 3': 111},
'Farva': {'Exam 1': 45, 'Exam 2': 56, 'Exam 3': 67},
'Rabbit': {'Exam 1': 59, 'Exam 2': 61, 'Exam 3': 67},
'Ursula': {'Exam 1': 73, 'Exam 2': 79, 'Exam 3': 83},
'Foster': {'Exam 1': 89, 'Exam 2': 97, 'Exam 3': 101}}
Exercise 4 (avg_grades_by_student_test: 1 point). Complete the function build_avg_by_student, taking grades as a parameter and
dictionary named avg_by_student that maps each student to his or her average exam score. For instance, avg_grades_by_student['Th
90. You may find solutions to earlier exercises useful for completing this one. Feel free to use them!
Hint. The statistics (https://docs.python.org/3.5/library/statistics.html) module of Python has at least one helpful function.
{'Thorny': 90,
'Mac': 99.33333333333333,
'Farva': 56,
'Rabbit': 62.333333333333336,
'Ursula': 78.33333333333333,
'Foster': 95.66666666666667}
Exercise 5 (grades_by_assignment_test: 2 points). Complete the function build_grade_by_asn, which takes grades as a parameter a
dictionary named grade_by_asn, whose keys are assignment (exam) names and whose values are lists of scores over all students on that ass
instance, grades_by_assignment['Exam 1'] == [100, 88, 45, 59, 73, 89]. You may find solutions to earlier exercises useful for
this one. Feel free to use them!
Exercise 6 (avg_grades_by_assignment_test: 1 point). Complete the function build_avg_by_asn, which takes grades as a parameter
dictionary, avg_by_asn, which maps each exam to its average score. You may find solutions to earlier exercises useful for completing this one
use them!
I [22] # C t di t i it t f th t it ll t d t
In [22]: # Create a dict mapping items to average for that item across all students.
def build_avg_by_asn(grades):
###
### YOUR CODE HERE
###
from statistics import mean
grades_by_assignment = build_grade_by_asn(grades)
return {a: mean(G) for a, G in grades_by_assignment.items()}