Matrices: Numpy 2 - Exercises

Introduction

Let’s see now some exercises. First ones will be given in two versions: first ones usually adopt for cycles and are thus slow, second ones are denoted ‘pro’ and avoid loops using all the power offered by Numpy. In particular in many cases you can obtain very efficient and compact programs by using slices in smart ways.

Numpy - this notebook

  1. not natively available in Python

  2. efficient

  3. many libraries for scientific calculations are based on Numpy (scipy, pandas)

  4. syntax to access elements is slightly different from list of lists

  5. in rare cases might give problems of installation and/or conflicts (implementation is not pure Python)

ATTENTION

Following exercises contain tests with asserts. To understand how to carry them out, read first Error handling and testing

frame

✪✪✪ RETURN a NEW Numpy matrix of n rows and n columns, in which all the values are zero except those on borders, which must be equal to a given k

For example, frame(4, 7.0) must give:

array([[7.0, 7.0, 7.0, 7.0],
       [7.0, 0.0, 0.0, 7.0],
       [7.0, 0.0, 0.0, 7.0],
       [7.0, 7.0, 7.0, 7.0]])

Ingredients:

  • create a matrix filled with zeros. ATTENTION: which dimensions does it have? Do you need n or k ? Read WELL the text.

For this first version, try filling the rows and columns using for in range and writing directly in the single cells

Show solution
[2]:
import numpy as np

def frame(n, k):
    raise Exception('TODO IMPLEMENT ME !')


expected_mat = np.array( [[7.0, 7.0, 7.0, 7.0],
                         [7.0, 0.0, 0.0, 7.0],
                         [7.0, 0.0, 0.0, 7.0],
                         [7.0, 7.0, 7., 7.0]])
# all_close return True if all the values in the first matrix are close enough
# (that is, within a given tolerance) to corresponding values in the second
assert np.allclose(frame(4, 7.0), expected_mat)

expected_mat = np.array( [ [7.0]
                       ])
assert np.allclose(frame(1, 7.0), expected_mat)

expected_mat = np.array( [ [7.0, 7.0],
                         [7.0, 7.0]
                       ])
assert np.allclose(frame(2, 7.0), expected_mat)

Exercise - frameslices

✪✪✪ Solve the precious exercise, this time using 4 slices

  • DO NOT use for nor while loops

Show solution
[3]:

def frameslices(n, k):
    raise Exception('TODO IMPLEMENT ME !')


r1 = np.array( [[7.0, 7.0, 7.0, 7.0],
                [7.0, 0.0, 0.0, 7.0],
                [7.0, 0.0, 0.0, 7.0],
                [7.0, 7.0, 7., 7.0]])

# all_close return True if all the values in the first matrix are close enough
# (that is, within a given tolerance) to corresponding values in the second
assert np.allclose(frameslices(4, 7.0), r1)

r2 = np.array( [ [7.0] ])
assert np.allclose(frameslices(1, 7.0), r2)

r3 = np.array( [ [7.0, 7.0],
                 [7.0, 7.0]])
assert np.allclose(frameslices(2, 7.0), r3)

Exercise - framefill

✪✪✪ Solve the precious exercise, this using np.full function and with only one slice

  • DO NOT use for nor while loops

Show solution
[4]:

def framefill(n, k):
    raise Exception('TODO IMPLEMENT ME !')


r1 = np.array( [[7.0, 7.0, 7.0, 7.0],
                [7.0, 0.0, 0.0, 7.0],
                [7.0, 0.0, 0.0, 7.0],
                [7.0, 7.0, 7., 7.0]])

# all_close return True if all the values in the first matrix are close enough
# (that is, within a given tolerance) to corresponding values in the second
assert np.allclose(framefill(4, 7.0), r1)

r2 = np.array( [ [7.0] ])
assert np.allclose(framefill(1, 7.0), r2)

r3 = np.array( [ [7.0, 7.0],
                 [7.0, 7.0]])
assert np.allclose(framefill(2, 7.0), r3)

Exercise - avg_rows

✪✪✪ Takes a numpy matrix n x m and RETURN a NEW numpy matrix consisting in a single column in which the values are the average of the values in corresponding rows of input matrix

Example:

Input: 5x4 matrix

3 2 1 4
6 2 3 5
4 3 6 2
4 6 5 4
7 2 9 3

