Линейная алгебра с Numpy

import numpy as np

NumPy это open-source модуль для python, который предоставляет общие математические и числовые операции в виде пре-скомпилированных, быстрых функций. Они объединяются в высокоуровневые пакеты. Они обеспечивают функционал, который можно сравнить с функционалом MatLab. NumPy (Numeric Python) предоставляет базовые методы для манипуляции с большими массивами и матрицами. SciPy (Scientific Python) расширяет функционал numpy огромной коллекцией полезных алгоритмов, таких как минимизация, преобразование Фурье, регрессия, и другие прикладные математические техники.

numpy arrays

Массивы бывают 1-мерные (вектора) 2-мерные (матрицы) и многомерные (условно тензоры).

Все элементы массива должны принадлежать к одному типу данных.

Создадим одномерный массив из списка при помощи функции array:

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

Создадим двумерный массив из списка при помощи функции array. Обратите внимание на скобки.

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

Но проще создавать массивы при помощи функции arange.

np.arange(10, 101, 10)
array([ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])

Для создания специфических массивов надо использовать специальные методы. Нарпимер, zeros создаёт массив нулей.

np.zeros(3)
array([0., 0., 0.])

А метод ones создаёт массив единиц.

np.ones(3)
array([1., 1., 1.])

Для создания двуменых массивов необходимо передать функции кортеж, первый элемент которого обозначат количество строк, а второй — столбцов.

Для создания массива с необходимым количеством линейнораспределённых элементов из заданного промежутка используется функция linspace.

np.linspace(10, 100, num=15)
array([ 10. , 16.42857143, 22.85714286, 29.28571429,
35.71428571, 42.14285714, 48.57142857, 55. ,
61.42857143, 67.85714286, 74.28571429, 80.71428571,
87.14285714, 93.57142857, 100. ])

Для создания единично матрицы используется функция eye. Ей можно задавать смещение.

np.eye(5, k=2)
array([[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])

Массивы случайных чисел

Можно создавать массивы со случайными числами при помощи функции rand() модуля random.

np.random.rand(4)
array([0.26437504, 0.94408227, 0.04647417, 0.70050205])

Для получения случайных чисел из нормального распределения используем функцию randn() из модуля random. Для создания матрицы случайных чисел надо передать функции два числа, не кортеж

np.random.randn(5)
array([ 0.45133976, -1.59993226, 1.03351685, 0.56488102, 0.91875806])

с равномерным распределением всё похоже

np.random.uniform(10, 100, (3, 3))
array([[88.60061463, 20.51125522, 29.51395969],
[29.03225571, 79.52490546, 71.89740721],
[89.91924457, 46.51368169, 24.74561669]])
np.random.randint(2, 100)
35

Атрибуты и методы массивов

Попробуем узнавать различную информацию о массивах и производить манипуляции с ними при помощи свойств и методов массивов.

arr = np.arange(25)

Размерность массива можно узнать при помощи функции свойства shape.

arr.shape
(25,)

Свойство dtype возващяет тип переменной.

arr.dtype
dtype('int64')
matrix = arr.reshape(5, 5)
matrix
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])

Также можно находить максимум и минимум при помощи методов max, min, argmax, argmin, счиатать средние значения, стандартные отклонения и многое другое.

arr.std()
7.211102550927978

Индексация массивов

arr
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24])

В базовом виде работает как в обычном Питоне.

arr[0:11:2]
array([ 0, 2, 4, 6, 8, 10])

Для срайсам по различным измерениям многомерных массивов указываем их через запятую

matrix[1:4, :]
array([[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])

Броадкастинг

arr*3
array([ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48,
51, 54, 57, 60, 63, 66, 69, 72])

Но будьте осторожны — тут мы всего лишь создаём ссылки на элементы массива arr с 0 по 5:

a = arr[:5]
a[:] = 9
arr
array([ 9, 9, 9, 9, 9, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24])

Выбор по условию

arr < 10
array([ True, True, True, True, True, True, True, True, True,
True, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False])
arr[arr < 10]
array([9, 9, 9, 9, 9, 5, 6, 7, 8, 9])

Базовые операции в numpy

+, -, *, /, **, sqrt, exp, sin, log, max, mix, mean и др.: https://docs.scipy.org/doc/numpy-1.13.0/reference/ufuncs.html

Для большинства операций можно указывать ось, по которой она будет производиться:

matrix.sum()
335
matrix.sum(axis=0) # сумма по столбцам
array([59, 63, 67, 71, 75])

Кстати говоря, на 0 делить разрешено

2/0
ZeroDivisionError: division by zero
np.array([-1, 2, 3]) / np.array([0, 2, 3])
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in true_divide
"""Entry point for launching an IPython kernel.
array([-inf, 1., 1.])

Практическое задание

Напишите функцию decorate_matrix, которая получает на вход одно целое число больше единицы. Функция должна возвращать матрицу n на n, у которой на границах стоят единицы, а на всех остальных позициях(если остались позиции не на границах) стоят нули.

# ожидаемый резальтат для аргумента 5
array([[1., 1., 1., 1., 1.],
[1., 0., 0., 0., 1.],
[1., 0., 0., 0., 1.],
[1., 0., 0., 0., 1.],
[1., 1., 1., 1., 1.]])

Практическое задание

Создайте массив класса np.ndarray ширины 4 и высоты 3 с двойками на главной диагонали и единицами на первой диагонали над главной, т.е. воплощение матрицы

np.eye(3, M=4) * 2 + np.eye(3, M=4, k=1)
array([[2., 1., 0., 0.],
[0., 2., 1., 0.],
[0., 0., 2., 1.]])

Практическое задание

Создайте матрицу чисел от 1 до 25 размерностью 5×5

mat = np.arange(1, 26).reshape(5, 5)
mat
array([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]])

Обрежьте её следующим образом:

mat[2: , 2:]
array([[13, 14, 15],
[18, 19, 20],
[23, 24, 25]])

Обработка изображений

import numpy as np
import matplotlib.pylab as plt

%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt

random_image = np.random.random([500, 500])

plt.imshow(random_image, cmap='gray', interpolation='nearest');
import requests


with open("lenna.png", "wb") as img_f:
    img_f.write(requests.get("https://i.stack.imgur.com/nL4u3.png").content)

im = plt.imread("lenna.png")
im.shape
(220, 220, 4)
def plti(im, h=6, **kwargs):
    """
    Helper function to plot an image.
    """
    y = im.shape[0]
    x = im.shape[1]
    w = (y/x) * h
    plt.figure(figsize=(w,h))
    plt.imshow(im, interpolation="nearest", **kwargs)
    plt.axis('off')

plti(im)

Удалим прозрачность

im = im[:,:,:3]

Обрежьте изображения до плеча

plti(im[20:200, 0:100, :])

Получите негатив изображения

plti(1 - im)

Сделайте изображение чёрно-белым

plti(np.mean(im, axis=2), cmap='gist_gray')

Поместите жёлтый квадрат 100×100px в верхнем левом углу

im[:100, :100]
array([[[0.88235295, 0.5372549 , 0.49803922],
[0.8784314 , 0.53333336, 0.49803922],
[0.8901961 , 0.5254902 , 0.46666667],
...,
[0.7882353 , 0.4117647 , 0.39607844],
[0.8 , 0.4117647 , 0.3882353 ],
[0.80784315, 0.39215687, 0.3882353 ]],

[[0.88235295, 0.5372549 , 0.49803922],
[0.8784314 , 0.53333336, 0.49803922],
[0.8901961 , 0.5254902 , 0.46666667],
...,
[0.7882353 , 0.40784314, 0.39607844],
[0.8 , 0.4117647 , 0.3882353 ],
[0.80784315, 0.39215687, 0.3882353 ]],

[[0.8901961 , 0.5372549 , 0.47843137],
[0.88235295, 0.5254902 , 0.4627451 ],
[0.89411765, 0.52156866, 0.45882353],
...,
[0.79607844, 0.39607844, 0.38431373],
[0.8 , 0.4117647 , 0.39215687],
[0.78431374, 0.3882353 , 0.3882353 ]],

...,

[[0.7019608 , 0.2627451 , 0.31764707],
[0.69411767, 0.28627452, 0.32941177],
[0.6901961 , 0.2784314 , 0.32156864],
...,
[0.52156866, 0.34117648, 0.48235294],
[0.48235294, 0.2627451 , 0.44705883],
[0.29411766, 0.02745098, 0.19607843]],

[[0.7019608 , 0.28627452, 0.31764707],
[0.7058824 , 0.29411766, 0.32156864],
[0.6901961 , 0.28627452, 0.32156864],
...,
[0.45882353, 0.24313726, 0.42352942],
[0.5568628 , 0.4 , 0.5764706 ],
[0.3254902 , 0.05098039, 0.23921569]],

[[0.7058824 , 0.27450982, 0.32156864],
[0.69803923, 0.2901961 , 0.33333334],
[0.6901961 , 0.28627452, 0.3254902 ],
...,
[0.49803922, 0.27450982, 0.47058824],
[0.6392157 , 0.52156866, 0.65882355],
[0.36078432, 0.09803922, 0.2784314 ]]], dtype=float32)
im[:5, :5, :]
array([[[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.]],

[[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.]],

[[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.]],

[[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.]],

[[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.],
[1., 1., 0.]]], dtype=float32)
im[:100, :100, :] = [1, 1, 0]
plti(im)