2. Numpy

NumPy jest podstawowym pakiet (dodatkowym) w Pythonie do obliczeń naukowych. Integruje on niskopoziomowe biblioteki takie jak BLAS i LAPACK lub ATLAS. Podstawowe właściwości NumPy to :

  • potężny N-wymiarowy obiekt tablicy danych

  • rozbudowane funkcje

  • narzędzia do integracji z kodem napisanym w C/C++ i Fortranie

  • narzędzia do algebry liniowej, transformaty Fouriera czy generator liczb losowych

NumPy is the fundamental package for scientific computing with Python. It contains among other things:

  • a powerful N-dimensional array object

  • sophisticated (broadcasting) functions

  • tools for integrating C/C++ and Fortran code

  • useful linear algebra, Fourier transform, and random number capabilities

Besides its obvious scientific uses, NumPy can also be used as an efficient multi-dimensional container of generic data. Arbitrary data-types can be defined. This allows NumPy to seamlessly and speedily integrate with a wide variety of databases.

2.1. Import

import numpy as np

2.2. Data Structures

  • Skalar - jednowymiarowa

  • Wektor - dwuwymiarowa

  • Tensor - trójwymiarowa

  • Tablica - czterowymiarowa

  • Macierz - n-wymiarowa

2.3. Functions

  • np.abs()

  • np.sign()

  • np.sqrt()

  • np.log()

  • np.log10()

  • np.exp()

  • np.sin()

  • np.cos()

  • np.tan()

  • np.arcsin()

  • np.arccos()

  • np.arctan()

  • np.sinh()

  • np.cosh()

  • np.tanh()

  • np.arcsinh()

  • np.arccosh()

  • np.arctanh()

2.4. Statistics

2.4.1. Compute the median along the specified axis

a = np.array([1, 4, 3, 8, 9, 2, 3], float)

np.median(a)
# 3.0

2.4.2. Estimate a covariance matrix, given data and weights

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

np.cov(a)
# array([[ 0.91666667, 2.08333333],
#        [ 2.08333333, 8.91666667]])

np.cov(a, ddof=0)
# array([[0.6875, 1.5625],
#       [1.5625, 6.6875]])

2.4.3. Pearson product-moment correlation coefficients

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

np.corrcoef(a)
# array([[ 1. , 0.72870505],
#        [ 0.72870505, 1. ]])

2.5. Random numbers

  • Mersenne Twister algorithm for pseudorandom number generation

2.5.1. Seed the generator

np.random.seed(293423)

2.5.2. Random values in a given shape

  • Random samples from a uniform distribution over [0, 1)

np.random.rand(5)
# array([ 0.40783762, 0.7550402 , 0.00919317, 0.01713451, 0.95299583])

np.random.rand(2,3)
# array([[ 0.50431753, 0.48272463, 0.45811345],
#        [ 0.18209476, 0.48631022, 0.49590404]])

np.random.rand(6).reshape((2,3))
# array([[ 0.72915152, 0.59423848, 0.25644881],
#        [ 0.75965311, 0.52151819, 0.60084796]])

2.5.3. Random floats in the half-open interval [0.0, 1.0)

  • Results are from the “continuous uniform” distribution over the stated interval

np.random.random()
# 0.70110427435769551

2.5.4. Random integers from low (inclusive) to high (exclusive)

np.random.randint(5, 10)
# 9

2.5.5. Draw samples from a Poisson distribution

np.random.poisson(6.0)  # Poisson distribution with lambda = 6.0
# 5

2.5.6. Draw random samples from a normal (Gaussian) distribution

np.random.normal(1.5, 4.0)  # continuous normal (Gaussian) distribution with mean micro=1.5 and standard deviation sigma=4.0
# 0.83636555041094318

np.random.normal()  # micro=0.0, sigma=1.0
# 0.27548716940682932

np.random.normal(size=5)
# array([-1.67215088, 0.65813053, -0.70150614, 0.91452499, 0.71440557])

2.5.7. Modify a sequence in-place by shuffling its contents

arr = list(range(10))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