Output: 5x1 matrix

(3+2+1+4)/4
(6+2+3+5)/4
(4+3+6+2)/4
(4+6+5+4)/4
(7+2+9+3)/4

Basic version ingredients (slow)

  • create a matrix n x 1 to return, filling it with zeros

  • visit all cells of original matrix with two nested fors

  • during visit, accumulate in the matrix to return the sum of elements takes from each row of original matrix

  • once completed the sum of a row, you can divide it by the dimension of columns of original matrix

  • return the matrix

Pro version (fast):

  • try using axis parameter and reshape

Show solution
[5]:
def avg_rows(mat):
    raise Exception('TODO IMPLEMENT ME !')
    return ret


m1 = np.array([ [5.0] ])
r1 = np.array([ [5.0] ])
assert np.allclose(avg_rows(m1), r1)

m2 = np.array([ [5.0, 3.0] ])
r2 = np.array([ [4.0] ])
assert np.allclose(avg_rows(m2), r2)


m3 = np.array([ [3,2,1,4],
                [6,2,3,5],
                [4,3,6,2],
                [4,6,5,4],
                [7,2,9,3] ])

r3 = np.array([ [(3+2+1+4)/4],
                [(6+2+3+5)/4],
                [(4+3+6+2)/4],
                [(4+6+5+4)/4],
                [(7+2+9+3)/4] ])

assert np.allclose(avg_rows(m3), r3)
Show solution
[6]:
#EFFICIENT SOLUTION avg_rows_pro


Exercise - matrot

✪✪✪ RETURN a NEW Numpy matrix which has the numbers of input matrix rotated by a column.

With rotation we mean that:

  • if a number of input matrix is found in column j, in the output matrix it will be in the column j+1 in the same row.

  • if a number is found in the last column, in the output matrix it will be in the zertoth column

Example:

If we have as input:

np.array(   [
                [0,1,0],
                [1,1,0],
                [0,0,0],
                [0,1,1]
            ])

We expect as output:

np.array(   [
                [0,0,1],
                [0,1,1],
                [0,0,0],
                [1,0,1]
            ])
Show solution
[7]:
import numpy as np

def matrot(mat):
    raise Exception('TODO IMPLEMENT ME !')

m1 = np.array(  [ [1] ])
r1 = np.array(  [ [1] ])

assert np.allclose(matrot(m1), r1)

m2 = np.array(  [ [0,1] ])
r2 = np.array(  [ [1,0] ])
assert np.allclose(matrot(m2), r2)

m3 = np.array(  [ [0,1,0] ])
r3 = np.array(  [ [0,0,1] ])

assert np.allclose(matrot(m3), r3)

m4 = np.array(  [
                    [0,1,0],
                    [1,1,0]
                ])
r4 = np.array( [
                    [0,0,1],
                    [0,1,1]
                ])
assert np.allclose(matrot(m4), r4)


m5 = np.array([
                [0,1,0],
                [1,1,0],
                [0,0,0],
                [0,1,1]
              ])
r5 = np.array([
                [0,0,1],
                [0,1,1],
                [0,0,0],
                [1,0,1]
               ])
assert np.allclose(matrot(m5), r5)
Show solution
[8]:
#EFFICIENT SOLUTION

Exercise - odd

✪✪✪ Takes a Numpy matrix mat of dimension nrows by ncols containing integer numbers and RETURN a NEW Numpy matrix of dimension nrows by ncols which is like the original, ma in the cells which contained even numbers now there will be odd numbers obtained by summing 1 to the existing even number.

Example:

odd(np.array( [
                    [2,5,6,3],
                    [8,4,3,5],
                    [6,1,7,9]
               ]))

Must give as output

array([[ 3.,  5.,  7.,  3.],
       [ 9.,  5.,  3.,  5.],
       [ 7.,  1.,  7.,  9.]])

Basic versions hints (slow):

  • Since you need to return a matrix, start with creating an empty one

  • go through the whole input matrix with indeces i and j

Show solution
[9]:
import numpy as np

def odd(mat):
    raise Exception('TODO IMPLEMENT ME !')



m1 = np.array([ [2] ])
m2 = np.array([ [3] ])
assert np.allclose(odd(m1), m2)
assert m1[0][0] == 2  # checks we are not modifying original matrix


