Как работать с матрицами в Python
Матрица — это двумерный массив, состоящий из M строк и N столбцов. Матрицы часто используются в математических вычислениях. Программисты работают с матрицами в основном в научной области, однако их можно использовать и для других вещей, например, для быстрой генерации уровней в видео-игре.
Матрицы и библиотека NumPy
Программист может самостоятельно реализовать все функции для работы с матрицами: умножение, сложение, транспонирование и т. д. На Python это сделать гораздо проще, чем на более низкоуровневых языках, таких как C.
Но каждый раз писать одни и те же алгоритмы не имеет смысла, поэтому была разработана библиотека NumPy. Она используется для сложных научных вычислений и предоставляет программисту функции для работы с двумерными массивами.
Вместо того чтобы писать десятки строк кода для выполнения простых операций над матрицами, программист может использовать одну функцию из NumPy. Библиотека написана на Python, C и Фортране, поэтому функции работают даже быстрее, чем на чистом Python.
Подключение библиотеки NumPy
NumPy не встроена в интерпретатор Python, поэтому перед импортом её необходимо установить. Для этого в можно воспользоваться утилитой pip. Введите в консоле команду:
Теперь, когда библиотека установлена, её можно подключить с помощью команды import . Для удобства переименуем numpy при импорте в np следующим образом:
Создание
Для создании матрицы используется функция array(). В функцию передаётся список. Вот пример создания, мы подаём в качестве аргумента функции двумерный список:
Вторым параметром можно задать тип элементов матрицы:
Тогда в консоль выведется:
Обратите внимание, что если изменить int на str, то тип элементов изменился на строковый. Кроме того, при выводе в консоль NumPy автоматически отформатировал вывод, чтобы он выглядел как матрица, а элементы располагались друг под другом.
В качестве типов элементов можно использовать int, float, bool, complex, bytes, str, buffers. Также можно использовать и другие типы NumPy: логические, целочисленные, беззнаковые целочисленные, вещественные, комплексные. Вот несколько примеров:
- np.bool8 — логическая переменная, которая занимает 1 байт памяти.
- np.int64 — целое число, занимающее 8 байт.
- np.uint16 — беззнаковое целое число, занимающее 2 байта в памяти.
- np.float32 — вещественное число, занимающее 4 байта в памяти.
- np.complex64 — комплексное число, состоящее из 4 байтового вещественного числа действительной части и 4 байтов мнимой.
Вы также можете узнать размер матрицы, для этого используйте атрибут shape:
Первое число (2) — количество строк, второе число (3) — количество столбцов.
Нулевая матрица
Если необходимо создать матрицу, состоящую только из нулей, используйте функцию zeros():
Результат этого кода будет следующий:
Получение строки, столбца и элемента
Чтобы получить строку двухмерной матрицы, нужно просто обратиться к ней по индексу следующим образом:
Получить столбец уже не так просто. Используем срезы, в качестве первого элемента среза мы ничего не указываем, а второй элемент — это номер искомого столбца. Пример:
Чтобы получить элемент, нужно указать номер столбца и строки, в которых он находится. Например, элемент во 2 строке и 3 столбце — это 5, проверяем (помним, что нумерация начинается с 0):
Умножение и сложение
Чтобы сложить матрицы, нужно сложить все их соответствующие элементы. В Python для их сложения используется обычный оператор «+».
Пример сложения:
Результирующая матрица будет равна:
Важно помнить, что складывать можно только матрицы с одинаковым количеством строк и столбцов, иначе программа на Python завершится с исключением ValueError.
Умножение матриц сильно отличается от сложения. Не получится просто перемножить соответствующие элементы двух матриц. Во-первых, матрицы должны быть согласованными, то есть количество столбцов одной должно быть равно количеству строк другой и наоборот, иначе программа вызовет ошибку.
Умножение в NumPy выполняется с помощью метода dot().
Пример умножения:
Результат выполнения этого кода будет следующий:
Транспонированная и обратная
Транспонированная матрица — это матрица, у которой строки и столбцы поменялись местами. В библиотеки NumPy для транспонирования двумерных матриц используется метод transpose(). Пример:
В результате получится матрица:
Чтобы получить обратную матрицу, необходимо использовать модуль linalg (линейная алгебра). Используем функцию inv():
Результирующая матрица будет равна:
Получение максимального и минимального элемента
Чтобы получить максимальный или минимальный элемент, можно пройтись по всем элементам матрицы с помощью двух циклов for . Это стандартный алгоритм перебора, который известен почти каждому программисту:
NumPy позволяет найти максимальный и минимальный элемент с помощью функций amax() и amin(). В качестве аргумента в функции нужно передать саму матрицу. Пример:
Как видим, результаты реализации на чистом Python и реализации с использованием библиотеки NumPy совпадают.
Заключение
На Python можно реализовать все необходимые функции для работы с матрицами. Чтобы упростить работу программистов, была создана библиотека NumPy. Она позволяет производить сложные математические вычисления легко и без ошибок, избавляя программиста от необходимости каждый раз писать один и тот же код.
Как транспонировать матрицу в питоне
Transpose of a matrix is a task we all can perform very easily in python (Using a nested loop). But there are some interesting ways to do the same in a single line.
In Python, we can implement a matrix as nested list (list inside a list). Each element is treated as a row of the matrix. For example m = [[1, 2], [4, 5], [3, 6]] represents a matrix of 3 rows and 2 columns.
First element of the list – m[0] and element in first row, first column – m[0][0].
-
Using Nested List Comprehension: Nested list comprehension are used to iterate through each element in the matrix. In the given example, we iterate through each element of matrix (m) in column major manner and assign the result to rez matrix which is the transpose of m.
NumPy: матрицы и операции над ними
В этом ноутбуке из сторонних библиотек нам понадобится только NumPy. Для удобства импортируем ее под более коротким именем:
1. Создание матриц
Приведем несколько способов создания матриц в NumPy.
Самый простой способ — с помощью функции numpy.array(list, dtype=None, . ).
В качестве первого аргумента ей надо передать итерируемый объект, элементами которого являются другие итерируемые объекты одинаковой длины и содержащие данные одинакового типа.
Второй аргумент является опциональным и определяет тип данных матрицы. Его можно не задавать, тогда тип данных будет определен из типа элементов первого аргумента. При задании этого параметра будет произведена попытка приведения типов.
Например, матрицу из списка списков целых чисел можно создать следующим образом:
Второй способ создания — с помощью встроенных функций numpy.eye(N, M=None, . ), numpy.zeros(shape, . ), numpy.ones(shape, . ).
Первая функция создает единичную матрицу размера N×M ; если M не задан, то M = N .
Вторая и третья функции создают матрицы, состоящие целиком из нулей или единиц соответственно. В качестве первого аргумента необходимо задать размерность массива — кортеж целых чисел. В двумерном случае это набор из двух чисел: количество строк и столбцов матрицы.
Примеры:
Обратите внимание: размерность массива задается не двумя аргументами функции, а одним — кортежем!
Вот так — np.ones(7, 5) — создать массив не получится, так как функции в качестве параметра shape передается 7, а не кортеж (7, 5).
И, наконец, третий способ — с помощью функции numpy.arange([start, ]stop, [step, ], . ), которая создает одномерный массив последовательных чисел из промежутка [start, stop) с заданным шагом step, и метода array.reshape(shape).
Параметр shape, как и в предыдущем примере, задает размерность матрицы (кортеж чисел). Логика работы метода ясна из следующего примера:
Более подробно о том, как создавать массивы в NumPy, см. документацию.
2. Индексирование
Для получения элементов матрицы можно использовать несколько способов. Рассмотрим самые простые из них.
Для удобства напомним, как выглядит матрица d:
Элемент на пересечении строки i и столбца j можно получить с помощью выражения array[i, j].
Обратите внимание: строки и столбцы нумеруются с нуля!
Из матрицы можно получать целые строки или столбцы с помощью выражений array[i, :] или array[:, j] соответственно:
Еще один способ получения элементов — с помощью выражения array[list1, list2], где list1, list2 — некоторые списки целых чисел. При такой адресации одновременно просматриваются оба списка и возвращаются элементы матрицы с соответствующими координатами. Следующий пример более понятно объясняет механизм работы такого индексирования:
Примеры использования слайсинга:
Более подробно о различных способах индексирования в массивах см. документацию.
3. Векторы, вектор-строки и вектор-столбцы
Следующие два способа задания массива кажутся одинаковыми:
Однако, на самом деле, это задание одномерного массива (то есть вектора) и двумерного массива:
Обратите внимание: вектор (одномерный массив) и вектор-столбец или вектор-строка (двумерные массивы) являются различными объектами в NumPy, хотя математически задают один и тот же объект. В случае одномерного массива кортеж shape состоит из одного числа и имеет вид (n,), где n — длина вектора. В случае двумерных векторов в shape присутствует еще одна размерность, равная единице.
В большинстве случаев неважно, какое представление использовать, потому что часто срабатывает приведение типов. Но некоторые операции не работают для одномерных массивов. Например, транспонирование (о нем пойдет речь ниже):
4. Datatypes
Все элементы в массиве numpy принадлежат одному типу. В этом плане массивы ближе к C, чем к привычным вам листам питона. Numpy имеет множество встренных типов, подходящих для решения большинства задач.
5. Математические операции
К массивам (матрицам) можно применять известные вам математические операции. Следут понимать, что при этом у элементов должны быть схожие размерности. Поведение в случае не совпадения размерностей хорошо описанно в документации numpy.
6. Умножение матриц и столбцов
Напоминание теории. Операция умножения определена для двух матриц, таких что число столбцов первой равно числу строк второй.
Пусть матрицы A и B таковы, что A ∈ ℝ n×k и B ∈ ℝ k×m . Произведением матриц A и B называется матрица C , такая что cij = ∑ k r = 1 airbrj , где cij — элемент матрицы C , стоящий на пересечении строки с номером i и столбца с номером j .
В NumPy произведение матриц вычисляется с помощью функции numpy.dot(a, b, . ) или с помощью метода array1.dot(array2), где array1 и array2 — перемножаемые матрицы.
Матрицы в NumPy можно умножать и на векторы:
Обратите внимание: операция * производит над матрицами покоординатное умножение, а не матричное!
Более подробно о матричном умножении в NumPy см. документацию.
7. Объединение массивов
Массивы можно Объединенять. Есть горизонтальное и вертикальное объединение.
Массивы можно переформировать при помощи метода, который задает новый многомерный массив. Следуя следующему примеру, мы переформатируем одномерный массив из десяти элементов во двумерный массив, состоящий из пяти строк и двух столбцов:
Задания: (Блок 1)
Задание 1:
Решите без использования циклов средставми NumPy (каждый пункт решается в 1-2 строчки)
- Создайте вектор с элементами от 12 до 42
- Создайте вектор из нулей длины 12, но его пятый елемент должен быть равен 1
- Создайте матрицу (3, 3), заполненую от 0 до 8
- Найдите все положительные числа в np.array([1,2,0,0,4,0])
- Умножьте матрицу размерности (5, 3) на (3, 2)
- Создайте матрицу (10, 10) так, чтобы на границе были 0, а внтури 1
- Создайте рандомный вектор и отсортируйте его
- Каков эквивалент функции enumerate для numpy массивов?
- *Создайте рандомный вектор и выполните нормализацию столбцов (из каждого столбца вычесть среднее этого столбца, из каждого столбца вычесть sd этого столбца)
- *Для заданного числа найдите ближайший к нему элемент в векторе
- *Найдите N наибольших значений в векторе
Задание 2:
8. Транспонирование матриц
Напоминание теории. Транспонированной матрицей A T называется матрица, полученная из исходной матрицы A заменой строк на столбцы. Формально: элементы матрицы A T определяются как a T ij = aji , где a T ij — элемент матрицы A T , стоящий на пересечении строки с номером i и столбца с номером j .
В NumPy транспонированная матрица вычисляется с помощью функции numpy.transpose() или с помощью метода array.T, где array — нужный двумерный массив.
В следующих разделах активно используется модуль numpy.linalg, реализующий некоторые приложения линейной алгебры. Более подробно о функциях, описанных ниже, и различных других функциях этого модуля можно посмотреть в его документации.
9. Определитель матрицы
Напоминание теории. Для квадратных матриц существует понятие определителя.
Пусть A — квадратная матрица. Определителем (или детерминантом) матрицы A ∈ ℝ n×n назовем число
где α1, α2, …, αn — перестановка чисел от 1 до n , N(α1, α2, …, αn) — число инверсий в перестановке, суммирование ведется по всем возможным перестановкам длины n .
Не стоит расстраиваться, если это определение понятно не до конца — в дальнейшем в таком виде оно не понадобится.
Например, для матрицы размера 2×2 получается:
Вычисление определителя матрицы по определению требует порядка n! операций, поэтому разработаны методы, которые позволяют вычислять его быстро и эффективно.
В NumPy определитель матрицы вычисляется с помощью функции numpy.linalg.det(a), где a — исходная матрица.
Рассмотрим одно интересное свойство определителя. Пусть у нас есть параллелограмм с углами в точках (0, 0), (c, d), (a + c, b + d), (a, b) (углы даны в порядке обхода по часовой стрелке). Тогда площадь этого параллелограмма можно вычислить как модуль определителя матрицы ⎛ ⎜ ⎝ a c b d ⎞ ⎟ ⎠ . Похожим образом можно выразить и объем параллелепипеда через определитель матрицы размера 3×3 .
10. Ранг матрицы
Напоминание теории. Рангом матрицы A называется максимальное число линейно независимых строк (столбцов) этой матрицы.
В NumPy ранг матрицы вычисляется с помощью функции numpy.linalg.matrix_rank(M, tol=None), где M — матрица, tol — параметр, отвечающий за некоторую точность вычисления. В простом случае можно его не задавать, и функция сама определит подходящее значение этого параметра.
С помощью вычисления ранга матрицы можно проверять линейную независимость системы векторов.
Допустим, у нас есть несколько векторов. Составим из них матрицу, где наши векторы будут являться строками. Понятно, что векторы линейно независимы тогда и только тогда, когда ранг полученной матрицы совпадает с числом векторов. Приведем пример:
11. Системы линейных уравнений
Напоминание теории. Системой линейных алгебраических уравнений называется система вида Ax = b , где A ∈ ℝ n×m , x ∈ ℝ m×1 , b ∈ ℝ n×1 . В случае квадратной невырожденной матрицы A решение системы единственно.
В NumPy решение такой системы можно найти с помощью функции numpy.linalg.solve(a, b), где первый аргумент — матрица A , второй — столбец b .
Убедимся, что вектор x действительно является решением системы:
Бывают случаи, когда решение системы не существует. Но хотелось бы все равно “решить” такую систему. Логичным кажется искать такой вектор x , который минимизирует выражение ‖ Ax − b ‖ 2 — так мы приблизим выражение Ax к b .
В NumPy такое псевдорешение можно искать с помощью функции numpy.linalg.lstsq(a, b, . ), где первые два аргумента такие же, как и для функции numpy.linalg.solve(). Помимо решения функция возвращает еще три значения, которые нам сейчас не понадобятся.
12. Обращение матриц
Напоминание теории. Для квадратных невырожденных матриц определено понятие обратной матрицы.
Пусть A — квадратная невырожденная матрица. Матрица A − 1 называется обратной матрицей к A , если
где I — единичная матрица.
В NumPy обратные матрицы вычисляются с помощью функции numpy.linalg.inv(a), где a — исходная матрица.
13. Собственные числа и собственные вектора матрицы
Напоминание теории. Для квадратных матриц определены понятия собственного вектора и собственного числа.
Пусть A — квадратная матрица и A ∈ ℝ n×n . Собственным вектором матрицы A называется такой ненулевой вектор x ∈ ℝ n , что для некоторого λ ∈ ℝ выполняется равенство Ax = λx . При этом λ называется собственным числом матрицы A . Собственные числа и собственные векторы матрицы играют важную роль в теории линейной алгебры и ее практических приложениях.
В NumPy собственные числа и собственные векторы матрицы вычисляются с помощью функции numpy.linalg.eig(a), где a — исходная матрица. В качестве результата эта функция выдает одномерный массив w собственных чисел и двумерный массив v, в котором по столбцам записаны собственные вектора, так что вектор v[:, i] соотвествует собственному числу w[i].
Обратите внимание: у вещественной матрицы собственные значения или собственные векторы могут быть комплексными.
14. Расстояния между векторами
Вспомним некоторые нормы, которые можно ввести в пространстве ℝ n , и рассмотрим, с помощью каких библиотек и функций их можно вычислять в NumPy.
p-норма
p-норма (норма Гёльдера) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
В частных случаях при: * p = 1 получаем ℓ1 норму * p = 2 получаем ℓ2 норму
Далее нам понабится модуль numpy.linalg, реализующий некоторые приложения линейной алгебры. Для вычисления различных норм мы используем функцию numpy.linalg.norm(x, ord=None, . ), где x — исходный вектор, ord — параметр, определяющий норму (мы рассмотрим два варианта его значений — 1 и 2). Импортируем эту функцию:
ℓ1 норма
ℓ1 норма (также известная как манхэттенское расстояние) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
Ей в функции numpy.linalg.norm(x, ord=None, . ) соответствует параметр ord=1.
ℓ2 норма
ℓ2 норма (также известная как евклидова норма) для вектора x = (x1, …, xn) ∈ ℝ n вычисляется по формуле:
Ей в функции numpy.linalg.norm(x, ord=None, . ) соответствует параметр ord=2.
Более подробно о том, какие еще нормы (в том числе матричные) можно вычислить, см. документацию.
15. Расстояния между векторами
Для двух векторов x = (x1, …, xn) ∈ ℝ n и y = (y1, …, yn) ∈ ℝ n ℓ1 и ℓ2 раccтояния вычисляются по следующим формулам соответственно:
16. Скалярное произведение и угол между векторами
Скалярное произведение в пространстве ℝ n для двух векторов x = (x1, …, xn) и y = (y1, …, yn) определяется как:
Длиной вектора x = (x1, …, xn) ∈ ℝ n называется квадратный корень из скалярного произведения, то есть длина равна евклидовой норме вектора:
Теперь, когда мы знаем расстояние между двумя ненулевыми векторами и их длины, мы можем вычислить угол между ними через скалярное произведение:
где α ∈ [0, π] — угол между векторами x и y .
17. Комплексные числа в питоне
Напоминание теории. Комплексными числами называются числа вида x + iy , где x и y — вещественные числа, а i — мнимая единица (величина, для которой выполняется равенство i 2 = − 1 ). Множество всех комплексных чисел обозначается буквой ℂ (подробнее про комплексные числа см. википедию).
В питоне комплескные числа можно задать следующим образом (j обозначает мнимую единицу):
С комплексными числами в питоне можно производить базовые арифметические операции так же, как и с вещественными числами:
Задания: (Блок 2)
Задание 3:
Рассмотрим сложную математическую функцию на отрезке [1, 15]:
f(x) = sin(x / 5) * exp(x / 10) + 5 * exp(-x / 2)

Она может описывать, например, зависимость оценок, которые выставляют определенному сорту вина эксперты, в зависимости от возраста этого вина. Мы хотим приблизить сложную зависимость с помощью функции из определенного семейства. В этом задании мы будем приближать указанную функцию с помощью многочленов.
Как известно, многочлен степени n (то есть w0 + w1x + w2x 2 + … + wnx n ) однозначно определяется любыми n + 1 различными точками, через которые он проходит. Это значит, что его коэффициенты w0 , … wn можно определить из следующей системы линейных уравнений:

где через x1, . xn, xn + 1 обозначены точки, через которые проходит многочлен, а через f(x1), . f(xn), f(xn + 1) — значения, которые он должен принимать в этих точках.
Воспользуемся описанным свойством, и будем находить приближение функции многочленом, решая систему линейных уравнений.
Библиотека numpy ¶
Пакет numpy предоставляет $n$-мерные однородные массивы (все элементы одного типа); в них нельзя вставить или удалить элемент в произвольном месте. В numpy реализовано много операций над массивами в целом. Если задачу можно решить, произведя некоторую последовательность операций над массивами, то это будет столь же эффективно, как в C или matlab — львиная доля времени тратится в библиотечных функциях, написанных на C .
Замечание. Модуль numpy.random не рассматривается целенаправленно. Вместо него рассмотри модуль scipy.stats , который больше подходит под вероятностно-статистические задачи.
Можно преобразовать список в массив.
print печатает массивы в удобной форме.
Класс ndarray имеет много методов.
Наш массив одномерный.
size — это полное число элементов в массиве; len — размер по первой координате (в 1-мерном случае это то же самое).
numpy предоставляет несколько типов для целых ( int16 , int32 , int64 ) и чисел с плавающей точкой ( float32 , float64 ).
Массив чисел с плавающей точкой.
Точно такой же массив.
Индексировать массив можно обычным образом.
Массивы — изменяемые объекты.
Массивы, разумеется, можно использовать в for циклах. Но при этом теряется главное преимущество numpy — быстродействие. Всегда, когда это возможно, лучше использовать операции над массивами как едиными целыми.
Упражнение: создайте numpy-массив, состоящий из первых пяти простых чисел, выведите его тип и размер.
Решение:
Массивы, заполненные нулями или единицами. Часто лучше сначала создать такой массив, а потом присваивать значения его элементам.
Если нужно создать массив, заполненный нулями, длины и типа другого массива, то можно использовать конструкцию
Функция arange подобна range . Аргументы могут быть с плавающей точкой. Следует избегать ситуаций, когда (конец-начало)/шаг — целое число, потому что в этом случае включение последнего элемента зависит от ошибок округления. Лучше, чтобы конец диапазона был где-то посредине шага.
Последовательности чисел с постоянным шагом можно также создавать функцией linspace . Начало и конец диапазона включаются; последний аргумент — число точек.
Упражнение: создайте и выведите последовательность чисел от 10 до 20 с постоянным шагом, длина последовательности — 21.
Решение:
Последовательность чисел с постоянным шагом по логарифмической шкале от $10^0$ до $10^1$.
Арифметические операции проводятся поэлементно.
Библиотека numpy содержит элементарные функции, которые тоже применяются к массивам поэлементно. Они называются универсальными функциями ( ufunc ).
Один из операндов может быть скаляром, а не массивом.
Сравнения дают булевы массивы.
Кванторы "существует" и "для всех".
Модификация на месте.
При выполнении операций над массивами деление на 0 не возбуждает исключения, а даёт значения np.nan или np.inf .
Сумма и произведение всех элементов массива; максимальный и минимальный элемент; среднее и среднеквадратичное отклонение.
Имеются встроенные функции
Иногда бывает нужно использовать частичные (кумулятивные) суммы. В наших курсах такое может пригодится.
Функция sort возвращает отсортированную копию, метод sort сортирует на месте.
Расщепление массива в позициях 3 и 6.
Функции delete , insert и append не меняют массив на месте, а возвращают новый массив, в котором удалены, вставлены в середину или добавлены в конец какие-то элементы.
Есть несколько способов индексации массива. Вот обычный индекс.
Диапазон индексов. Создаётся новый заголовок массива, указывающий на те же данные. Изменения, сделанные через такой массив, видны и в исходном массиве.
Диапазон с шагом 2.
Массив в обратном порядке.
Подмассиву можно присвоить значение — массив правильного размера или скаляр.
Тут опять создаётся только новый заголовок, указывающий на те же данные.
Чтобы скопировать и данные массива, нужно использовать метод copy .
Можно задать список индексов.
Можно задать булев массив той же величины.
Упражнение:
1). Создайте массив чисел от $-2\pi$ до $2\pi$.
2). Посчитайте сумму поэлементных квадратов синуса и косинуса для данного массива.
3). С помощью np.all проверьте, что в ответе только единицы.
Решение:
Атрибуту shape можно присвоить новое значение — кортеж размеров по всем координатам. Получится новый заголовок массива; его данные не изменятся.
Можно растянуть в одномерный массив
Арифметические операции поэлементные
Поэлементное и матричное (только в Python >=3.5) умножение.
Упражнение: создайте матрицы $\begin
Решение:
Умножение матрицы на вектор.
Если у вас Питон более ранней версии, то для работы с матрицами можно использовать класс np.matrix , в котором операция умножения реализуется как матричное умножение.
Внешнее произведение $a_
Двумерные массивы, зависящие только от одного индекса: $x_
Метод reshape делает то же самое, что присваивание атрибуту shape .
Цикл по строкам.
Можно построить двумерный массив из функции.
Соединение матриц по горизонтали и по вертикали.
Сумма всех элементов; суммы столбцов; суммы строк.
Аналогично работают prod , max , min и т.д.
След — сумма диагональных элементов.
Упражнение:
в статистике и машинном обучении часто приходится иметь с функцией $RSS$, которая вычисляется по формуле $\sum_^
Решение:
Суммирование (аналогично остальные операции)
Массивы можно объединять друг с другом по разным осям
Не обязательно объединять массивы одинакового размера
Однако начинают возникать проблемы, когда мы хотим объединить одномерный массив с двумерным.
С этой проблемой может помочь функция np.newaxis
Функция np.stack умеет объединять массивы по несуществующим осям, однако она принимает только массивы одинаковой размерности.
4.3. Broadcasting¶
Выше при арифметических операциях с массивами, например, при сложении и умножении, мы перемножали массивы одинаковой формы. В самом простом случае операндами были одномерные массивы одинаковой длины.
Произошло поэлементное умножение, все элементы массива $a$ умножились на $2$. Но мы знаем, что это можно сделать проще, просто умножив массив на $2$.
На самом деле поведение будет аналогичным, если умножить одномерный массив на массив длины $1$.
В этом случае работает так называемый broadcasting. Один массив "растягивается", чтобы повторить форму другого.
Такой же эффект работает и для многомерных массивов. Если по какому-то измерению размер у одного массива равен $1$, а у другого — произвольный, то по этому измерению может произойти "рястяжение". Таким образом, массивы можно умножать друг на друга, если в измерениях, где они по размеру не совпадают, хотя бы у одного размер $1$. Для других поэлементных операций правило аналогично.
Важно отметить, что размерности сопоставляются справа налево. Если их количество не совпадает, что массивы меньшей размерности сначала дополняются слева размерностями 1. Например, при сложении массива размера $4 \times 3$ с массивом размера $3$ последний сначала преобразуется в массив размера $1 \times 3$.
Схематично проведенную операцию можно визуализировать следующим образом.
Если неединичные размерности справа не будут совпадать, то выполнить операцию уже не получится. Например, как приведено на схеме ниже.
Упражнение:
Подумайте, массив какого размера получится, если перемножить массив $4 \times 1 \times 3$ и массив $12 \times 1$. Убедитесь на практике в правильности вашего ответа.
Знать про broadcasting нужно, но пользоваться им надо с осторожностью. Многократное копирование массива при растяжении может привести к неэффективной работе программы по памяти. Особенно за этим приходится следить при работе с GPU.
Решение линейной системы $au=v$.
Собственные значения и собственные векторы: $a u_i = \lambda_i u_i$. l — одномерный массив собственных значений $\lambda_i$, столбцы матрицы $u$ — собственные векторы $u_i$.
Функция diag от одномерного массива строит диагональную матрицу; от квадратной матрицы — возвращает одномерный массив её диагональных элементов.
Все уравнения $a u_i = \lambda_i u_i$ можно собрать в одно матричное уравнение $a u = u \Lambda$, где $\Lambda$ — диагональная матрица с собственными значениями $\lambda_i$ по диагонали.
Поэтому $u^ <-1>a u = \Lambda$.
Найдём теперь левые собственные векторы $v_i a = \lambda_i v_i$. Собственные значения $\lambda_i$ те же самые.
Собственные векторы нормированы на 1.
Левые и правые собственные векторы, соответствующие разным собственным значениям, ортогональны, потому что $v_i a u_j = \lambda_i v_i u_j = \lambda_j v_i u_j$.
Упражнение:
в машинном обучении есть модель линейной регрессии, для которой "хорошее" решение считается по следующей формуле: $\widehat <\theta>= (X^T \cdot X + \lambda \cdot I_n)^<-1>\cdot X^T y$. Вычислите $\widehat<\theta>$ для $ X = \begin
Решение:
Адаптивное численное интегрирование (может быть до бесконечности). err — оценка ошибки.
Получится такой файл
Теперь его можно прочитать
8. Производительность numpy¶
Посмотрим на простой пример — сумма первых $10^8$ чисел.
Немного улучшеный код
Код с использованием функций библиотеки numpy
Простой и понятный код работает в $30$ раз быстрее!
Посмотрим на другой пример. Сгенерируем матрицу размера $500\times1000$, и вычислим средний минимум по колонкам.
Простой код, но при этом даже использующий некоторые питон-функции
Замечание. Далее с помощью scipy.stats происходит генерация случайных чисел из равномерного распределения на отрезке $[0, 1]$. Этот модуль будем изучать в следующем ноутбуке.
Понятный код с использованием функций библиотеки numpy
Простой и понятный код работает в 1500 раз быстрее!
С помощью соглашения Эйнштейна о суммировании, многие общие многомерные линейные алгебраические операции с массивами могут быть представлены простым способом.
Если одна и та же буква в обозначении индекса встречается и сверху, и снизу, то такой член полагается просуммированным по всем значениям, которые может принимать этот индекс.
Например, выражение $c_j = a_i b^i_j$ понимается как $c_j = \sum_^n a_i b^i_j$.
Подобные операции часто возникают в анализе данных, в особенности при реализации байесовских методов.
В numpy такие операции реализует функция einsum , причем здесь не делается разницы между нижними и верхними индексами. Функция принимает на вход сигнатуру операции в виде текстовой строки и матрицы с данными.
Разберем на примере выше. В данном случае сигнатура имеет вид i,ji->j . Элементы сигнатуры последовательно означают следующее (тензор = многомерная матрица):