np.random.shuffle(arr)
# [4, 9, 5, 0, 2, 7, 6, 8, 1, 3]

Multi-dimensional arrays are only shuffled along the first axis:

arr = np.arange(9).reshape((3, 3))

np.random.shuffle(arr)
# array([[3, 4, 5],
#       [6, 7, 8],
#       [0, 1, 2]])

2.6. Polynomial mathematics

2.6.1. Defining polynomial

Ax^3 + Bx^2 + Cx^1 + D
np.poly([-1, 1, 1, 10])
# array([ 1, -11, 9, 11, -10])

2.6.2. Roots of a polynomial

np.roots([1, 4, -2, 3])
# array([-4.57974010+0.j , 0.28987005+0.75566815j, 0.28987005-0.75566815j])

np.roots([ 1, -11, 9, 11, -10])
#array([10.+0.0000000e+00j, -1.+0.0000000e+00j,
#       1.+9.6357437e-09j, 1.-9.6357437e-09j])

2.6.3. Antiderivative (indefinite integral) of a polynomial

np.polyint([1, 1, 1, 1])
# array([ 0.25 , 0.33333333, 0.5 , 1. , 0. ])

2.6.4. Derivatives

np.polyder([1./4., 1./3., 1./2., 1., 0.])
# array([ 1., 1., 1., 1.])

2.6.5. Evaluate a polynomial at specific values

np.polyval([1, -2, 0, 2], 4)
# 34

2.6.6. Least squares polynomial fit

x = [1, 2, 3, 4, 5, 6, 7, 8]
y = [0, 2, 1, 3, 7, 10, 11, 19]

np.polyfit(x, y, 2)
# array([ 0.375 , -0.88690476, 1.05357143])

2.6.7. Polynomial Arithmetic

  • np.polyadd()

  • np.polysub()

  • np.polymul()

  • np.polydiv()

Find the sum of two polynomials:
np.polyadd([1, 2], [9, 5, 4])
# array([9, 6, 6])

2.7. Arrays

2.7.1. Create array

  • From list:

    import numpy as np
    
    np.array([1, 2, 3])
    # [1, 2, 3]
    
    np.array([1, 4, 5, 8], float)
    # array([ 1., 4., 5., 8.])
    
    np.array([[1,2], [3,4]])
    # array([[1, 2],
    #        [3, 4]])
    
  • Generate array:

    import numpy as np
    
    np.arange(3)
    # array([0, 1, 2])
    
    np.arange(3.0)
    # array([ 0.,  1.,  2.])
    
    np.arange(3, 7)
    # array([3, 4, 5, 6])
    
    np.arange(3, 7, step=2)
    # array([3, 5])
    
    np.arange(start=3, stop=7, step=2, dtype=float)
    # array([3., 5.])
    

2.7.2. Slice array

np.array([1, 4, 5, 8], float)
# array([ 1., 4., 5., 8.])

a[:2]
# array([ 1., 4.])

a[3]
# 8.0

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

a[0,0]  # 1.0
a[0,1]  # 2.0
a = np.array([[1, 2, 3], [4, 5, 6]], float)

a[1,:]      # array([ 4., 5., 6.])
a[:,2]      # array([ 3., 6.])
a[-1:,-2:]  # array([[ 5., 6.]])

2.7.3. Array shape

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

a.shape  # (2, 3)
a.dtype  # dtype('float64')
a = np.array([[1, 2, 3], [4, 5, 6]], int)

a.astype(float)
a.dtype  # dtype('float64')
a = np.array([[1, 2, 3], [4, 5, 6]], float)

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

2 in a
# True

0 in a
# False
a = np.array(range(10), float)
# array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])

a = a.reshape((5, 2))
# array([[ 0., 1.],
#        [ 2., 3.],
#        [ 4., 5.],
#        [ 6., 7.],
#        [ 8., 9.]])

a.shape
# (5, 2)
a = np.array([1, 2, 3], float)

b = a
c = a.copy()

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

b
# array([0., 2., 3.])

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

a.tolist()
# [1.0, 2.0, 3.0]