m3 = np.array( [ [2,5,6,3],
                 [8,4,3,5],
                 [6,1,7,9] ])
m4 = np.array( [ [3,5,7,3],
                 [9,5,3,5],
                 [7,1,7,9] ])
assert np.allclose(odd(m3), m4)
Show solution
[10]:
#EFFICIENT SOLUTION 1 with np.where


Show solution
[11]:
#EFFICIENT SOLUTION 2 without np.where


Exercise - doublealt

✪✪✪ Takes a Numpy matrix mat of dimensions nrows x ncols containing integer numbers and RETURN a NEW Numpy matrix of dimension nrows x ncols having at rows of even index the numbers of original matrix multiplied by two, and at rows of odd index the same numbers as the original matrix.

Example:

m  = np.array( [                      #  index
                    [ 2, 5, 6, 3],    #    0     even
                    [ 8, 4, 3, 5],    #    1     odd
                    [ 7, 1, 6, 9],    #    2     even
                    [ 5, 2, 4, 1],    #    3     odd
                    [ 6, 3, 4, 3]     #    4     even
               ])

A call to

doublealt(m)

will return the Numpy matrix:

array([[ 4, 10, 12,  6],
       [ 8,  4,  3,  5],
       [14,  2, 12, 18],
       [ 5,  2,  4,  1],
       [12,  6,  8,  6]])
Show solution
[12]:
import numpy as np

def doublealt(mat):
    raise Exception('TODO IMPLEMENT ME !')


m1 = np.array([ [2] ])
m2 = np.array([ [4] ])
assert np.allclose(doublealt(m1), m2)
assert m1[0][0] == 2  # checks we are not modifying original matrix


m3 = np.array( [ [ 2, 5, 6],
                 [ 8, 4, 3] ])
m4 = np.array( [ [ 4,10,12],
                 [ 8, 4, 3] ])
assert np.allclose(doublealt(m3), m4)

m5 = np.array( [ [ 2, 5, 6, 3],
                 [ 8, 4, 3, 5],
                 [ 7, 1, 6, 9],
                 [ 5, 2, 4, 1],
                 [ 6, 3, 4, 3] ])
m6 = np.array( [ [ 4,10,12, 6],
                 [ 8, 4, 3, 5],
                 [14, 2,12,18],
                 [ 5, 2, 4, 1],
                 [12, 6, 8, 6] ])
assert np.allclose(doublealt(m5), m6)
Show solution
[13]:
# EFFICIENT SOLUTION


Exercise - chessboard

✪✪✪ RETURN a NEW Numpy matrix of n rows and n columns, in which all cells alternate zeros and ones.

For example, chessboard(4) must give:

array([[1.0, 0.0, 1.0, 0.0],
       [0.0, 1.0, 0.0, 1.0],
       [1.0, 0.0, 1.0, 0.0],
       [0.0, 1.0, 0.0, 1.0]])

Basic version ingredients (slow):

  • to alternate, you can use range in the form in which takes 3 parameters, for example range(0,n,2) starts from 0, arrives to n excluded by jumping one item at a time, generating 0,2,4,6,8, ….

  • range(1,n,2) would instead generate 1,3,5,7, …

Show solution
[14]:
def chessboard(n):
    raise Exception('TODO IMPLEMENT ME !')


r1 = np.array([[1.0, 0.0, 1.0, 0.0],
               [0.0, 1.0, 0.0, 1.0],
               [1.0, 0.0, 1.0, 0.0],
               [0.0, 1.0, 0.0, 1.0]])
assert np.allclose(chessboard(4), r1)

r2 = np.array( [ [1.0] ])
assert np.allclose(chessboard(1), r2)

r3 = np.array( [ [1.0, 0.0],
                 [0.0, 1.0] ])
assert np.allclose(chessboard(2), r3)
Show solution
[15]:
#FAST SOLUTION


Exercise - altsum

✪✪✪ MODIFY the input Numpy matrix (n x n), by summing to all the odd rows the even rows. For example

m = [[1.0, 3.0, 2.0, 5.0],
     [2.0, 8.0, 5.0, 9.0],
     [6.0, 9.0, 7.0, 2.0],
     [4.0, 7.0, 2.0, 4.0]]
altsum(m)

after the call to altsum m should be:

m = [[1.0, 3.0, 2.0, 5.0],
     [3.0, 11.0,7.0, 14.0],
     [6.0, 9.0, 7.0, 2.0],
     [10.0,16.0,9.0, 6.0]]

