Занятие 3

Лабораторная работа 3

NumPy(сокращенно от Numerical Python)— библиотека с открытым исходным кодом для языка программирования Python.

  • поддержмвает многомерные массивы (включая матрицы)
  • поддерживает высокоуровневые математические функции, предназначенные для работы с многомерными массивами.

NumPy обеспечивает как гибкость Python, так и скорость хорошо оптимизированного скомпилированного кода на C.

Если у вас ещё не установлен Numpy это можно сделать командой: pip install numpy

Туторила NumPy: https://numpy.org

0. Массивы в Numpy

  • Массив в NumPy это таблица элементов одного типа, пронумерованная кортежем положительных целых чисел.
  • В NumPy измерения называются осями. Количество осей является рангом.
  • Класс массива NumPy называется ndarray.

Обратите внимание, что массив в Numpy содержит элементы одного типа, в отличие от списка!

In [2]:
import numpy as np # импортируем библиотеку и заменим её ключевым словом np(для удобства)

1. Создание массива

Есть несколько способов создать массив NumPy. Рассмотрим их подробнее:

1. Создание из списков или кортежей

Вы можете создать массив, передав списки или кортежи в функцию np.array():

In [3]:
# Создание одномерного массива
array_1d = np.array([1, 2, 3, 4, 5])
print(array_1d)

# Создание двумерного массива
array_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(array_2d)
[1 2 3 4 5]
[[1 2 3]
 [4 5 6]]

2. Создание пустых, нулевых и единичных массивов

Для создания массивов, заполненных нулями, единицами или пустых (неинициализированных), можно использовать следующие функции:

  • np.zeros(shape): создает массив, заполненный нулями.
  • np.ones(shape): создает массив, заполненный единицами.
  • np.empty(shape): создает пустой массив (значения не инициализированы).
In [4]:
# Массив нулей
zeros_array = np.zeros((2, 3))
print(zeros_array)

# Массив единиц
ones_array = np.ones((3, 2))
print(ones_array)

# Пустой массив
empty_array = np.empty((2, 2))
print(empty_array)
[[0. 0. 0.]
 [0. 0. 0.]]
[[1. 1.]
 [1. 1.]
 [1. 1.]]
[[0. 0.]
 [0. 0.]]

3. Создание массивов с равномерным распределением

Для создания массивов с равномерным распределением чисел можно использовать функции np.arange() и np.linspace():

  • np.arange(start, stop, step): создает массив чисел от start до stop с заданным шагом.
  • np.linspace(start, stop, num): создает массив из num равномерно распределенных точек между start и stop.
In [5]:
# Массив с использованием np.arange
arange_array = np.arange(0, 10, 2)  # от 0 до 10 с шагом 2
print(arange_array)

# Массив с использованием np.linspace
linspace_array = np.linspace(0, 1, 5)  # 5 равномерных точек от 0 до 1
print(linspace_array)
[0 2 4 6 8]
[0.   0.25 0.5  0.75 1.  ]

4. Создание массивов с нормальным распределением

Массивы, заполненные случайными числами, можно создавать с помощью функции np.random:

In [6]:
# Массив с нормально распределёнными числами
random_array = np.random.normal(loc=0.0, scale=1.0, size=(2, 3))  # 2x3 массив
print(random_array)
[[ 0.68034811  1.04777232  0.54527467]
 [-0.62004137 -1.02943094  0.71602192]]

5. Создание идентичного массива

Для создания единичной матрицы (матрицы, в которой все элементы на главной диагонали равны 1, а остальные равны 0):

In [7]:
identity_matrix = np.eye(3)  # Создание 3x3 единичной матрицы
print(identity_matrix)
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

6. Повторение и объединение массивов

Вы можете использовать функции np.tile() и np.concatenate() для повторения или объединения массивов:

  • np.tile(array, reps): повторяет массив reps раз.
  • np.concatenate((array1, array2), axis): объединяет два массива по указанному оси.

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

1. Одномерная индексация

Для одномерных массивов вы можете использовать обычные квадратные скобки [] и указывать индекс элемента. Индексы начинаются с 0.

In [8]:
# Создание одномерного массива
array_1d = np.array([10, 20, 30, 40, 50])

# Индексация
print(array_1d[0])  # 10 (первый элемент)
print(array_1d[2])  # 30 (третий элемент)
10
30

2. Индексация двумерных массивов

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

In [9]:
# Создание двумерного массива
array_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# Индексация
print(array_2d[0, 1])  # 2 (первая строка, второй столбец)
print(array_2d[2, 0])  # 7 (третья строка, первый столбец)
2
7

