# Lecture 15 – NumPy¶

## Review: lists¶

In :
names = ['bill', 'sarah', 'cal', 'nina', 'joe']
names

Out:
'sarah'
In :
me = ['berkeley', 22, 1998, '🇨🇦']

In :
[1, 2, 3] + [4, 5, 6]

Out:
[1, 2, 3, 4, 5, 6]
In :
numbers = [5, 4, 9, 12, 18]
new_numbers = []
for num in numbers:
new_numbers.append(num + 5)

new_numbers

Out:
[10, 9, 14, 17, 23]

## NumPy¶

In :
# Necessary to use numpy arrays!
import numpy as np

In :
# Array with 4 numbers
np.array([4, 9, 1, 2])

Out:
array([4, 9, 1, 2])
In :
# Array with 3 strings
np.array(['how', 'are', 'you'])

Out:
array(['how', 'are', 'you'], dtype='<U3')
In :
# Empty array
np.array([])

Out:
array([], dtype=float64)
In :
numbers = [5, 4, 9, 12, 18]
numbers

Out:
[5, 4, 9, 12, 18]
In :
type(numbers)

Out:
list
In :
numbers_arr = np.array(numbers)
numbers_arr

Out:
array([ 5,  4,  9, 12, 18])
In :
type(numbers_arr)

Out:
numpy.ndarray

## Benefit 1: operations on every element¶

### Basic operations:¶

In :
numbers_arr

Out:
array([ 5,  4,  9, 12, 18])
In :
numbers_arr * 2

Out:
array([10,  8, 18, 24, 36])
In :
numbers_arr - 5

Out:
array([ 0, -1,  4,  7, 13])
In :
numbers_arr // 2

Out:
array([2, 2, 4, 6, 9])
In :
numbers_arr ** 2 - 1

Out:
array([ 24,  15,  80, 143, 323])

### Example: Celsius to Fahrenheit¶

In :
c_temps = [17, 18, 22, -4.5, 15, 9, 0, 3, 8]

# Using vanilla lists:
f_temps = []
for c in c_temps:
f = (9 / 5) * c + 32
f_temps.append(f)

f_temps

Out:
[62.6, 64.4, 71.6, 23.9, 59.0, 48.2, 32.0, 37.4, 46.4]
In :
# Using arrays: no for loop!
(9 / 5) * np.array(c_temps) + 32

Out:
array([62.6, 64.4, 71.6, 23.9, 59. , 48.2, 32. , 37.4, 46.4])

### More math¶

In :
numbers_arr

Out:
array([ 5,  4,  9, 12, 18])
In :
np.sqrt(numbers_arr)

Out:
array([2.23606798, 2.        , 3.        , 3.46410162, 4.24264069])
In :
np.log(numbers_arr)

Out:
array([1.60943791, 1.38629436, 2.19722458, 2.48490665, 2.89037176])
In :
np.sin(numbers_arr)

Out:
array([-0.95892427, -0.7568025 ,  0.41211849, -0.53657292, -0.75098725])
In :
np.sqrt(144)

Out:
12.0

### Quick Check 1¶

In :
my_tips = [0.15, 0.16, 0.22, 0.39]
your_tips = [0.25, 0.19, 0.08]
tips = np.array(my_tips + your_tips)
tips_pct = 100 * tips

In [ ]:



## Benefit 2: element-wise operations¶

In :
a = np.array([1, 2, 3])
b = np.array([-4, 5, 9])

In :
a + b

Out:
array([-3,  7, 12])
In :
a - 2 * b

Out:
array([  9,  -8, -15])
In :
a**2 + b**2

Out:
array([17, 29, 90])
In :
# a and c have different lengths, so you can't add them element-wise
c = np.array([9, 0, 2, 4])

a + c

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-30-87488aa0dee2> in <module>
2 c = np.array([9, 0, 2, 4])
3
----> 4 a + c

ValueError: operands could not be broadcast together with shapes (3,) (4,) 

### Example: population growth¶

In :
pop_2019 = np.array([100, 55, 23, 91, 121])
pop_2020 = np.array([101, 45, 23, 93, 118])

In :
# Change from 2020 to 2019
pop_2020 - pop_2019

Out:
array([  1, -10,   0,   2,  -3])
In :
# Percent change
100 * (pop_2020 - pop_2019) / pop_2019

Out:
array([  1.        , -18.18181818,   0.        ,   2.1978022 ,
-2.47933884])

### Quick Check 2¶

In :
# a = np.array([3, 4, 5])
# b = np.array([7, -4.0, 5])
# c = (a + b) / (a - b)


## Other features of arrays¶

### Accessing individual elements¶

In :
pop_2020 = np.array([101, 45, 23, 93, 118])

In :
pop_2020

Out:
101
In :
pop_2020[-2]

Out:
93
In :
pop_2020.item(0)

Out:
101
In :
pop_2020.item(-2)

Out:
93

### Common methods¶

In :
pop_2020

Out:
array([101,  45,  23,  93, 118])
In :
# Sum of all elements
# Equivalent to np.sum(pop_2020)
pop_2020.sum()

Out:
380
In :
# Average of all elements
# Equivalent to np.mean(pop_2020)
pop_2020.mean()

Out:
76.0
In :
# Product of all elements
# Equivalent to np.prod(pop_2020)
pop_2020.prod()

Out:
1147167090

### Ranges¶

In :
np.arange(10)

Out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In :
np.arange(3, 13, 3)

Out:
array([ 3,  6,  9, 12])
In :
# Powers of 2
2**np.arange(10)

Out:
array([  1,   2,   4,   8,  16,  32,  64, 128, 256, 512])
In :
# 1^2 + 2^2 + 3^2 + ... + 99^2 + 100^2
np.sum(np.arange(101)**2)

Out:
338350

### Automatic type conversion¶

In :
# 2. means 2.0
some_values = [2, 3, 3.5, 4, False]
np.array(some_values)

Out:
array([2. , 3. , 3.5, 4. , 0. ])
In :
np.array(some_values).item(0)

Out:
2.0
In :
other_values = [9, 8, 'hello', -14.5]
np.array(other_values)

Out:
array(['9', '8', 'hello', '-14.5'], dtype='<U21')

### Even more functions¶

In :
pop_2020

Out:
array([101,  45,  23,  93, 118])
In :
# Cumulative sum: for each element,
# add all elements so far
np.cumsum(pop_2020)

Out:
array([101, 146, 169, 262, 380])
In :
# Difference: takes the differences
# of consecutive differences
np.diff(pop_2020)

Out:
array([-56, -22,  70,  25])
In :
# count_nonzero: counts the number of elements
# that are not equal to 0
np.count_nonzero(np.array([1, 2, 3, 0, 0, 4, -5]))

Out:
5