Basic version ingredients (slow):

  • to alternate, you can use range in the form in which takes 3 parameters, for example range(0,n,2) starts from 0, arrives to n excluded by jumping one item at a time, generating 0,2,4,6,8, ….

  • instead range(1,n,2) would generate 1,3,5,7, ..

Show solution
[16]:
def altsum(mat):
    raise Exception('TODO IMPLEMENT ME !')


m1 = np.array( [ [1.0, 3.0, 2.0, 5.0],
                 [2.0, 8.0, 5.0, 9.0],
                 [6.0, 9.0, 7.0, 2.0],
                 [4.0, 7.0, 2.0, 4.0] ])

r1 = np.array(   [ [1.0, 3.0, 2.0, 5.0],
                   [3.0, 11.0,7.0, 14.0],
                   [6.0, 9.0, 7.0, 2.0],
                   [10.0,16.0,9.0, 6.0] ])

altsum(m1)
assert np.allclose(m1, r1) # checks we MODIFIED the original matrix

m2 = np.array( [ [5.0]  ])
r2 = np.array( [ [5.0] ])
altsum(m1)
assert np.allclose(m2, r2)

m3 = np.array( [ [6.0, 1.0],
                 [3.0, 2.0] ])
r3 = np.array( [ [6.0, 1.0],
                 [9.0, 3.0] ])
altsum(m3)
assert np.allclose(m3, r3)
Show solution
[17]:
#EFFICIENT SOLUTION


Exercise - avg_half

✪✪✪ Takes as input a Numpy matrix withan even number of columns, and RETURN as output a Numpy matrix 1x2, in which the first element will be the average of the left half of the matrix, and the second element will be the average of the right half.

Ingredients:

  • to obtain the number of columns divided by two as integer number, use // operator

Show solution
[18]:
def avg_half(mat):
    raise Exception('TODO IMPLEMENT ME !')

m1 = np.array([ [7,9] ])

r1 = np.array([(7)/1, (9)/1  ])
assert np.allclose( avg_half(m1), r1)


m2 = np.array([ [3,4],
                [6,3],
                [5,2] ])

r2 = np.array([(3+6+5)/3, (4+3+2)/3  ])
assert np.allclose( avg_half(m2), r2)

m3 = np.array([ [3,2,1,4],
                [6,2,3,5],
                [4,3,6,2],
                [4,6,5,4],
                [7,2,9,3] ])

r3 = np.array([(3+2+6+2+4+3+4+6+7+2)/10, (1+4+3+5+6+2+5+4+9+3)/10  ])

assert np.allclose( avg_half(m3), r3)
Show solution
[19]:
#EFFICIENT SOLUTION

Exercise - matxarr

✪✪ Takes a Numpy matrix n x m and an ndarray of m elements, and RETURN a NEW Numpy matrix in which the values of each column of input matrix are multiplied by the corresponding value in the n elements array.

Show solution
[20]:

def matxarr(mat, arr):
    raise Exception('TODO IMPLEMENT ME !')

m1 = np.array([ [3,2,1],
               [6,2,3],
               [4,3,6],
               [4,6,5]])
a1 = [5, 2, 6]
r1 = [ [3*5, 2*2, 1*6],
               [6*5, 2*2, 3*6],
               [4*5, 3*2, 6*6],
               [4*5, 6*2, 5*6]]

assert np.allclose(matxarr(m1,a1), r1)
Show solution
[21]:
#EFFICIENT SOLUTION

Exercise - colgap

✪✪ Given a numpy matrix of \(n\) rows and \(m\) columns, RETURN a numpy vector of \(m\) elements consisting in the difference between the maximum and minimum values of each column.

Example:

m = np.array([[5,4,2],
              [8,5,1],
              [6,7,9],
              [3,6,4],
              [4,3,7]])
>>> colgap(m)
array([5, 4, 8])

because:

5 = 8 - 3
4 = 7 - 3
8 = 9 - 1
Show solution
[22]:
import numpy as np

def colgap(mat):
    raise Exception('TODO IMPLEMENT ME !')

# TEST
m1 = np.array([[6]])
assert np.allclose(colgap(m1), np.array([0]))
ret = colgap(m1)
assert type(ret) == np.ndarray

m2 = np.array([[6,8]])
assert np.allclose(colgap(m2), np.array([0,0]))
m3 = np.array([[2],
               [5]])

assert np.allclose(colgap(m3), np.array([3]))
m4 = np.array([[5,7],
               [2,9]])
assert np.allclose(colgap(m4), np.array([3,2]))
m5 = np.array([[4,7],
               [4,9]])
assert np.allclose(colgap(m5), np.array([0,2]))
m6 = np.array([[5,2],
               [3,7],
               [9,0]])
assert np.allclose(colgap(m6), np.array([6,7]))
m7 = np.array([[5,4,2],
               [8,5,1],
               [6,7,9],
               [3,6,4],
               [4,3,7]])
assert np.allclose(colgap(m7), np.array([5,4,8]))
Show solution
[23]:
#EFFICIENT SOLUTION

Exercise - substmax

✪✪ Given an \(n\) x \(m\) numpy matrix mat, MODIFY the matrix substituting each cell with the maximum value found in the corresponding column.

Example:

>>> m  = np.array([[5,4,2],
                   [8,5,1],
                   [6,7,9],
                   [3,6,4],
                   [4,3,7]])
>>> substmax(m)    # returns nothing!
>>> m
np.array([[8, 7, 9],
          [8, 7, 9],
          [8, 7, 9],
          [8, 7, 9],
          [8, 7, 9]])
Show solution
[24]:

import numpy as np

def substmax(mat):
    raise Exception('TODO IMPLEMENT ME !')

# TEST
m1 = np.array([[6]])
substmax(m1)
assert np.allclose(m1, np.array([6]))
ret = substmax(m1)
assert ret == None # returns nothing!

m2 = np.array([[6,8]])
substmax(m2)
assert np.allclose(m2, np.array([6,8]))

m3 = np.array([[2],
               [5]])
substmax(m3)
assert np.allclose(m3, np.array([[5],
                                 [5]]))

m4 = np.array([[5,7],
               [2,9]])
substmax(m4)

assert np.allclose(m4, np.array([[5,9],
                                 [5,9]]))

m5 = np.array([[4,7],
               [4,9]])
substmax(m5)
assert np.allclose(m5, np.array([[4,9],
                                 [4,9]]))

m6 = np.array([[5,2],
               [3,7],
               [9,0]])
substmax(m6)
assert np.allclose(m6, np.array([[9,7],
                                 [9,7],
                                 [9,7]]))

m7 = np.array([[5,4,2],
               [8,5,1],
               [6,7,9],
               [3,6,4],
               [4,3,7]])
substmax(m7)
assert np.allclose(m7, np.array([[8, 7, 9],
                                 [8, 7, 9],
                                 [8, 7, 9],
                                 [8, 7, 9],
                                 [8, 7, 9]]))
Show solution
[25]:
#EFFICIENT SOLUTION

Exercise - quadrants

✪✪✪ Given a matrix 2n * 2n, divide the matrix in 4 equal square parts (see example) and RETURN a NEW matrix 2 * 2 containing the average of each quadrant.

We assume the matrix is always of even dimensions

HINT: to divide by two and obtain an integer number, use // operator

Example:

1, 2 , 5 , 7
4, 1 , 8 , 0
2, 0 , 5 , 1
0, 2 , 1 , 1

can be divided in

  1, 2 | 5 , 7
  4, 1 | 8 , 0
-----------------
  2, 0 | 5 , 1
  0, 2 | 1 , 1

and returns

(1+2+4+1)/ 4  | (5+7+8+0)/4                        2.0 , 5.0
-----------------------------            =>        1.0 , 2.0
(2+0+0+2)/4   | (5+1+1+1)/4
Show solution
[26]:


import numpy as np

def quadrants(mat):
    raise Exception('TODO IMPLEMENT ME !')


m1 = np.array( [ [3.0, 5.0],
                 [4.0, 9.0] ])
r1 = np.array([  [3.0, 5.0],
                 [4.0, 9.0],
              ])
assert np.allclose(quadrants(m1),r1)

m2 = np.array( [ [1.0, 2.0 , 5.0 , 7.0],
                 [4.0, 1.0 , 8.0 , 0.0],
                 [2.0, 0.0 , 5.0 , 1.0],
                 [0.0, 2.0 , 1.0 , 1.0] ])