3. Срезы

Срезы в NumPy работают аналогично обычным спискам Python. Вы можете указать начальный и конечный индексы, и NumPy извлечет элементы в заданном диапазоне.

In [10]:
# Срез для одномерного массива
print(array_1d[1:4])  # [20 30 40]

# Срез для двумерного массива
print(array_2d[0:2, 1:3])  # [[2 3]
                           #  [5 6]]
[20 30 40]
[[2 3]
 [5 6]]

4. Индексация с помощью массивов

Вы можете использовать логическую маску или массив индексов для извлечения данных.

In [11]:
# Индексация с помощью логической маски
mask = array_1d > 30
print(array_1d[mask])  # [40 50]
[40 50]

5. Изменение элементов

Вы можете изменять значения элементов массива, используя индексы.

In [12]:
array_1d[0] = 100
print(array_1d)  # [100 20 30 40 50]
[100  20  30  40  50]

3. Операции над массивами

1 Математические операции

In [92]:
# создадим два массива
a = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
b = np.array([(19, 20, 21), (22, 23, 24), (25, 26, 27)])

Мы можем складывать, умножать, делить, считать остаток и т.д поэлементно.

In [93]:
# сумма
print(a + b)
[[20 22 24]
 [26 28 30]
 [32 34 36]]
In [94]:
# разность
print(a - b)
[[-18 -18 -18]
 [-18 -18 -18]
 [-18 -18 -18]]
In [95]:
# умножение
print(a * b)
[[ 19  40  63]
 [ 88 115 144]
 [175 208 243]]
In [96]:
# остаток от деления
print(b % a)
[[0 0 0]
 [2 3 0]
 [4 2 0]]
In [97]:
# Также, в numpy есть библиотека стандартных мат функций, которые можно применить к каждому элементу массива. 
a = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
np.sqrt(a)
Out[97]:
array([[1.        , 1.41421356, 1.73205081],
       [2.        , 2.23606798, 2.44948974],
       [2.64575131, 2.82842712, 3.        ]])

2 Базовые операции с массивыми

In [98]:
a = np.array([(1, 2, 3, 4, 5, 6, 7, 8, 9)])
# сумма элементов
print(a.sum())
# произведение элементов
print(a.prod())
# макс и мин элемент
print(a.max())
print(a.min())
# среднее значение
print(a.mean())
# дисперсия
print(a.var())
45
362880
9
1
5.0
6.666666666666667

P.S NumPy - мощный интсрумент, который содержит в себе много функций и методов.

Обращайтесь к туториалу: https://numpy.org/devdocs/user/quickstart.html

И не бойтесь гуглить!

Задача 1

Создайте две numpy матрицы, содержащие температуры в Кельвинах и Фаренгейтах на основе матрицы температур в Цельсиях.

In [99]:
a = np.array([(14, 23, 31, 14, 55, 36, 87, 118, 91)]) # матрица температур(в Цельсиях)
In [ ]:

Задача 2

Создайте матрицу с 0 внутри и 1 на границах.

In [ ]:

3 Умножения матриц

In [100]:
a = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
a = np.array([(1), (4), (7)])
# можем так
print(a @ b)
# а можем так
print(a.dot(b))
[282 294 306]
[282 294 306]

Задача 3

Посчитайте произведение матриц используя:

  • @
  • dot
  • не используя ни dot, ни @
In [101]:
A = np.array([[1.0, 2.0, 3.0],
              [4.0, 5.0, 6.0]])
B = np.array([[11.0, 12.0],
              [13.0, 14.0],
              [15.0, 16.0]])
In [ ]:

Задача 4

Мы можем расчитать норму вектора: np.linalg.norm([1.0, 2.0, 3.0]).

Найдите косинус угла между векторами:

  • используя np.linalg.norm
  • не используя
In [102]:
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])
In [ ]:

4. Линейнай алгебра в NumPy

1 Решение систем линейных уравнений

Библиотеку numpy удобно использовать для решения систем линейных уравнений. Если система уравнений $Ax = y$ имеет решение, и при этом только одно, то оно выражается как $x = A^{-1}y$ . Для обращения матрицы используется функция np.linalg.inv. Рассмотрим систему уравнений: $$ \left\{ \begin{array}{c} 2x + z = 1 \\ x - z = 4 \\ \end{array} \right. $$

In [103]:
A = np.array([[2.0, 1.0],
              [1.0, -1.0]])
y = np.array([1.0, 4.0])
# решение будет
print(np.linalg.inv(A) @ y)
[ 1.66666667 -2.33333333]

Задача 5

Решите следующую систему:

$$ \left\{ \begin{array}{c} 2x+3y+4z = 5 \\ x-y+z=3 \\ 2x+6y-3z=4 \end{array} \right. $$
In [ ]:

2 Ещё немного линейной алгебры

Задача 6

Дана матрица B.

Найдите её:

  • детерминант
  • ранг
  • собственные значения
In [104]:
B = np.array([[11.0, 12.0],
              [13.0, 14.0]])
In [ ]:

5. Математика многочленов

1 np.poly

In [105]:
# np.poly - передаём список корней, получаем коэффициенты уравнения, которое имеет данные корни:
np.poly([-1, 1, 2])
Out[105]:
array([ 1., -2., -1.,  2.])

Получили уравнение:

$x^3 -2x^2 -x + 2 =0$

2 roots

In [106]:
# np.roots - передаём список коэффициентов уравнения, возвращаем корни.
np.roots([1, -5, 6])
Out[106]:
array([3., 2.])

Мы решили уравнение: $x^2 - 5x + 6 = 0$

Задача 7

Напишите функцию решающую квадратное уравнение и принимающую на вход коэффициенты этого уравнения.

In [ ]:

Задача 8

Теперь решите задачу 7, не используя np.roots.

Почувствуйте разницу)

6. Продвинутые методы numpy

1. Сортировка и поиск

  • np.sort(): Функция для сортировки элементов массива.
  • np.argsort(): Возвращает индексы отсортированных значений.
  • np.searchsorted(): Находит индексы, в которые надо вставить элементы для сохранения сортировки.
In [13]:
array_unsorted = np.array([3, 1, 2, 5, 4])
sorted_array = np.sort(array_unsorted)
print(sorted_array)  # [1 2 3 4 5]

indices = np.argsort(array_unsorted)
print(indices)  # [1 2 0 4 3] (индексы отсортированных значений)
[1 2 3 4 5]
[1 2 0 4 3]

2. Функции агрегации

Сборка и разделение массивов

  • Сборка: функции np.concatenate(), np.vstack(), np.hstack() позволяют объединять массивы вдоль различных осей.
  • Разделение: функции np.split(), np.hsplit(), np.vsplit() позволяют делить массивы на подмассивы.
In [14]:
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
combined = np.concatenate((array1, array2))  # Сборка
print(combined)  # [1 2 3 4 5 6]

splitted = np.split(combined, 2)  # Разделение на 2 подмассивы
print(splitted)  # [array([1, 2, 3]), array([4, 5, 6])]
[1 2 3 4 5 6]
[array([1, 2, 3]), array([4, 5, 6])]

3. Работа с пропусками

NumPy предоставляет функции для обработки данных с пропусками.

  • np.nanmean(): Вычисляет среднее значение, игнорируя NaN.
  • np.isnan(): Проверяет, являются ли элементы массива NaN.
In [15]:
array_with_nan = np.array([1, 2, np.nan, 4])
mean_value = np.nanmean(array_with_nan)
print(mean_value)  # 2.3333333333333335 (игнорируя NaN)
2.3333333333333335

Задача 9

Создайте два массива: один — из первых 5 четных чисел, а другой — из первых 5 нечетных. Объедините их в один массив и затем разделите на два отдельных массива.

In [ ]:

Задача 10

Создайте двумерный массив 4x4 с произвольными числами. Найдите сумму всех элементов, среднее по строкам и стандартное отклонение по столбцам.

In [ ]:

Задача 11

Создайте массив из 15 случайных целых чисел от 1 до 100. Отсортируйте массив и на его основе найдите индексы отсортированных значений. Затем найдите индекс, по которому нужно вставить число 50, чтобы сохранить порядок сортировки.

In [ ]:

Задача 12

Создайте массив с 10 элементами, в котором будут значения от 1 до 10, но замените некоторые значения на NaN. Используя функции NumPy, найдите среднее значение всех элементов, игнорируя NaN.

In [ ]:

Задача 13

Дано 4 точки у каждой из которых есть координата x и y. Значения x и y каждой точки представлены в матрице A.

Преобразуйте их в полярные координаты.

In [ ]:

Задача 14

Найдите наиболее частое значение в массиве.

In [ ]:

Задача 15

Создайте класс Matrix, добавьте в него методы сложения, умножения, транспонирования, возведения в степень для матриц.

In [ ]:

Задача 16

Пусть дано n, матрица A. Напишите функцию, вычисляющую ряд: $A + A^2 + ... A^n$.

In [ ]: