Линейная алгебра
Contents
Линейная алгебра#
Подмодуль scipy.linalg в целом является надмножеством над numpy.linalg, т.е. кроме того, что он содержит все методы из numpy.linalg
, в него включены еще ряд дополнительных методов.
Ряд примеров приведен в документации.
Обращение матриц (функция linalg.inv) и решение СЛАУ (функция linalg.solve);
Разложение матрицы: собственные значения и вектора, сингулярное разложение, LU и QR разложения и другое;
Методы создания специальных матриц, блочно-диагональных и многих других;
import numpy as np
from scipy import linalg
Вычисление норм матриц и векторов#
Существуют разные нормы определенные на пространстве векторов и матриц. Многие из них можно вычислить средствами функции scipy.linalg.norm.
Векторы#
Для одномерных массивов по умолчанию возвращается евклидова норма (она же \(l_2\)), которая для \(x\in\mathbb{R}^n\) (или \(x\in\mathbb{C}^n\)) определяется формулой
x = np.array([3, 4])
print(f"Евклидова норма вектора x равняется {linalg.norm(x)}")
Евклидова норма вектора x равняется 5.0
Евклидова норма является частным случаем нормы \(l_p\), которая для любого положительно \(p\) определяется выражением
Параметр ord
позволяет указать значение p
необходимой нормы. Например, очень часто вместо \(l_2\) (евклидова, \(p=2\)) используется называемая иногда абсолютной норма \(l_1\) (\(p=1\)), которая определяется выражением
print(f"Абсолютная норма вектора x равняется {linalg.norm(x, ord=1)}")
Абсолютная норма вектора x равняется 7.0
На другом конце спектра нормированных пространств семейства \(l_p\) находится пространство с равномерной метрикой \(l_\infty\), определяемой выражением
Чтобы её вычислить, необходимо передать в качестве параметра ord
значение numpy.inf.
print(f"Равномерная норма вектора x равняется {linalg.norm(x, ord=np.inf)}")
Равномерная норма вектора x равняется 4.0
Матрицы#
Если массив двухмерный, то по умолчанию вычисляется тоже евклидова норма (она же норма Фробениуса), которая для матрицы \(A\in\mathbb{R}^{n\times m}\) определяется выражением
Tip
Если необходимо вычислить векторную норму от множества векторов в многомерном массиве, то полезным окажется параметр axis
этого метода.
A = np.array([
[1, 2],
[3, 4]
])
print(f"Норма матрицы A равняется {linalg.norm(A)}")
Норма матрицы A равняется 5.477225575051661
В ряде задач, в которых матрицы используются для представления линейных операторов, важно следить за согласованностью и подчиненностью матричных норм с соответствующими нормами векторных пространств, в которых они оперируют.
Так, например, норма евклидово векторное пространство \(l_2\) порождает в матричном пространстве спектральную норму, которая равняется максимальному сингулярному числу этого оператора. Чтобы вычислить спектральную норму матрицы, необходимо передать 2 в качестве параметра ord
.
singular_values = linalg.svdvals(A)
print(f"Максимальное спектральное число матрицы A равняется {singular_values.max()}")
print(f"Спектральная норма матрицы m равняется {linalg.norm(A, ord=2)}")
Максимальное спектральное число матрицы A равняется 5.464985704219043
Спектральная норма матрицы m равняется 5.464985704219043
За более полным списком поддерживаемых норм этим методом, автор направляет вас в документацию.
Обращение матриц#
Функция linalg.inv отвечает за обращение матрицы, т.е. за поиск такой матрицы \(A^{-1}\), что \(A A^{-1} = A^{-1} A = I\), где \(I\) — единичная матрица того же размера.
import numpy as np
from scipy import linalg
A = np.array([[1., 2.], [3., 4.]])
A_inv = linalg.inv(A)
print(A, A_inv, sep="\n")
[[1. 2.]
[3. 4.]]
[[-2. 1. ]
[ 1.5 -0.5]]
Чтобы убедиться, что она возвращает обратную матрицу, проверим выполнение равенства \(A A^{-1} = A^{-1} A = I\).
print(A @ A_inv)
print(A_inv @ A)
[[1.0000000e+00 0.0000000e+00]
[8.8817842e-16 1.0000000e+00]]
[[1.00000000e+00 0.00000000e+00]
[2.22044605e-16 1.00000000e+00]]
Как видим, получилась не совсем единичная матрица, но т.к. все вычисления с числами с плавающей точкой производятся в компьютере не точно, то большего ожидать нельзя.
Сверять целый массив глазами не очень удобно. Упростим себе задачу и посчитаем норму невязки, т.к. нормы матриц
и
R_1 = linalg.norm(A @ A_inv - np.eye(2))
R_2 = linalg.norm(A_inv @ A - np.eye(2))
print(f"{R_1=}, {R_2=}")
R_1=9.930136612989092e-16, R_2=4.965068306494546e-16
Решение систем линейных алгебраических уравнений#
Функция linalg.solve используется для решения СЛАУ вида \(Ax = b\), где \(A\) — квадратная матрица размера \(N \times N\). Правая часть уравнения \(b\) может быть формы (N, NRHS)
, т.е. если \(b\) — одномерный массив, то решается обычное СЛАУ, а если \(b\) — матрица из \(N\) строк и NRHS
столбцов, то решается матричное уравнение (или сразу решается NRHS
СЛАУ с общей матрицей \(A\), а в качестве векторов правых частей выступают столбцы матрицы \(b\)).
Для иллюстрации создадим матрицу A
и вектор x
. Сгенерируем вектор правой части b = A @ x
и попробуем восстановить значение x
, решив СЛАУ A x = b
.
A = np.array([[1., 2.], [3., 4.]])
x = np.array([1., 1.])
b = A @ x
x_approx = linalg.solve(A, b)
error = linalg.norm(x_approx - x)
print(f"{x_approx=}. Погрешность: {error}")
x_approx=array([1., 1.]). Погрешность: 4.002966042486721e-16
Кроме метода solve
, который пытается решить СЛАУ в общем случае, в NumPy
предусмотрен набор методов для решения СЛАУ, если известны свойства матрицы в левой части. Например, для треугольной матрицы предпочтительно использовать метод solve_triangular, для циркулянтной матрицы — метод solve_circulant и т.п.
Определитель квадратной матрицы вычисляется методом det.
print(f"Определитель матрицы A равен {linalg.det(A)}")
Определитель матрицы A равен -2.0
Поиск собственных чисел и векторов#
В ряде задач требуется найти собственные числа и/или собственные значения.
Метод eigvals отвечает за поиск собственных чисел. Найдем с помощью него собственные значения матрицы
Характеристический полином
имеет два действительных решения \(\lambda_1=3\) и \(\lambda_2=1\).
A = np.array([
[2, 1],
[1., 2]
])
eigen_values = linalg.eigvals(A)
print(f"Собственные значения матрицы A: {eigen_values}")
Собственные значения матрицы A: [3.+0.j 1.+0.j]
Метод eig вычисляет сразу и собственные числа и собственные векторы. При этом собственные вектора возвращаются как столбцы матрицы второго возвращаемого значения.
eigen_values, eigen_vectors = linalg.eig(A)
print(f"Собственные значения матрицы A: {eigen_values}")
for vector in eigen_vectors.T:
print(f"{vector} --- собственный вектор матрицы A")
Собственные значения матрицы A: [3.+0.j 1.+0.j]
[0.70710678 0.70710678] --- собственный вектор матрицы A
[-0.70710678 0.70710678] --- собственный вектор матрицы A
Проверим, что найденные собственные вектора и числа корректны. Для этого посчитаем невязки
где \(v_1\) и \(v_2\) — собственные вектора соответствующие собственным числам \(\lambda_1\) и \(\lambda_2\).
for l, v in zip(eigen_values, eigen_vectors.T):
R = linalg.norm(A@v - l*v)
print(f"{R=}")
R=0.0
R=0.0
Tip
Если заранее известны определенные свойства матрицы \(A\), то лучше воспользоваться соответствующими методами.
Сингулярное разложение матрицы#
За поиск сингулярных чисел отвечает функция svdvalues. Функция svd (Singular Value Decomposition) вычисляет сингулярное разложение матрицы, которое определено и для прямоугольных матриц.
A = np.array([
[1, 2, 3],
[4, 5, 6],
])
left_vectors, singular_values, right_vectors = linalg.svd(A)
for v, s, u in zip(left_vectors.T, singular_values, right_vectors):
R = linalg.norm(A.T @ v - s * u)
print(f"{R=}")
R=1.9860273225978185e-15
R=1.1625080825424498e-15
Tip
Кроме сингулярного разложения в scipy
есть и многие другие, такие как QR-разложение, LU-разложение и т.д.