r2 = np.array( [ [2.0, 5.0],
                 [1.0, 2.0] ] )
assert np.allclose(quadrants(m2),r2)
Show solution
[27]:
#EFFICIENT SOLUTION

Exercise - downup

✪✪✪ Write a function which given the dimensions of n rows and m columns, RETURN a NEW n x m numpy matrix with sequences which go down and up in alternating rows as in the examples.

  • if m is odd, raises ValueError

>>> downup(6,10)
array([[0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
       [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
       [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
       [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.]])
Show solution
[28]:
import numpy as np

def downup(n,m):
    raise Exception('TODO IMPLEMENT ME !')


assert np.allclose(downup(2,2),  np.array([ [0., 0.],
                                            [0., 0.] ]))
assert type(downup(2,2)) == np.ndarray

assert np.allclose(downup(2,6),  np.array([ [0., 0., 0., 2., 1., 0.],
                                            [0., 1., 2., 0., 0., 0.] ]))

assert np.allclose(downup(6,10), np.array([ [0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
                                            [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.],
                                            [0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
                                            [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.],
                                            [0., 0., 0., 0., 0., 4., 3., 2., 1., 0.],
                                            [0., 1., 2., 3., 4., 0., 0., 0., 0., 0.] ]))
try:
    downup(2,3)
    raise Exception("I should have failed!")
except ValueError:
    pass
Show solution
[29]:
#EFFICIENT SOLUTION (HINT: use np.tile)

Exercise - stairsteps

✪✪✪ Given a numpy square matrix mat of dimension n, RETURN a NEW numpy array containing the values retrieved from the matrix in the followin order:

1,2,*,*,*
*,3,4,*,*
*,*,5,6,*
*,*,*,7,8
*,*,*,*,9
  • if the matrix is not square, raises ValueError

  • DO NOT use python lists!

  • HINT: how many elements must the array to return have?

Example:

>>> stairsteps(np.array([ [6,3,5,2,5],
                          [3,4,2,3,4],
                          [6,5,4,5,1],
                          [4,3,2,3,9],
                          [2,5,1,6,7] ] ))
array([6., 3., 4., 2., 4., 5., 3., 9., 7.])
Show solution
[30]:
import numpy as np


def stairsteps(mat):
    raise Exception('TODO IMPLEMENT ME !')

m1 = np.array([ [7] ])
assert np.allclose(stairsteps(m1), np.array([7]))
assert type(m1) == np.ndarray

m2 = np.array([ [6,8],
                [9,3]])
assert np.allclose(stairsteps(m2), np.array([6,8,3]))
assert type(m1) == np.ndarray

m3 = np.array([ [6,3,5,2,5],
                [3,4,2,3,4],
                [6,5,4,5,1],
                [4,3,2,3,9],
                [2,5,1,6,7]])

assert np.allclose(stairsteps(m3), np.array([6,3,4,2,4,5,3,9,7]))

try:
    stairsteps(np.array([[1,2,3],
                      [4,5,6]]))
    raise Exception("I should have failed!")
except ValueError:
    pass
Show solution
[31]:
#EFFICIENT SOLUTION

Exercise - vertstairs

✪✪✪ Given a numbers of rows n and of columns m, RETURN a NEW n x m numpy matrix having the numbers in even columns progressively increasing from 1 to n, and numbers in odd columns progressively decreasing from n to 1.

Show solution
[32]:
import numpy as np

def vertstairs(n,m):
    raise Exception('TODO IMPLEMENT ME !')


assert np.allclose(vertstairs(1,1), np.array([ [1] ]))
assert np.allclose(vertstairs(1,2), np.array([ [1,1] ]))
assert np.allclose(vertstairs(2,1), np.array([ [1],
                                               [2] ]))
assert np.allclose(vertstairs(2,2), np.array([ [1,2],
                                               [2,1] ]))
assert type(vertstairs(2,2)) == np.ndarray
assert np.allclose(vertstairs(4,5), np.array([ [1,4,1,4,1],
                                               [2,3,2,3,2],
                                               [3,2,3,2,3],
                                               [4,1,4,1,4] ]))
Show solution
[33]:
#EFFICIENT SOLUTION (HINT: use np.tile)


Exercise - comprescol

✪✪✪ Given an \(n\) x \(2m\) matrix mat with an even number of columns, RETURN a NEW \(n\) x \(m\) matrix in which the columns are given by the sum of corresponding column pairs from mat

  • if mat doesn’t have an even number of columns, raise ValueError

Example:

>>> m  = np.array([[5,4,2,6,4,2],
                   [7,5,1,0,6,1],
                   [6,7,9,2,3,7],
                   [5,2,4,6,1,3],
                   [7,2,3,4,2,5]])

>>> comprescol(m)
np.array([[ 9, 8, 6],
          [12, 1, 7],
          [13,11,10],
          [ 7,10, 4],
          [ 9, 7, 7]])

because

9 = 5 + 4     8 = 2 + 6     6 = 4 + 2
12= 7 + 5     1 = 1 + 0     7 = 6 + 1
. . .
Show solution
[34]:
import numpy as np

def comprescol(mat):
    raise Exception('TODO IMPLEMENT ME !')

m1 = [[7,9]]
res = comprescol(np.array(m1))
assert type(res) == np.ndarray
assert np.allclose(res, np.array([[16]]))

m2  = np.array([[5,8],
               [7,2]])
assert np.allclose(comprescol(m2), np.array([[13],
                                            [9]]))
assert np.allclose(m2, np.array([[5,8],
                                 [7,2]]))  # check doesn't MODIFY original matrix

m3  = np.array([[5,4,2,6,4,2],
                [7,5,1,0,6,1],
                [6,7,9,2,3,7],
                [5,2,4,6,1,3],
                [7,2,3,4,2,5]])

assert np.allclose(comprescol(m3), np.array([ [ 9, 8, 6],
                                              [12, 1, 7],
                                              [13,11,10],
                                              [ 7,10, 4],
                                              [ 9, 7, 7] ]))

try:
    comprescol(np.array([[7,1,6],
                        [5,2,4]]))
    raise Exception("I should have failed!")
except ValueError:
    pass

Exercise - revtriang

✪✪✪ Givena square numpy matrix, RETURN a NEW numpy matrix having the same dimensions as the original one, and the numbers in the lower triangular part (excluding the diagonal) in reverse.

  • if the matrix is not square, raise ValueError

Example:

m  = np.array([ [5,4,2,6,4],
                [3,5,1,0,6],
                [6,4,9,2,3],
                [5,2,8,6,1],
                [7,9,3,2,2] ])

>>> revtriang(m)
np.array([ [5, 4, 2, 6, 4],
           [3, 5, 1, 0, 6],     # 3       -> 3
           [4, 6, 9, 2, 3],     # 6,4     -> 4,6
           [8, 2, 5, 6, 1],     # 5,2,8   -> 8,2,5
           [2, 3, 9, 7, 2] ])   # 7,9,3,2 -> 2,3,9,7
Show solution
[35]:
import numpy as np

def revtriang(mat):
    raise Exception('TODO IMPLEMENT ME !')

m1 = np.array([[8]])
assert np.allclose(revtriang(m1), np.array([[8]]))


m3 = np.array([[1,5],
               [9,6]])
assert np.allclose(revtriang(m3), np.array([[1,5],
                                            [9,6]]))

m4 = np.array([[1,5,8],
               [9,6,2],
               [3,2,5]])
assert np.allclose(revtriang(m4), np.array([[1,5,8],
                                            [9,6,2],
                                            [2,3,5]]))
assert np.allclose(m4, np.array([[1,5,8],
                                 [9,6,2],
                                 [3,2,5]]))  # shouldn't change the original

m5 = np.array([[5,4,2,6,4],
               [3,5,1,0,6],
               [6,4,9,2,3],
               [5,2,8,6,1],
               [7,9,3,2,2]])
assert np.allclose(revtriang(m5), np.array([[5, 4, 2, 6, 4],
                                            [3, 5, 1, 0, 6],
                                            [4, 6, 9, 2, 3],
                                            [8, 2, 5, 6, 1],
                                            [2, 3, 9, 7, 2]]))
try:
    revtriang(np.array([[7,1,6],
                        [5,2,4]]))
    raise Exception("I should have failed!")
except ValueError:
    pass

Exercise - walkas

✪✪✪ Given a numpy matrix \(n\) x \(m\) with odd \(m\), RETURN a numpy array containing all the numbers found along the path of an S, from bottom to top.

HINT: can you determine the array dimension right away?

Example:

m = np.array([[5,8,2,4,6,5,7],
              [7,9,5,8,3,2,2],
              [6,1,8,3,6,6,1],
              [1,5,3,7,9,4,7],
              [1,5,3,2,9,5,4],
              [4,3,8,5,6,1,5]])

it must walk, from bottom to top:

m = np.array([[5,8,2,>,>,>,>],
              [7,9,5,^,3,2,2],
              [6,1,8,^,6,6,1],
              [1,5,3,^,9,4,7],
              [1,5,3,^,9,5,4],
              [>,>,>,^,6,1,5]])

To obtain:

>>> walkas(m)
array([4., 3., 8., 5., 2., 7., 3., 8., 4., 6., 5., 7.])
Show solution
[36]:
import numpy as np

def walkas(mat):
    raise Exception('TODO IMPLEMENT ME !')

# TEST
m1 = np.array([[7]])
assert np.allclose(walkas(m1), np.array([7]))

m2 = np.array([[7,5,2]])
assert np.allclose(walkas(m2), np.array([7,5,2]))

m3 = np.array([[9,3,5,6,0]])
assert np.allclose(walkas(m3), np.array([9,3,5,6,0]))

m4 = np.array([[7,5,2],
               [9,3,4]])
assert np.allclose(walkas(m4), np.array([9,3,5,2]))

m5 = np.array([[7,4,6],
               [8,2,1],
               [0,5,3]])
assert np.allclose(walkas(m5), np.array([0,5,2,4,6]))

m6 = np.array([[5,8,2,4,6,5,7],
               [7,9,5,8,3,2,2],
               [6,1,8,3,6,6,1],
               [1,5,3,7,9,4,7],
               [1,5,3,2,9,5,4],
               [4,3,8,5,6,1,5]])
assert np.allclose(walkas(m6), np.array([4,3,8,5,2,7,3,8,4,6,5,7]))

Exercise - walkaz

✪✪✪ Given a numpy matrix \(n\) x \(m\) with odd \(m\), RETURN a numpy array containing all the numbers found along the path of an Z, from bottom to top.

HINT: can you determine the array dimension right away?

Example:

m = np.array([[5,8,2,4,6,5,7],
              [7,9,5,8,3,2,2],
              [6,1,8,3,6,6,1],
              [1,5,3,7,9,4,7],
              [1,5,3,2,9,5,4],
              [4,3,8,5,6,1,5]])

it must walk, from bottom to top:

m = np.array([[<,<,<,^,6,5,7],
              [7,9,5,^,3,2,2],
              [6,1,8,^,6,6,1],
              [1,5,3,^,9,4,7],
              [1,5,3,^,9,5,4],
              [4,3,8,^,<,<,<]])

To obtain:

>>> walkaz(m)
array([5.,1.,6.,5.,2.,7.,3.,8.,4.,2.,8.,5.])
Show solution
[37]:
import numpy as np

def walkaz(mat):
    raise Exception('TODO IMPLEMENT ME !')

# TEST
m1 = np.array([[7]])
assert np.allclose(walkaz(m1), np.array([7]))

m2 = np.array([[7,5,2]])
assert np.allclose(walkaz(m2), np.array([2,5,7]))

m3 = np.array([[9,3,5,6,0]])
assert np.allclose(walkaz(m3), np.array([0,6,5,3,9]))

m4 = np.array([[7,5,2],
               [9,3,4]])
assert np.allclose(walkaz(m4), np.array([4,3,5,7]))

m5 = np.array([[7,4,6],
               [8,2,1],
               [0,5,3]])
assert np.allclose(walkaz(m5), np.array([3,5,2,4,7]))

m6 = np.array([[5,8,2,4,6,5,7],
               [7,9,5,8,3,2,2],
               [6,1,8,3,6,6,1],
               [1,5,3,7,9,4,7],
               [1,5,3,2,9,5,4],
               [4,3,8,5,6,1,5]])
assert np.allclose(walkaz(m6), np.array([5,1,6,5,2,7,3,8,4,2,8,5]))

Continue

  • Try doing exercises from lists of lists using Numpy instead - try making the exercises performant by using Numpy features and functions (i.e. 2*arr multiplies all numbers in arr without the need of a slow Python for)

  • For some nice application, follow Numpy images tutorial ### ———

References

[ ]: