Глава 1. ЛИНЕЙНАЯ АЛГЕБРА
1.1. Сложение векторов
\[ \mathbf{u} + \mathbf{v} = \begin{bmatrix} u_1 \\ u_2 \\ \vdots \\ u_n \end{bmatrix} + \begin{bmatrix} v_1 \\ v_2 \\ \vdots \\ v_n \end{bmatrix} = \begin{bmatrix} u_1 + v_1 \\ u_2 + v_2 \\ \vdots \\ u_n + v_n \end{bmatrix} \]Объяснение: Сложение векторов объединяет два вектора покомпонентно. Оно широко используется в машинном обучении для обновления градиентов или геометрических операций с векторами.
Пример: Если \(\mathbf{u} = \begin{bmatrix} 1 \\ 2 \end{bmatrix}\) и \(\mathbf{v} = \begin{bmatrix} 3 \\ 4 \end{bmatrix}\), то \(\mathbf{u} + \mathbf{v} = \begin{bmatrix} 4 \\ 6 \end{bmatrix}\).
Реализация:
import numpy as np
u = np.array([1, 2])
v = np.array([3, 4])
result = u + v
1.2. Умножение вектора на скаляр
\[ \alpha\mathbf{v} = \alpha \begin{bmatrix} v_1 \\ v_2 \\ \vdots \\ v_n \end{bmatrix} = \begin{bmatrix} \alpha v_1 \\ \alpha v_2 \\ \vdots \\ \alpha v_n \end{bmatrix} \]Объяснение: Умножение на скаляр масштабирует каждую компоненту вектора на один и тот же скаляр. Используется для масштабирования градиентов или управления величинами векторов.
Пример: Если \(\alpha = 3\) и \(\mathbf{v} = \begin{bmatrix} 2 \\ -1 \end{bmatrix}\), то \(\alpha\mathbf{v} = \begin{bmatrix} 6 \\ -3 \end{bmatrix}\).
Реализация:
import numpy as np
alpha = 3
v = np.array([2, -1])
result = alpha * v
1.3. Скалярное произведение
\[ \mathbf{u} \cdot \mathbf{v} = \sum_{i=1}^{n} u_i v_i = u_1 v_1 + u_2 v_2 + \dots + u_n v_n \]Объяснение: Скалярное произведение вычисляет скаляр, представляющий величину проекции одного вектора на другой. Широко используется в МО для мер сходства или линейных операций.
Пример: Если \(\mathbf{u} = \begin{bmatrix} 1 \\ 2 \end{bmatrix}\) и \(\mathbf{v} = \begin{bmatrix} 3 \\ 4 \end{bmatrix}\), то \(\mathbf{u} \cdot \mathbf{v} = 1 \cdot 3 + 2 \cdot 4 = 11\).
Реализация:
import numpy as np
u = np.array([1, 2])
v = np.array([3, 4])
result = np.dot(u, v)
1.4. Векторное произведение (3D)
\[ \mathbf{u} \times \mathbf{v} = \begin{vmatrix} \mathbf{i} & \mathbf{j} & \mathbf{k} \\ u_1 & u_2 & u_3 \\ v_1 & v_2 & v_3 \end{vmatrix} \]Объяснение: Векторное произведение генерирует вектор, перпендикулярный двум входным векторам в 3D пространстве. Обычно используется в физике и компьютерной графике.
Пример: Если \(\mathbf{u} = \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix}\) и \(\mathbf{v} = \begin{bmatrix} 0 \\ 1 \\ 0 \end{bmatrix}\), то \(\mathbf{u} \times \mathbf{v} = \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix}\).
Реализация:
import numpy as np
u = np.array([1, 0, 0])
v = np.array([0, 1, 0])
result = np.cross(u, v)
1.5. Норма вектора (Евклидова)
\[ \|\mathbf{v}\| = \sqrt{\sum_{i=1}^{n} v_i^2} = \sqrt{v_1^2 + v_2^2 + \dots + v_n^2} \]Объяснение: Евклидова норма измеряет величину (длину) вектора. Она полезна в оптимизации и вычислениях расстояний в МО.
Пример: Если \(\mathbf{v} = \begin{bmatrix} 3 \\ 4 \end{bmatrix}\), то \(\|\mathbf{v}\| = \sqrt{3^2 + 4^2} = 5\).
Реализация:
import numpy as np
v = np.array([3, 4])
result = np.linalg.norm(v)
1.6. Условие ортогональности
\[ \mathbf{u} \cdot \mathbf{v} = 0 \]Объяснение: Два вектора ортогональны, если их скалярное произведение равно нулю. Это условие критически важно в линейной алгебре и МО для понимания независимости и построения базисов.
Пример: Если \(\mathbf{u} = \begin{bmatrix} 1 \\ 2 \end{bmatrix}\) и \(\mathbf{v} = \begin{bmatrix} -2 \\ 1 \end{bmatrix}\), то \(\mathbf{u} \cdot \mathbf{v} = 1 \cdot (-2) + 2 \cdot 1 = 0\), что подтверждает ортогональность.
Реализация:
import numpy as np
u = np.array([1, 2])
v = np.array([-2, 1])
result = np.dot(u, v)
is_orthogonal = result == 0
1.7. Сложение матриц
\[ A + B = \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} + \begin{bmatrix} b_{11} & b_{12} \\ b_{21} & b_{22} \end{bmatrix} = \begin{bmatrix} a_{11} + b_{11} & a_{12} + b_{12} \\ a_{21} + b_{21} & a_{22} + b_{22} \end{bmatrix} \]Объяснение: Сложение матриц объединяет две матрицы поэлементно. Используется в МО для обновления весов и смещений или агрегирования данных.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\), то \(A + B = \begin{bmatrix} 6 & 8 \\ 10 & 12 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = A + B
1.8. Умножение матрицы на скаляр
\[ \alpha A = \alpha \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} = \begin{bmatrix} \alpha a_{11} & \alpha a_{12} \\ \alpha a_{21} & \alpha a_{22} \end{bmatrix} \]Объяснение: Масштабирование матрицы скаляром полезно в МО для настройки скорости обучения или нормализации.
Пример: Если \(\alpha = 2\) и \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\), то \(\alpha A = \begin{bmatrix} 2 & 4 \\ 6 & 8 \end{bmatrix}\).
Реализация:
import numpy as np
alpha = 2
A = np.array([[1, 2], [3, 4]])
result = alpha * A
1.9. Умножение матрицы на вектор
\[ A\mathbf{x} = \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} = \begin{bmatrix} a_{11}x_1 + a_{12}x_2 \\ a_{21}x_1 + a_{22}x_2 \end{bmatrix} \]Объяснение: Умножение матрицы на вектор преобразует вектор с использованием линейного преобразования, определенного матрицей. Это фундаментальная операция в МО для применения весов к входным данным.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(\mathbf{x} = \begin{bmatrix} 5 \\ 6 \end{bmatrix}\), то \(A\mathbf{x} = \begin{bmatrix} 17 \\ 39 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
x = np.array([5, 6])
result = np.dot(A, x) # Или A @ x
1.10. Умножение матриц
\[ C = AB, \quad c_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj} \]Объяснение: Умножение матриц объединяет две матрицы, производя матрицу, которая представляет композицию линейных преобразований. Используется в МО для операций между слоями в нейронных сетях.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\), то \(AB = \begin{bmatrix} 19 & 22 \\ 43 & 50 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = np.dot(A, B) # Или A @ B
1.11. Транспонирование матрицы
\[ A^T = \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix}^T = \begin{bmatrix} a_{11} & a_{21} \\ a_{12} & a_{22} \end{bmatrix} \]Объяснение: Транспонирование матрицы "переворачивает" ее относительно главной диагонали, меняя местами строки и столбцы. Используется в МО для переключения между представлениями данных.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\), то \(A^T = \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
result = A.T
1.12. Определитель матрицы 2x2
\[ \det(A) = \begin{vmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{vmatrix} = a_{11}a_{22} - a_{12}a_{21} \]Объяснение: Определитель измеряет коэффициент масштабирования преобразования, представленного матрицей. Он используется для определения обратимости матрицы.
Пример: Если \(A = \begin{bmatrix} 3 & 8 \\ 4 & 6 \end{bmatrix}\), то \(\det(A) = 3 \cdot 6 - 8 \cdot 4 = -14\).
Реализация:
import numpy as np
A = np.array([[3, 8], [4, 6]])
result = np.linalg.det(A)
1.13. Обратная матрица 2x2
\[ A^{-1} = \frac{1}{\det(A)} \begin{bmatrix} a_{22} & -a_{12} \\ -a_{21} & a_{11} \end{bmatrix}, \quad \det(A) \neq 0 \]Объяснение: Обратная матрица 2x2 отменяет линейное преобразование, которое она представляет. Используется при решении систем линейных уравнений.
Пример: Если \(A = \begin{bmatrix} 3 & 8 \\ 4 & 6 \end{bmatrix}\), то \(\det(A) = -14\) и \(A^{-1} = \frac{1}{-14} \begin{bmatrix} 6 & -8 \\ -4 & 3 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[3, 8], [4, 6]])
result = np.linalg.inv(A)
1.14. Правило Крамера
\[ x_i = \frac{\det(A_i)}{\det(A)}, \quad \det(A) \neq 0 \]Объяснение: Правило Крамера решает систему линейных уравнений \(A\mathbf{x} = \mathbf{b}\), заменяя каждый столбец матрицы A вектором \(\mathbf{b}\) и вычисляя определители. Это теоретический метод, часто используемый для небольших систем.
Пример: Для \(A = \begin{bmatrix} 2 & 1 \\ 1 & 3 \end{bmatrix}\) и \(\mathbf{b} = \begin{bmatrix} 5 \\ 7 \end{bmatrix}\), \(A_1 = \begin{bmatrix} 5 & 1 \\ 7 & 3 \end{bmatrix}\), \(A_2 = \begin{bmatrix} 2 & 5 \\ 1 & 7 \end{bmatrix}\). И \(\det(A) = 5\), тогда \(x_1 = \frac{\det(A_1)}{\det(A)}\), \(x_2 = \frac{\det(A_2)}{\det(A)}\).
Реализация:
import numpy as np
A = np.array([[2, 1], [1, 3]])
b = np.array([5, 7])
det_A = np.linalg.det(A)
x = []
for i in range(A.shape[1]):
Ai = A.copy()
Ai[:, i] = b
x.append(np.linalg.det(Ai) / det_A)
# Альтернативная реализация из OCR (более компактная, но менее читаемая):
# x = [np.linalg.det(np.column_stack((b if i == j else A[:, j]
# for j in range(A.shape[1])))) / det_A
# for i in range(A.shape[1])]
1.15. Обратная квадратная матрица
\[ A^{-1} = \frac{1}{\det(A)} \text{adj}(A), \quad \det(A) \neq 0 \]Объяснение: Обратная квадратная матрица обобщает процесс для высших размерностей с использованием присоединенной матрицы (матрицы алгебраических дополнений) и определителя. Крайне важна в линейной алгебре и МО для решения систем уравнений.
Пример: Если \(A = \begin{bmatrix} 4 & 7 \\ 2 & 6 \end{bmatrix}\), обратная матрица вычисляется с использованием разложения по кофакторам и масштабирования.
Реализация:
import numpy as np
A = np.array([[4, 7], [2, 6]])
result = np.linalg.inv(A)
1.16. Определитель треугольной матрицы
\[ \det(A) = \prod_{i=1}^{n} a_{ii} \]Объяснение: Определитель треугольной матрицы (верхней или нижней) равен произведению ее диагональных элементов. Это упрощает вычисление определителей и полезно при разложениях.
Пример: Если \(A = \begin{bmatrix} 2 & 1 & 0 \\ 0 & 3 & 4 \\ 0 & 0 & 5 \end{bmatrix}\), то \(\det(A) = 2 \cdot 3 \cdot 5 = 30\).
Реализация:
import numpy as np
A = np.array([[2, 1, 0], [0, 3, 4], [0, 0, 5]])
result = np.prod(np.diag(A))
1.17. Теорема о ранге и дефекте (Rank-Nullity Theorem)
\[ \text{rank}(A) + \text{nullity}(A) = n \]Объяснение: Теорема о ранге и дефекте утверждает, что сумма ранга (размерность пространства столбцов) и дефекта (размерность нулевого пространства) матрицы равна числу ее столбцов (n). Она фундаментальна в линейной алгебре для понимания решений систем линейных уравнений.
Пример: Если матрица A имеет 3 столбца и ее ранг равен 2, то дефект равен 1, так как 2 + 1 = 3.
Реализация:
import numpy as np
from numpy.linalg import matrix_rank
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
rank = matrix_rank(A)
# nullity (дефект) - это размерность нулевого пространства
# nullity = n - rank, где n - количество столбцов
nullity = A.shape[1] - rank
1.18. Произведение Адамара (поэлементное)
\[ C = A \circ B = \begin{bmatrix} a_{11}b_{11} & a_{12}b_{12} \\ a_{21}b_{21} & a_{22}b_{22} \end{bmatrix} \]Объяснение: Произведение Адамара выполняет поэлементное умножение между двумя матрицами. Используется в МО для масштабирования признаков или в механизмах вентилей (gating).
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\), то \(C = A \circ B = \begin{bmatrix} 5 & 12 \\ 21 & 32 \end{bmatrix}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = np.multiply(A, B) # Или result = A * B
1.19. Внешнее произведение
\[ C = \mathbf{u} \otimes \mathbf{v} = \begin{bmatrix} u_1 v_1 & u_1 v_2 & \dots & u_1 v_n \\ u_2 v_1 & u_2 v_2 & \dots & u_2 v_n \\ \vdots & \vdots & \ddots & \vdots \\ u_m v_1 & u_m v_2 & \dots & u_m v_n \end{bmatrix} \]Объяснение: Внешнее произведение генерирует матрицу путем умножения каждого элемента одного вектора на каждый элемент другого. Используется в тензорных операциях и построении матриц ранга 1.
Пример: Если \(\mathbf{u} = \begin{bmatrix} 1 \\ 2 \end{bmatrix}\) и \(\mathbf{v} = \begin{bmatrix} 3 \\ 4 \\ 5 \end{bmatrix}\) (заметим, что v должен быть строкой для стандартного определения \(uv^T\), но numpy.outer делает это автоматически), то \(\mathbf{u} \otimes \mathbf{v} = \begin{bmatrix} 3 & 4 & 5 \\ 6 & 8 & 10 \end{bmatrix}\).
Реализация:
import numpy as np
u = np.array([1, 2])
v = np.array([3, 4, 5])
result = np.outer(u, v)
1.20. Норма Фробениуса
\[ \|A\|_F = \sqrt{\sum_{i=1}^{m} \sum_{j=1}^{n} |a_{ij}|^2} \]Объяснение: Норма Фробениуса измеряет "величину" матрицы путем суммирования квадратов всех ее элементов. Широко используется в оптимизации и матричном анализе.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\), то \(\|A\|_F = \sqrt{1^2 + 2^2 + 3^2 + 4^2} = \sqrt{30}\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
result = np.linalg.norm(A, 'fro')
1.21. Неравенство для нормы матрицы
\[ \|A\mathbf{x}\| \le \|A\| \|\mathbf{x}\| \]Объяснение: Неравенство для нормы матрицы утверждает, что норма произведения матрицы на вектор ограничена произведением нормы матрицы и нормы вектора. Это ключевое свойство в численной линейной алгебре и МО для анализа ошибок.
Пример: Для \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(\mathbf{x} = \begin{bmatrix} 1 \\ 1 \end{bmatrix}\), вычислить \(\|A\mathbf{x}\| \le \|A\| \|\mathbf{x}\|\). (Используются совместимые нормы, например, Евклидова норма для вектора и индуцированная L2 норма для матрицы, или норма Фробениуса для матрицы).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
x = np.array([1, 1])
# Используем L2 норму для векторов и матриц (спектральная норма для A)
left = np.linalg.norm(np.dot(A, x))
right = np.linalg.norm(A, 2) * np.linalg.norm(x) # np.linalg.norm(A) по умолчанию L2 для матриц
inequality_holds = left <= right
1.22. След матрицы
\[ \text{Tr}(A) = \sum_{i=1}^{n} a_{ii} \]Объяснение: След матрицы — это сумма ее диагональных элементов. Используется в МО в функциях потерь и для характеристики свойств матрицы.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\), то \(\text{Tr}(A) = 1 + 4 = 5\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
result = np.trace(A)
1.23. След произведения
\[ \text{Tr}(AB) = \text{Tr}(BA) \]Объяснение: След произведения двух матриц инвариантен относительно циклических перестановок. Это свойство полезно в МО для упрощения градиентов в матричном исчислении.
Пример: Для \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\), вычислить \(\text{Tr}(AB) = \text{Tr}(BA)\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
trace1 = np.trace(np.dot(A, B))
trace2 = np.trace(np.dot(B, A))
equality_holds = trace1 == trace2
1.24. Блочное умножение матриц
\[ C = \begin{bmatrix} A & B \\ C & D \end{bmatrix} \begin{bmatrix} E & F \\ G & H \end{bmatrix} = \begin{bmatrix} AE + BG & AF + BH \\ CE + DG & CF + DH \end{bmatrix} \]Объяснение: Блочное умножение матриц следует тем же правилам, что и скалярное умножение матриц, но каждый элемент является подматрицей. Используется в МО для крупномасштабных вычислений и разложений.
Пример: Вычислить блочное произведение для двух разделенных матриц 4x4.
Реализация:
import numpy as np
# Пример блоков (A, B, C, D, E, F, G, H должны быть numpy массивами)
# A = np.array([[1, 2], [3, 4]])
# B = np.array([[5, 6], [7, 8]])
# C = np.array([[9, 10], [11, 12]])
# D = np.array([[13, 14], [15, 16]])
# E = np.array([[17, 18], [19, 20]])
# F = np.array([[21, 22], [23, 24]])
# G = np.array([[25, 26], [27, 28]])
# H = np.array([[29, 30], [31, 32]])
#
# top_left = np.dot(A, E) + np.dot(B, G)
# top_right = np.dot(A, F) + np.dot(B, H)
# bottom_left = np.dot(C, E) + np.dot(D, G)
# bottom_right = np.dot(C, F) + np.dot(D, H)
#
# result = np.block([[top_left, top_right], [bottom_left, bottom_right]])
# Примечание: В реальном коде убедитесь, что размерности блоков совместимы для умножения и сложения.
1.25. Произведение Кронекера
\[ C = A \otimes B = \begin{bmatrix} a_{11}B & a_{12}B \\ a_{21}B & a_{22}B \end{bmatrix} \]Объяснение: Произведение Кронекера создает блочную матрицу путем умножения каждого элемента одной матрицы на всю другую матрицу. Используется в МО для тензорных операций и обработки сигналов.
Пример: Если \(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\) и \(B = \begin{bmatrix} 0 & 5 \\ 6 & 7 \end{bmatrix}\), вычислить \(A \otimes B\).
Реализация:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[0, 5], [6, 7]])
result = np.kron(A, B)