3.14. Array Arithmetic

Vectorized Operations

Single statement without a loop that explains a looping concept. Applies operation to each element.

import numpy as np


a = np.array([1, 2, 3])

a ** 2
# array([1, 4, 9])

3.14.1. Broadcasting Rules

  1. Operations between multiple array objects are first checked for proper shape match

  2. Mathematical operators (+, -, *, /, exp, log, ...) apply element by element, on values

  3. Reduction operations (mean, std, skew, kurt, sum, prod, ...) apply to whole array, unless an axis is specified

  4. Missing values propagate, unless explicitly ignored (nanmean, nansum, ...)

3.14.2. Addition

import numpy as np


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

a + 2
# array([[3, 4, 5],
#        [6, 7, 8]])

a + a
# array([[ 2,  4,  6],
#        [ 8, 10, 12]])
import numpy as np


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

a + b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.3. Subtraction

import numpy as np


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

a - 2
# array([[-1,  0,  1],
#        [ 2,  3,  4]])

a - a
# array([[0, 0, 0],
#        [0, 0, 0]])
import numpy as np


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

a - b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.4. Division

import numpy as np


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

a / 2
# array([[0.5, 1. , 1.5],
#        [2. , 2.5, 3. ]])

a / a
# array([[1., 1., 1.],
#        [1., 1., 1.]])
import numpy as np


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

a / b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.5. Square Root

import numpy as np


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

np.sqrt(a)
# array([[1., 1.41421356, 1.73205081],
#        [2., 2.23606798, 2.44948974]])

3.14.6. Modulo

import numpy as np


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

a % 2
# array([[1, 0, 1],
#        [0, 1, 0]])

a % a
# array([[0, 0, 0],
#        [0, 0, 0]])

a // a
# array([[1, 1, 1],
#        [1, 1, 1]])
import numpy as np


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

a % b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

a // b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.7. Multiplication

import numpy as np


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

a * 2
# array([[ 2,  4,  6],
#        [ 8, 10, 12]])
import numpy as np


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

a * b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.8. Power

import numpy as np


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

a ** 2
# array([[ 1,  4,  9],
#        [16, 25, 36]])

a * a
# array([[ 1,  4,  9],
#        [16, 25, 36]])
import numpy as np


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

a ** b
# ValueError: operands could not be broadcast together with shapes (3,) (2,)

3.14.9. Array Multiplication

Warning

For two-dimensional arrays, multiplication * remains elementwise and does not correspond to matrix multiplication.

import numpy as np


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

b = np.array([[4, 5, 6],
              [7, 8, 9]])

a * b
# array([[ 4, 10, 18],
#        [ 7, 16, 27]])

3.14.10. Matrix Multiplication

import numpy as np


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

b = np.array([[4, 5, 6],
              [7, 8, 9]])

a.dot(b)
# ValueError: shapes (3,) and (2,3) not aligned: 3 (dim 0) != 2 (dim 0)
import numpy as np


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

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

a.dot(b)
# array([[22, 28],
#        [49, 64]])
import numpy as np


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

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

a @ b
# array([[22, 28],
#        [49, 64]])
import numpy as np


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

a @ b
# ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)

a.dot(b)
# ValueError: shapes (3,) and (2,3) not aligned: 3 (dim 0) != 2 (dim 0)
  • np.dot()

  • If either a or b is 0-D (scalar), it is equivalent to multiply and using numpy.multiply(a, b) or a * b is preferred.

  • If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).

  • If both a and b are 2-D arrays, it is matrix multiplication, but using matmul or a @ b is preferred.

  • If a is an N-D array and b is a 1-D array, it is a sum product over the last axis of a and b.

  • If a is an N-D array and b is an M-D array (where M>=2), it is a sum product over the last axis of a and the second-to-last axis of b: dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

import numpy as np


a = np.array([1, 2, 3], float)
b = np.array([0, 1, 1], float)

np.dot(a, b)
# 5.0
import numpy as np


a = np.array([[0, 1], [2, 3]], float)
b = np.array([2, 3], float)
c = np.array([[1, 1], [4, 0]], float)

a
# array([[ 0., 1.],
#        [ 2., 3.]])

np.dot(b, a)
# array([ 6., 11.])

np.dot(a, b)
# array([ 3., 13.])

np.dot(a, c)
# array([[ 4., 0.],
#        [ 14., 2.]])

np.dot(c, a)
# array([[ 2., 4.],
#        [ 0., 4.]])

3.14.11. Assignments

3.14.11.1. Matrix multiplication

  • Complexity level: easy

  • Lines of code to write: 2 lines

  • Estimated time of completion: 5 min

  • Filename: solution/numpy_matmul.py

English
  1. Multiply two np.array

  2. Compare output of @ and *

  3. Why it differs?

Polish
  1. Pomnóż dwa np.array

  2. Porównaj wynik @ oraz *

  3. Dlaczego się różnią?

def matrix_multiplication(A, B):
    """
    >>> import numpy as np

    >>> A = np.array([[1, 0], [0, 1]])
    >>> B = [[4, 1], [2, 2]]
    >>> matrix_multiplication(A, B)
    array([[4, 1],
           [2, 2]])

    >>> A = [[1,0,1,0], [0,1,1,0], [3,2,1,0], [4,1,2,0]]
    >>> B = np.array([[4,1], [2,2], [5,1], [2,3]])
    >>> matrix_multiplication(A, B)
    array([[ 9,  2],
           [ 7,  3],
           [21,  8],
           [28,  8]])
    """
    return ...

3.14.11.2. Arithmetic operations

English
  1. For given: a: ndarrays, b: ndarrays, c: ndarrays (see below)

  2. Calculate square root of each element in a and b

  3. Calculate second power (square) of each element in c

  4. Add elements from a to b

  5. Multiply the result by c

  6. Calculate the natural logarithm of the result

Polish
  1. Dla danych: a: ndarrays, b: ndarrays, c: ndarrays (patrz poniżej)

  2. Oblicz pierwiastek kwadratowy każdego z elementu w a i b

  3. Oblicz drugą potęgę (kwadrat) każdego z elementu w c

  4. Dodaj elementy z a do b

  5. Przemnóż wynik przez c

  6. Wylicz logarytm naturalny rezultatu

Input
a = np.array([[0, 1], [2, 3]], float)
b = np.array([2, 3], float)
c = np.array([[1, 1], [4, 0]], float)
Output
array([[0.34657359, 1.00505254],
       [3.81230949,       -inf]])