list(a)
# [1.0, 2.0, 3.0]
a = np.array([1, 2, 3], float)

s = a.tostring()
# '\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]'

np.fromstring(s)
# array([ 1., 2., 3.])

2.7.4. Array modification

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

a.fill(0)
# array([ 0., 0., 0.])
a = np.array(range(6), float).reshape((2, 3))
# array([[ 0., 1., 2.],
#        [ 3., 4., 5.]])

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

a.flatten()
# array([ 1., 2., 3., 4., 5., 6.])
a = np.array(range(6), float).reshape((2, 3, 1))
# array([[[0.],
#         [1.],
#         [2.]],
#
#        [[3.],
#         [4.],
#         [5.]]])

2.7.5. Concatenation

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

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

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

np.concatenate((a,b), axis=0)
# array([[ 1., 2.],
#        [ 3., 4.],
#        [ 5., 6.],
#        [ 7., 8.]])

np.concatenate((a,b), axis=1)
# array([[ 1., 2., 5., 6.],
#        [ 3., 4., 7., 8.]])
a = np.array([1, 2, 3], float)
# array([1., 2., 3.])

a[:,np.newaxis]
# array([[ 1.],
#        [ 2.],
#        [ 3.]])

a[:,np.newaxis].shape
# (3,1)

b[np.newaxis,:]
# array([[ 1., 2., 3.]])

b[np.newaxis,:].shape
# (1,3)
n1 = np.array([1,2,3])
n2 = np.array([[1,2],[3,4]])

f'Wymiar: n1: {n1.ndim}, n2: {n2.ndim}'
# Wymiar: n1: 1, n2: 2

f'Kształt: n1: {n1.shape}, n2: {n2.shape}'
# Kształt: n1: (3,), n2: (2, 2)

f'Rozmiar: n1: {n1.size}, n2: {n2.size}'
# Rozmiar: n1: 3, n2: 4

f'Typ: n1: {n1.dtype}, n2: {n2.dtype}'
# Typ: n1: int32, n2: int32

f'Rozmiar elementu (w bajtach): n1: {n1.itemsize}, n2: {n2.itemsize}'
# Rozmiar elementu (w bajtach): n1: 4, n2: 4

f'Wskaźnik do danych: n1: {n1.data}, n2: {n2.data}'
# Wskaźnik do danych: n1: <memory at 0x000001B93EC75348>, n2: <memory at 0x000001B93EC5BB40>

W przeciwieństwie do kolekcji, tablice mogą mieć tylko jeden typ elementu, choć może być złożony https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html

for v in [1, 1., 1j]:
   a = np.array([v])
   print('Tablica: {}, typ: {}'.format(a, a.dtype))

# Można też wymusić typ przy tworzeniu tablicy
a = np.array([1], dtype=str)

f'Tablica: {a}, typ: {a.dtype}'
# Tablica: [1], typ: int32
# Tablica: [1.], typ: float64
# Tablica: [0.+1.j], typ: complex128
# Tablica: ['1'], typ: <U1
np.arange(1,10)
# [1 2 3 4 5 6 7 8 9]

np.zeros((2,3))
# [[0. 0. 0.]
#  [0. 0. 0.]]

np.ones((3,2))
# [[1. 1.]
#  [1. 1.]
#  [1. 1.]]

np.empty((2,7))  # Bez inicjalizacji
# [[1.01855798e-312 1.18831764e-312 1.01855798e-312 9.54898106e-313
#   1.06099790e-312 1.03977794e-312 1.23075756e-312]
# [1.20953760e-312 1.06099790e-312 9.76118064e-313 1.01855798e-312
#  1.01855798e-312 1.16709769e-312 4.44659081e-322]]

np.random.rand(2,2)
# [[0.6468727  0.76909227]
#  [0.89730518 0.13993221]]
a = np.array([[1, 2, 3], [4, 5, 6]], float)

np.zeros_like(a)
# array([[ 0., 0., 0.],
#        [ 0., 0., 0.]])

np.ones_like(a)
# array([[ 1., 1., 1.],
#        [ 1., 1., 1.]])

np.identity(4, dtype=float)
# array([[ 1., 0., 0., 0.],
#        [ 0., 1., 0., 0.],
#        [ 0., 0., 1., 0.],
#        [ 0., 0., 0., 1.]])

2.7.6. Array slicing

n1 = np.array([1,2,3])
n2 = np.array([[1,2],[3,4]])

n1[1], n2[1][1]
# 2 4

n2[1,1]
# 4

n2[1,:]
# [3 4]

n2[:,1]
# [2 4]

n2[1,:1]
# [3]
a = np.random.randint(100,size=(2,3))
# [[38  5 91]
#  [26 33 65]]

2*a
# [[ 76  10 182]
#  [ 52  66 130]]

a**2
# [[1444   25 8281]
#  [ 676 1089 4225]]

a*a
# [[1444   25 8281]
#  [ 676 1089 4225]]

2.7.7. Array math operations

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

a + b
# array([6., 4., 9.])

a - b
# array([-4., 0., -3.])

a * b
# array([5., 4., 18.])

b / a
# array([5., 1., 2.])

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

b**a
# array([5., 4., 216.])
a = np.array([[1,2], [3,4]], float)
b = np.array([[2,0], [1,3]], float)

a * b
# array([[2., 0.], [3., 12.]])

Warning

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

2.7.8. Array Multiplication

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

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

a + b
# ValueError: shape mismatch: objects cannot be broadcast to a single shape
a = np.array([[1, 2], [3, 4], [5, 6]], float)
# array([[ 1., 2.],
#  [ 3., 4.],
#  [ 5., 6.]])

b = np.array([-1, 3], float)
# array([-1., 3.])

a + b
# array([[ 0., 5.],
#  [ 2., 7.],
#  [ 4., 9.]])
a = np.zeros((2,2), float)
# array([[ 0., 0.],
#        [ 0., 0.]])

b = np.array([-1., 3.], float)
# array([-1., 3.])

a + b
# array([[-1., 3.],
#        [-1., 3.]])

a + b[np.newaxis,:]
# array([[-1., 3.],
#        [-1., 3.]])

a + b[:,np.newaxis]
# array([[-1., -1.],
#        [ 3., 3.]])
a = np.array([1.1, 1.5, 1.9], float)

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

np.floor(a)
# array([ 1., 1., 1.])

np.ceil(a)
# array([ 2., 2., 2.])

np.rint(a)
# array([ 1., 2., 2.])
np.pi
# 3.1415926535897931

np.e
# 2.7182818284590451

np.nan
# NaN

np.inf
# inf

2.7.9. Array iteration

>>> a = np.array([1, 4, 5], int)

for x in a:
    print(x)

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

for x in a:
    print(x)

# [ 1. 2.]
# [ 3. 4.]
# [ 5. 6.]

2.7.10. Array operations

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

a.sum()
# 9.0

a.prod()
# 24.0
a = np.array([2, 1, 9], float)

a.mean()
# 4.0

a.var()
# 12.666666666666666

a.std()
# 3.5590260840104371

a.min()
# 1.0

a.max()
# 9.0

a.argmin()  # index of an ``a.min()`` element in array
# 1

a.argmax()  # index of an ``a.max()`` element in array
# 2
a = np.array([[0, 2], [3, -1], [3, 5]], float)

a.mean(axis=0)
# array([ 2., 2.])

a.mean(axis=1)
# array([ 1., 1., 4.])

a.min(axis=1)
# array([ 0., -1., 3.])

a.max(axis=0)
# array([ 3., 5.])
a = np.array([6, 2, 5, -1, 0], float)

sorted(a)
# [-1.0, 0.0, 2.0, 5.0, 6.0]

a.sort()
# array([-1., 0., 2., 5., 6.])
a = np.array([6, 2, 5, -1, 0], float)

a.clip(0, 5)
# array([ 5., 2., 5., 0., 0.])
a = np.array([1, 1, 4, 5, 5, 5, 7], float)

np.unique(a)
# array([ 1., 4., 5., 7.])
a = np.array([[1, 2], [3, 4]], float)

a.diagonal()
# array([ 1., 4.])

2.7.11. Array arithmetic

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

a * b
# array([[2., 0.], [3., 12.]])
a = np.array([1,2,3], float)
b = np.array([4,5], float)

a + b
# ValueError: shape mismatch: objects cannot be broadcast to a single shape
a = np.array([[1, 2], [3, 4], [5, 6]], float)
b = np.array([-1, 3], float)

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

b
# array([-1., 3.])

a + b
# array([[ 0., 5.],
#        [ 2., 7.],
#        [ 4., 9.]])
a = np.zeros((2,2), float)
# array([[ 0., 0.],
#        [ 0., 0.]])

b = np.array([-1., 3.], float)
# array([-1., 3.])

a + b
# array([[-1., 3.],
#        [-1., 3.]])

a + b[np.newaxis,:]
# array([[-1., 3.],
#        [-1., 3.]])

a + b[:,np.newaxis]
# array([[-1., -1.],
#        [ 3., 3.]])

2.7.12. Comparison operators and value testing

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

a > b
# array([ True, False, False], dtype=bool)

a == b
# array([False, True, False], dtype=bool)

a <= b
# array([False, True, True], dtype=bool)

c = a > b
# array([ True, False, False], dtype=bool)
a = np.array([1, 3, 0], float)
a > 2
# array([False, True, False], dtype=bool)
c = np.array([ True, False, False], bool)

any(c)
# True

all(c)
# False
a = np.array([1, 3, 0], float)

np.logical_and(a > 0, a < 3)
# array([ True, False, False], dtype=bool)
a = np.array([True, False, True], bool)

np.logical_not(a)
# array([False, True, False], dtype=bool)
a = np.array([True, False, True], bool)
b = np.array([False, True, False], bool)

np.logical_or(a, b)
# array([ True, True, False], dtype=bool)

2.7.12.1. Where

  • Single argument where where(boolarray):

    a = np.array([1, 3, 0], float)
    
    np.where(a != 0)
    # array([0, 1])  # indexes of elements
    
    
    b = np.array([1, 0, 3, 4, 0], float)
    np.where(b != 0)
    # array([0, 2, 3])
    
  • Multiple argument where where(boolarray, truearray, falsearray):

    a = np.array([1, 3, 0], float)
    
    np.where(a != 0, a, None)  # for element ``a != 0`` return such element, otherwise ``None``
    # array([1.0, 3.0, None], dtype=object)
    
    a = np.array([1, 3, 0], float)
    
    np.where(a != 0, 1 / a, a)
    # array([ 1. , 0.33333333, 0. ])
    
    a = np.array([1, 3, 0], float)
    
    np.where(a != 0, 1 / a, a)
    # array([ 1. , 0.33333333, 0. ])
    
    np.where(a > 0, 3, 2)
    # array([3, 3, 2])
    
    a = np.array([1, -3, 3, 0], float)
    np.logical_and(a > 0, a % 3 == 0)
    # array([False, False, True, False])
    

2.7.12.2. Nonzero

a = np.array([[0, 1], [3, 0]], float)
a.nonzero()
# (array([0, 1]), array([1, 0]))

2.7.12.3. IsFinite and IsNaN

a = np.array([1, np.NaN, np.Inf], float)
# array([ 1., NaN, Inf])

np.isnan(a)
# array([False, True, False], dtype=bool)

np.isfinite(a)
# array([True, False, False], dtype=bool)

2.7.13. Array item selection and manipulation

a = np.array([[6, 4], [5, 9]], float)

a >= 6
# array([[ True, False],
#        [False, True]], dtype=bool)

a[a >= 6]
# array([ 6., 9.])
a = np.array([[6, 4], [5, 9]], float)

sel = (a >= 6)
a[sel]
# array([ 6., 9.])

a[np.logical_and(a > 5, a < 9)]
# array([ 6.])
a = np.array([2, 4, 6, 8], float)
b = np.array([0, 0, 1, 3, 2, 1], int)

a[b]
# array([ 2., 2., 4., 8., 6., 4.])
a = np.array([2, 4, 6, 8], float)

a[[0, 0, 1, 3, 2, 1]]
# array([ 2., 2., 4., 8., 6., 4.])
a = np.array([[1, 4], [9, 16]], float)
b = np.array([0, 0, 1, 1, 0], int)
c = np.array([0, 1, 1, 1, 1], int)

a[b,c]
# array([ 1., 4., 16., 16., 4.])
a = np.array([2, 4, 6, 8], float)
b = np.array([0, 0, 1, 3, 2, 1], int)

a.take(b)
# array([ 2., 2., 4., 8., 6., 4.])
a = np.array([[0, 1], [2, 3]], float)
b = np.array([0, 0, 1], int)

a.take(b, axis=0)
# array([[ 0., 1.],
#        [ 0., 1.],
#        [ 2., 3.]])

a.take(b, axis=1)
# array([[ 0., 0., 1.],
#        [ 2., 2., 3.]])
a = np.array([0, 1, 2, 3, 4, 5], float)
b = np.array([9, 8, 7], float)

a.put([0, 3], b)
# array([ 9., 1., 2., 8., 4., 5.])
a = np.array([0, 1, 2, 3, 4, 5], float)

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

2.8. Vector and matrix mathematics

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

np.dot(a, b)
# 5.0
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.]])
a = np.array([1, 4, 0], float)
b = np.array([2, 2, 1], float)

np.outer(a, b)
# array([[ 2., 2., 1.],
#        [ 8., 8., 4.],
#        [ 0., 0., 0.]])

np.inner(a, b)
# 10.0

np.cross(a, b)
# array([ 4., -1., -6.])
a = np.array([[4, 2, 0], [9, 3, 7], [1, 2, 1]], float)
# array([[ 4., 2., 0.],
#        [ 9., 3., 7.],
#        [ 1., 2., 1.]])

np.linalg.det(a)
# -53.999999999999993
a = np.array([[4, 2, 0], [9, 3, 7], [1, 2, 1]], float)
# array([[ 4., 2., 0.],
#        [ 9., 3., 7.],
#        [ 1., 2., 1.]])

vals, vecs = np.linalg.eig(a)

vals
# array([ 9. , 2.44948974, -2.44948974])

vecs
# array([[-0.3538921 , -0.56786837, 0.27843404],
#        [-0.88473024, 0.44024287, -0.89787873],
#        [-0.30333608, 0.69549388, 0.34101066]])
a = np.array([[4, 2, 0], [9, 3, 7], [1, 2, 1]], float)
# array([[ 4., 2., 0.],
#        [ 9., 3., 7.],
#        [ 1., 2., 1.]])

b = np.linalg.inv(a)
# array([[ 0.14814815, 0.07407407, -0.25925926],
#        [ 0.2037037 , -0.14814815, 0.51851852],
#        [-0.27777778, 0.11111111, 0.11111111]])

np.dot(a, b)
# array([[ 1.00000000e+00, 5.55111512e-17, 2.22044605e-16],
#        [ 0.00000000e+00, 1.00000000e+00, 5.55111512e-16],
#        [ 1.11022302e-16, 0.00000000e+00, 1.00000000e+00]])
a = np.array([[1, 3, 4], [5, 2, 3]], float)

U, s, Vh = np.linalg.svd(a)

U
# array([[-0.6113829 , -0.79133492],
#        [-0.79133492, 0.6113829 ]])

s
# array([ 7.46791327, 2.86884495])
Vh
# array([[-0.61169129, -0.45753324, -0.64536587],
#        [ 0.78971838, -0.40129005, -0.46401635],
#        [-0.046676 , -0.79349205, 0.60678804]])

2.9. Matrix

Numpy ma również typ macierzy matrix. Jest on bardzo podobny do tablicy ale podstawowe operacje wykonywane są w sposób macierzowy a nie tablicowy.

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

a * b
# [[19 22]
#  [43 50]]

a ** 2
# [[ 7 10]
#  [15 22]]

a * 2
# [[2 4]
#  [6 8]]
d = np.diag([3,4])
# [[3 0]
#  [0 4]]

d * m
# [[ 3  6]
#  [12 16]]

Niemniej, tablice można używać podobnie, ale do mnożenia trzeba wykorzystywać funkcje dot:

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

a * b
# [[ 5 12]
#  [21 32]]

a.dot(b)
# [[19 22]
#  [43 50]]

a ** 2
#  [[ 1  4]
#   [ 9 16]]

a * 2
# [[2 4]
#  [6 8]]

Dodatkowo, operacje algebry liniowej można wykonywać zarówno na tablicach jak i macierzach, np:

print('det(m) = {}'.format(np.linalg.det(m)))
print('det(a) = {}'.format(np.linalg.det(a)))

2.10. Linear Algebra

Table 82. Linear algebra basics

Function

Description

norm

Vector or matrix norm

inv

Inverse of a square matrix

solve

Solve a linear system of equations

det

Determinant of a square matrix

slogdet

Logarithm of the determinant of a square matrix

lstsq

Solve linear least-squares problem

pinv

Pseudo-inverse (Moore-Penrose) calculated using a singular value decomposition

matrix_power

Integer power of a square matrix

matrix_rank

Calculate matrix rank using an SVD-based method

Table 83. Eigenvalues and decompositions

Function

Description

eig

Eigenvalues and vectors of a square matrix

eigh

Eigenvalues and eigenvectors of a Hermitian matrix

eigvals

Eigenvalues of a square matrix

eigvalsh

Eigenvalues of a Hermitian matrix

qr

QR decomposition of a matrix

svd

Singular value decomposition of a matrix

cholesky

Cholesky decomposition of a matrix

Table 84. Tensor operations

Function

Description

tensorsolve

Solve a linear tensor equation

tensorinv

Calculate an inverse of a tensor

Table 85. Exceptions

Function

Description

LinAlgError

Indicates a failed linear algebra operation

2.11. Euclidean distance

../_images/k-nearest-neighbors-euclidean-distance2.png

Figure 64. Wyliczanie odległości w celu oszacowania przynależności do zbioru. Zwróć uwagę, że bez względu na ilość wymiarów wzór się niewiele różni.

2.12. Assignments

2.12.1. Matrix multiplication

  • Complexity level: easy

  • Lines of code to write: 2 lines

  • Estimated time of completion: 5 min

  • Filename: solution/numpy_matmul.py

  1. Używając numpy oraz operatora @ oraz *

  2. Czym 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)
    [[4, 1], [2, 2]]

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

2.12.2. Array filtering

  1. Ustaw ziarno losowości na 0

  2. Wygeneruj macierz (50x50) o nazwie A

  3. Macierz ma składać się z losowych liczb całkowitych z zakresu od 0 do 1024 włącznie.

  4. Stwórz macierz B, która będzie zawierała liczby z macierzy A będące potęgami dwójki.

  5. Pozostaw tylko i wyłącznie unikalne wartości.

  6. Uporządkuj macierz B w kolejności malejącej (od największej do najmniejszej).

2.12.3. Sum of inner matrix

  1. Ustaw ziarno losowości na 0

  2. Wygeneruj macierz (16x16) randomowych intów o wartościach od 10 do 100

  3. Przekonwertuj macierz na typ float

  4. Transponuj ją

  5. Policz sumę środkowych (4x4) elementów macierzy

  6. Wyświetl wartość (skalar) sumy, a nie nie wektor

2.12.4. Euclidean distance 2D

  1. Dany jest np.array przechowujący wektor

  2. Dane są dwa punkty A i B o podanych koordynatach tuple

  3. Punkty A i B są dwuwymiarowe (x, y)

  4. Oblicz odległość między nimi

  5. Wykorzystaj algorytm Euklidesa euclidean_distance(a, b) = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}

  6. Funkcja musi przechodzić doctest Listing 489.

Listing 489. Euclidean distance 2D
def euclidean_distance(a, b):
    """
    >>> a = (1, 0)
    >>> b = (0, 1)
    >>> euclidean_distance(a, b)
    1.4142135623730951

    >>> euclidean_distance((0,0), (1,0))
    1.0

    >>> euclidean_distance((0,0), (1,1))
    1.4142135623730951

    >>> euclidean_distance((0,1), (1,1))
    1.0

    >>> euclidean_distance((0,10), (1,1))
    9.055385138137417
    """
    return

2.12.5. Euclidean distance multi dimensions

  1. Dane są dwa punkty A i B o podanych koordynatach tuple

  2. Punkty A i B są na N-wymiarowej przestrzeni (x, y, ...)

  3. Punkty A i B muszą być równo-wymiarowe

  4. Wykorzystaj algorytm Euklidesa euclidean_distance(a, b) = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + ... + (n_2 - n_1)^2}

  5. Funkcja musi przechodzić doctest Listing 490.

Listing 490. Euclidean distance N-dimension
def euclidean_distance(a, b):
    """
    >>> a = (0,1,0,1)
    >>> b = (1,1,0,0)
    >>> euclidean_distance(a, b)
    1.4142135623730951

    >>> euclidean_distance((0,0,0), (0,0,0))
    0.0

    >>> euclidean_distance((0,0,0), (1,1,1))
    1.7320508075688772

    >>> euclidean_distance((0,1,0,1), (1,1,0,0))
    1.4142135623730951

    >>> euclidean_distance((0,0,1,0,1), (1,1,0,0,1))
    1.7320508075688772

    >>> euclidean_distance((0,0,1,0,1), (1,1))
    Traceback (most recent call last):
        ...
    ValueError: Punkty muszą być w przestrzeni tylu-samo wymiarowej
    """
    return

2.12.6. Szukanie liczby

  • Complexity level: medium

  • Lines of code to write: 10 lines

  • Estimated time of completion: 15 min

  • Filename: solution/numpy_number.py

  1. Mamy liczbę trzycyfrową.

  2. Jeżeli od liczny dziesiątek odejmiemy liczbę jedności otrzymamy 6.

  3. Jeżeli do liczby dziesiątek dodamy liczbę jedności otrzymamy 10.

  4. Znajdź wszystkie liczby trzycyfrowe spełniające ten warunek

  5. Znajdź liczby trzycyfrowe podzielne przez 3

Hints
  • Ax=B

  • x=A−1B

liczba_dziesiatek - liczba_jednosci = 6
liczba_dziesiatek + liczba_jednosci = 10

liczba_dziesiatek = liczba_jednosci + 6
liczba_dziesiatek + liczba_jednosci = 10

liczba_dziesiatek = liczba_jednosci + 6
(liczba_jednosci + 6) + liczba_jednosci 10

liczba_dziesiatek = liczba_jednosci + 6
2 * liczba_jednosci + 6 = 10

liczba_dziesiatek = liczba_jednosci + 6
liczba_jednosci = 8 / 2

liczba_dziesiatek = 2 + 6
liczba_jednosci = 2

liczba_dziesiatek = 8
liczba_jednosci = 2
x1 - x2 = 6
x1 + x2 = 10

x1 = 6 + x2
6 + x2 + x2 = 10

2 * x2 = 4
x2 = 2
x1 = 8


import numpy as np

A = np.matrix([[1, -1], [1, 1]])
# matrix([[ 1, -1],
#        [ 1,  1]])

B = np.matrix([6, 10]).T  # Transpose matrix
# matrix([[ 6],
#        [10]])

x = A**(-1) * B
# matrix([[8.],
#        [2.]])

A*x == B
# matrix([[ True],
#        [ True]])

res1 = np.arange(1, 10)*100 + 10*x[0,0] + 1*x[1,0]
# array([182., 282., 382., 482., 582., 682., 782., 882., 982.])

res1[res1 % 3 == 0]
# array([282., 582., 882.])

m = res1 % 3 == 0
# array([False,  True, False, False,  True, False, False,  True, False])

res1[m]
# array([282., 582., 882.])

res2 = res1[m]
# array([282., 582., 882.])