Все курсы > Линейная алгебра > Занятие 1
На первом занятии мы более подробно рассмотрим понятие вектора.
Ноутбук к сегодняшнему занятию⧉
Понятие вектора
Вектор (vector) — это направленный отрезок, и для нас будет важно, что любой вектор обладает длиной (magnitude) и направлением (direction).
На курсе мы будем обозначать векторы полужирной строчной буквой, например $\textbf{a}$, а матрицы заглавной буквой, например, А.
Возьмём двумерный вектор $\textbf{v}$
$$ \textbf{v} = \begin{bmatrix} 4 \\ 3 \end{bmatrix} $$
Вектор $\textbf{v}$ удобно изобразить на координатной плоскости, исходящим из начала координат.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
v = np.array([4, 3]) ax = plt.axes() plt.xlim([0, 5]) plt.ylim([0, 5]) plt.grid() ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0]/2, v[1]/2), xytext=(10, -10), textcoords='offset points', fontsize = 16) plt.show() |
![вектор на плоскости, исходящий из начала координат](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/vector.png)
Добавлю, что вектор — частный случай матрицы. В случае вектор-столбца речь идет о матрице размерностью n x 1. В случае вектор-строки — 1 x n. Вектор $\textbf{v}$ — это матрица 2 х 1.
Операции над векторами
Сложение векторов
Складывать векторы очень несложно. Достаточно сложить их компоненты или координаты.
$$ \begin{bmatrix} 4 \\ 3 \end{bmatrix} + \begin{bmatrix} 2 \\ -1 \end{bmatrix} = \begin{bmatrix} 6 \\ 2 \end{bmatrix} $$
1 2 3 4 5 |
a = np.array([4, 3]) b = np.array([2, -1]) a_plus_b = a + b a_plus_b |
1 |
array([6, 2]) |
Графически, если поставить начало второго вектора в конец первого, сложение можно представить как расстояние от начала первого вектора до конца второго. Своего рода путь, пройденный двумя векторами.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
ax = plt.axes() plt.xlim([0, 7]) plt.ylim([0, 7]) plt.grid() arrow_a = ax.arrow(0, 0, a[0], a[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') arrow_b = ax.arrow(a[0], a[1], b[0], b[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') arrow_a_plus_b = ax.arrow(0, 0, a_plus_b[0], a_plus_b[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'b', ec = 'b') plt.legend([arrow_a, arrow_b, arrow_a_plus_b], ['вектор a', 'вектор b', 'вектор a + b'], prop = {'size': 16}) plt.show() |
![сложение двух векторов](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/vector_addition.png)
Сложение векторов ассоциативно $\textbf{a} + \textbf{b} = \textbf{b} + \textbf{a}$.
Умножение на скаляр
Умножение на скаляр просто удлиняет или укорачивает вектор.
$$ 2 \cdot \textbf{v} = 2 \cdot \begin{bmatrix} 4 \\ 3 \end{bmatrix} = \begin{bmatrix} 8 \\ 6 \end{bmatrix} $$
1 2 3 |
v = np.array([4, 3]) double_v = 2 * v double_v |
1 |
array([8, 6]) |
1 2 3 4 5 6 7 8 9 10 11 12 |
ax = plt.axes() plt.xlim([0, 10]) plt.ylim([0, 10]) plt.grid() ax.arrow(0, 0, double_v[0], double_v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'b', ec = 'b') plt.annotate('2v', xy=(double_v[0], double_v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0], v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) plt.show() |
![умножение на скаляр](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/scalar_multiplication.png)
Умножение на отрицательное число не только удлиняет или укорачивает вектор, но и переворачивает его направление.
$$ -0,5 \cdot \textbf{v} = -0,5 \cdot \begin{bmatrix} 4 \\ 3 \end{bmatrix} = \begin{bmatrix} -2 \\ -1,5 \end{bmatrix} $$
1 2 3 |
v = np.array([4, 3]) neg_half_v = -0.5 * v neg_half_v |
1 |
array([-2. , -1.5]) |
1 2 3 4 5 6 7 8 9 10 11 12 |
ax = plt.axes() plt.xlim([-5, 5]) plt.ylim([-5, 5]) plt.grid() ax.arrow(0, 0, neg_half_v[0], neg_half_v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'b', ec = 'b') plt.annotate('-0.5v', xy=(neg_half_v[0], neg_half_v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0], v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) plt.show() |
![умножение на отрицательное число](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/neg_scalar_multiplication.png)
Очевидно, что умножение на −1 просто переворачивает направление вектора, но не меняет его длины.
$$ -1 \cdot \textbf{v} = -1 \cdot \begin{bmatrix} 4 \\ 3 \end{bmatrix} = \begin{bmatrix} -4 \\ -3 \end{bmatrix} $$
1 2 3 |
v = np.array([4, 3]) neg_one_v = -1 * v neg_one_v |
1 |
array([-4, -3]) |
1 2 3 4 5 6 7 8 9 10 11 12 |
ax = plt.axes() plt.xlim([-5, 5]) plt.ylim([-5, 5]) plt.grid() ax.arrow(0, 0, neg_one_v[0], neg_one_v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'b', ec = 'b') plt.annotate('-v', xy=(neg_one_v[0], neg_one_v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0], v[1]), xytext=(10, -10), textcoords='offset points', fontsize = 16) plt.show() |
![умножение на минус один](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/minus_one_multiplication.png)
Вычитание и деление на число
Вычитание векторов можно представить как сумму первого вектора со вторым вектором, умноженным на −1.
$$ \begin{bmatrix} 4 \\ 3 \end{bmatrix} + \left( -1 \cdot \begin{bmatrix} 2 \\ -1 \end{bmatrix} \right) = \begin{bmatrix} 2 \\ 4 \end{bmatrix} $$
1 2 3 4 5 6 7 8 |
a = np.array([4, 3]) b = np.array([2, -1]) b_neg = -1 * b a_minus_b = a + b_neg b_neg, a_minus_b |
1 |
(array([-2, 1]), array([2, 4])) |
Графически мы сначала находим вектор $\textbf{-b}$ (зеленая стрелка), а затем прибавляем его к вектору $\textbf{a}$ (красная стрелка).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
plt.figure(figsize = (8, 8)) ax = plt.axes() plt.xlim([0, 7]) plt.ylim([0, 7]) plt.grid() arrow_a = ax.arrow(0, 0, a[0], a[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') arrow_b_neg = ax.arrow(a[0], a[1], b_neg[0], b_neg[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') arrow_b = ax.arrow(a[0], a[1], b[0], b[1], width = 0.0001, head_width = 0.1, head_length = 0.1, length_includes_head = True, fc = 'black', ec = 'black', linestyle = '--') arrow_a_minus_b = ax.arrow(0, 0, a_minus_b[0], a_minus_b[1], width = 0.02, head_width = 0.2, head_length = 0.2, length_includes_head = True, fc = 'b', ec = 'b') plt.legend([arrow_a, arrow_b_neg, arrow_b, arrow_a_minus_b], ['вектор a', 'вектор -b', 'вектор b', 'вектор a+(-b)'], prop = {'size': 16}) plt.show() |
![вычитание векторов](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/a_minus_b.png)
Остается добавить, что деление вектора на число, это всего лишь умножение на обратное число (multiplicative inverse). Разделим вектор $\textbf{v}$ на семь.
$$ \frac{\textbf{v}}{7} = \begin{bmatrix} 4 \\ 3 \end{bmatrix} \cdot \frac{1}{7} = \begin{bmatrix} \frac{4}{7} \\ \frac{3}{7} \end{bmatrix} $$
1 2 3 |
v = np.array([4, 3]) v * (1/7) |
1 |
array([0.57142857, 0.42857143]) |
Тот факт, что мы выразили вычитание через сложение и умножение на скаляр, а деление через умножение на обратное число позволило нам остаться в пределах операций сложения и умножения на скаляр.
Видео про векторы⧉.
Длина вектора
Длину или норму вектора (norm, length, magnitude or size of a vector) рассчитать не сложно, достаточно вспомнить теорему Пифагора. Снова возьмем вектор $\textbf{v}$
$$ \textbf{v} = \begin{bmatrix} 4 \\ 3 \end{bmatrix} $$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
v = np.array([4, 3]) ax = plt.axes() plt.xlim([0, 5]) plt.ylim([-0.01, 5]) plt.grid() ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0]/2, v[1]/2), xytext=(10, -10), textcoords='offset points', fontsize = 16) ax.hlines(y = 0, xmin = 0, xmax = 4, linewidth = 3, color = 'b', linestyles = '--') ax.vlines(x = 4, ymin = 0, ymax = 3, linewidth = 3, color = 'g', linestyles = '--') plt.show() |
![координаты вектора и сам вектор образуют прямоугольный треугольник](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/vector_norm.png)
Как видно на графике, вектор $\textbf{v}$, смещение вдоль оси x и смещение вдоль оси y образуют прямоугольный треугольник. Значит, длина вектора (гипотенуза) равна квадратному корню из суммы квадратов смещений (катетов или в нашем случае координат).
$$ ||\textbf{v}|| = \sqrt{4^2 + 3^2} = \sqrt{25} = 5 $$
1 |
np.linalg.norm(v) |
1 |
5.0 |
Для n-мерного вектора ничего не меняется.
$$ ||\textbf{v}|| = \sqrt{v_1^2 + v_2^2 + \dots + v_n^2} $$
Например, найдем длину трехмерного вектора $\textbf{w}$.
$$ \textbf{w} = \begin{bmatrix} 6 \\ 3 \\ 2 \end{bmatrix} \rightarrow ||\textbf{w}|| = \sqrt{6^2 + 3^2 + 2^2} = \sqrt{49} = 7 $$
Единичный вектор
Вектор с длиной, равной единице, называют единичным вектором (unit vector). Примерами единичных векторов, с которыми мы будем часто встречаться в пространстве $ R^2 $, являются следующие два вектора
$$ \hat{i} = \begin{bmatrix} 1 \\ 0 \end{bmatrix}, \hat{j} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} $$
Единичный вектор принято обозначать строчной буквой с знаком циркумфлекса, «крышечки» (hat).
Проверим, равна ли их длина единице.
$$ ||\hat{i}|| = \sqrt{1^2 + 0^2} = \sqrt{1} = 1, ||\hat{j}|| = \sqrt{0^2 + 1^2} = \sqrt{1} = 1 $$
Интересно, что с помощью векторов $ \hat{i}, \hat{j} $ можно выразить любой другой вектор в $ R^2 $. Например, вектор $\textbf{v}$ можно представить как
$$ 4 \begin{bmatrix} 1 \\ 0 \end{bmatrix} + 3 \begin{bmatrix} 0 \\ 1 \end{bmatrix} = \begin{bmatrix} 4 \\ 3 \end{bmatrix} \rightarrow 4\hat{i} + 3 \hat{j} $$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
v = np.array([4, 3]) i = np.array([1, 0]) j = np.array([0, 1]) ax = plt.axes() plt.xlim([-0.07, 4.5]) plt.ylim([-0.07, 4.5]) plt.grid() ax.arrow(0, 0, v[0], v[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') plt.annotate('v', xy=(v[0]/2, v[1]/2), xytext=(10, -10), textcoords='offset points', fontsize = 16) ax.arrow(0, 0, i[0], i[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') ax.arrow(0, 0, j[0], j[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') plt.show() |
![вектор, как линейная комбинация базисных векторов](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/unit_vectors.png)
Это обстоятельство нам пригодится в будущем.
Нормализация вектора
Длина нормализованного вектора равна единице. Для того чтобы нормализовать вектор, достаточно разделить вектор на его длину. Создадим единичный вектор $\hat{v}$ для вектора $\textbf{v}$.
$$ \hat{v} = \frac{\textbf{v}}{||\textbf{v}||} = \frac{1}{5} \cdot \begin{bmatrix} 4 \\ 3 \end{bmatrix} = \begin{bmatrix} \frac{4}{5} \\ \frac{3}{5} \end{bmatrix} $$
1 2 3 |
v = np.array([4, 3]) v * (1/np.linalg.norm(v)) |
1 |
array([0.8, 0.6]) |
Скалярное произведение
Важной операцией над векторами является уже знакомое нам скалярное произведение (dot product). В качестве напоминания того, как работает скалярное произведение приведем несложный пример. Пусть даны два вектора $\textbf{v}$ и $\textbf{w}$.
$$ \textbf{v} = \begin{bmatrix} 4 \\ 3 \end{bmatrix}, \textbf{w} = \begin{bmatrix} 2 \\ 1 \end{bmatrix} $$
Найдем их скалярное произведение.
$$ \textbf{v} \cdot \textbf{w} = 4 \cdot 2 + 3 \cdot 1 = 11 $$
Как вы видите, мы перемножаем компоненты векторов и складываем получившиеся произведения.
Скалярное произведение как длина вектора
Интересно, что корень из скалярного произведения вектора на самого себя есть его длина.
$$ \sqrt{ \textbf{v} \cdot \textbf{v} } = \sqrt{4 \cdot 4 + 3 \cdot 3 } = \sqrt{ 4^2 + 3^2 } = \sqrt{25} = 5 $$
1 2 3 |
v = np.array([4, 3]) np.sqrt(v.dot(v)) |
1 |
5.0 |
Угол между векторами
В предисловии мы сказали, что скалярное произведение также определяется как произведение длин векторов на косинус угла между ними.
$$ \mathbf a \cdot \mathbf b = || \mathbf a || \cdot || \mathbf b || \cdot \cos \theta $$
Именно это свойство привело нас к расчету косинусного сходства между векторами.
$$ \cos \theta = \frac{\mathbf a \cdot \mathbf b}{|| \mathbf a || \cdot || \mathbf b ||} $$
Выведем эту формулу. Вначале вспомним теорему косинусов.
![теорема косинусов](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/cosine_rule.png)
$$ c^2 = a^2 + b^2-2ab \cdot \cos \theta $$
Теперь представим, что у нас не стороны треугольника, а векторы. Если сторону а обозначить как вектор $ \textbf{a} $, сторону b — как вектор $ \textbf{b} $, то сторона с станет разностью между $ \textbf{a} $ и $ \textbf{b} $ (чтобы убедиться в этом, найдите $ \textbf{-b} $ и приставьте его к окончанию $ \textbf{a} $).
![треугольник из векторов](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/vector_cosine_rule.png)
Выразим теорему косинусов через длины векторов. Другими словами, представим, что мы имеем дело не с отрезками на плоскости, а с многомерными векторами (для удобства не будем выделять векторы полужирным шрифтом).
$$ || a-b ||^2 = ||a||^2 + ||b||^2-2 \cdot ||a|| \cdot ||b|| \cdot \cos \theta $$
Помня, что длина есть скалярное произведение вектора на самого себя, мы можем выразить левую часть $ || a-b || $ как
$$ (a-b)(a-b) = a \cdot a-a \cdot b-b \cdot a + (-b) \cdot (-b) = ||a||^2-2ab + ||b||^2 $$
Поместим результат в исходное выражение.
$$ ||a||^2-2ab + ||b||^2 = ||a||^2 + ||b||^2-2 \cdot ||a|| \cdot ||b|| \cdot \cos \theta $$
Сократив подобные члены получим
$$ a \cdot b = ||a|| \cdot ||b|| \cdot \cos \theta $$
Выводы. Из тригонометрии мы помним, что косинус 90 градусов равен нулю. Как следствие, скалярное произведение перпендиклярных (правильнее сказать ортогональных (orthogonal)) векторов $ \textbf{a} \perp \textbf{b} $ равно нулю.
$$ a \cdot b = ||a|| \cdot ||b|| \cdot \cos 90^{\circ} = 0 $$
Очевидно, что если угол между двумерными векторами меньше 90 градусов, косинус, а значит и скалярное произведение положительны. В противном случае — отрицательны. Для n-мерных векторов положительное скалярное произведение говорит, что они в целом смотрят в одну строну, отрицательное — противоположные.
Для коллинеарных (сонаправленных) векторов скалярное произведение равно произведению их длин, потому что косинус нуля равен единице.
$$ a \cdot b = ||a|| \cdot ||b|| \cdot \cos 0^{\circ} = ||a|| \cdot ||b|| $$
Добавлю, что если $ \textbf{a} $ и $ \textbf{b} $ — единичные векторы, то косинус угла между векторами просто равен его их скалярному произведению.
$$ \cos \theta = a \cdot b $$
Рассчитаем косинусное расстояние для векторов
$$ \textbf{v} = \begin{bmatrix} 4 \\ 3 \end{bmatrix}, \textbf{w} = \begin{bmatrix} 1 \\ 7 \end{bmatrix} $$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
a = np.array([4, 3]) b = np.array([1, 7]) numerator = np.dot(a, b) aLen = np.linalg.norm(a) bLen = np.linalg.norm(b) denominator = aLen * bLen cosine = numerator / denominator angle = np.arccos(cosine) * 360/2/np.pi cosine, angle |
1 |
(0.7071067811865475, 45.00000000000001) |
1 2 3 |
from scipy.spatial import distance 1 - distance.cosine([4, 3], [1, 7]) |
1 |
0.7071067811865475 |
Внешнее произведение
Под внешним произведением (outer product) понимается умножение вектор-столбца на вектор-строку по обычным правилам матричного умножения. Результатом такого произведения будет матрица, а не число, как в случае скалярного произведения.
![внешнее произведение](https://www.dmitrymakarov.ru/wp-content/uploads/2023/02/outer-1024x216.jpg)
Ортогональность векторов
Еще раз продемонстрируем, почему если векторы ортогональны, их скалярное произведение будет равно нулю. Возьмем три вектора, образовывающих прямоугольный треугольник.
![ортогональность векторов](https://www.dmitrymakarov.ru/wp-content/uploads/2023/02/image-4-1024x625.png)
Тогда, по теореме Пифагора,
$$ || \mathbf x ||^2 + || \mathbf y ||^2 = || \mathbf x + \mathbf y ||^2 $$
$$ \mathbf x^T \mathbf x + \mathbf y^T \mathbf y = (\mathbf x + \mathbf y)^T (\mathbf x + \mathbf y) $$
$$ \mathbf x^T \mathbf x + \mathbf y^T \mathbf y = \mathbf x^T \mathbf x + \mathbf y^T \mathbf y + \mathbf x^T \mathbf y + \mathbf y^T \mathbf x $$
$$ \mathbf x^T \mathbf x + \mathbf y^T \mathbf y = \mathbf x^T \mathbf x + \mathbf y^T \mathbf y + 2 \mathbf x^T \mathbf y $$
$$ \mathbf 0 = 2 \mathbf x^T \mathbf y $$
$$ \mathbf x^T \mathbf y = \mathbf 0 $$
Проекция вектора на вектор
Подойдем к скалярному произведению с другой стороны. Рассмотрим два вектора $ \textbf{a} $ и $ \textbf{b} $ и найдем проекцию первого вектора на второй.
![проекция вектора на вектор](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/projection.png)
Проекция через угол между векторами
Говоря неформально, проекцией вектора $ \textbf{a} $ на вектор $ \textbf{b} $ будет такой участок вектора $ \textbf{b} $, что расстояние от точки A до точки B минимально. Минимальным оно будет, если угол OAB будет равен 90 градусов. Получается прямоугольный треугольник. Найдем отрезок OB.
$$ \cos \theta = \frac {OB}{OA} = \frac {OB}{|| \mathbf a ||} \rightarrow OB = || \mathbf a || \cdot \cos \theta $$
Выразим то же самое через формулу скалярного произведения, заменив $|| \mathbf a || \cdot \cos \theta $ на OB.
$$ \mathbf b \cdot \mathbf a = || \mathbf b || \cdot || \mathbf a || \cdot \cos \theta \rightarrow \mathbf b \cdot \mathbf a = || \mathbf b || \cdot OB $$
Так мы нашли длину проекции OB. Ее называют числовой или скалярной проекцией (scalar projection).
$$ \frac{\mathbf b \cdot \mathbf a}{|| \mathbf b ||} = || \mathbf a || \cdot \cos \theta = OB $$
Более того, если длина вектора $ \textbf{b} $ равна единице, то длина проекции OB просто равна скалярному произведению.
$$ || \mathbf b || = 1 \rightarrow \mathbf b \cdot \mathbf a = OB $$
Это объясняет, почему скалярное произведение еще называют projection product.
Очевидное и тем не менее интересное примечание. Обратите внимание на связь понимания скалярного произведения как проекции одного вектора на другой и произведения длин векторов на косинус угла между ними. Если векторы перпендикулярны, проекция одного вектора на другой равна нулю, а значит и произведение проекции второго вектора на первый равно нулю.
![перпендикулярные векторы](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/zero_projection.png)
Предположим, нас интересует не только длина проекции, но и ее направление. В этом случае говорят про векторную проекцию (vector projection).
![векторная проекция](https://www.dmitrymakarov.ru/wp-content/uploads/2022/04/vector_projection.png)
Она выражается как произведение нормализованного вектора $ \textbf{b} $ на длину проекции (то есть скалярную проекцию) OB.
$$ proj_\mathbf{b} \textbf{a} = OB \cdot \hat{b} $$
Перепишем OB через скалярное произведение, а $\hat{b}$ через частное вектора $ \textbf{b} $ на его длину.
$$ proj_\mathbf{b} \textbf{a} = \frac{\mathbf b \cdot \mathbf a}{|| \mathbf b ||} \cdot \frac{\mathbf b}{|| \mathbf b ||} $$
Таким образом, можно сказать, что векторная проекция показывает, длину вектора $ \textbf{a} $ в направлении вектора $ \textbf{b} $.
Пример. Возьмем два вектора $ \mathbf a$ и $ \mathbf b$ и найдем вначале скалярную, затем векторную проекцию вектора $ \mathbf a$ на вектор $ \mathbf b$.
1 2 3 4 5 |
a = np.array([3, 4]) b = np.array([1, 1]) scalar_proj_a_on_b = np.dot(a, b) / np.linalg.norm(b) scalar_proj_a_on_b |
1 |
4.949747468305833 |
1 2 |
vector_proj_a_on_b = scalar_proj_a_on_b * (b / np.linalg.norm(b)) vector_proj_a_on_b |
1 |
array([3.5, 3.5]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
a = np.array([3, 4]) b = np.array([1, 1]) proj = np.array([3.5, 3.5]) ax = plt.axes() plt.xlim([-0.07, 4.5]) plt.ylim([-0.07, 4.5]) plt.grid() ax.arrow(0, 0, a[0], a[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') ax.arrow(0, 0, b[0], b[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'k', ec = 'k') ax.arrow(0, 0, proj[0], proj[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') plt.show() |
![пример нахождения скалярной и векторной проекции](https://www.dmitrymakarov.ru/wp-content/uploads/2023/01/proj_a_b.png)
Матрица проекции
Векторную проекцию можно выразить с помощью матрицы проекции $P$.
$$ proj_\mathbf{b} \textbf{a} = P \cdot \mathbf a = \frac{\mathbf b \mathbf b^T}{\mathbf b^T \mathbf b} \cdot \mathbf a $$
В знаменателе находится скалярное произведение и результатом умножения будет число. В числителе — внешнее произведение и результатом будет матрица. Найдем внешнее произведение из примера выше.
1 2 |
b_bT = np.outer(b, b) b_bT |
1 2 |
array([[1, 1], [1, 1]]) |
Найдем скалярное произведение.
1 2 |
bT_b = np.dot(b, b) bT_b |
1 |
2 |
Создадим матрицу проекции $P$ и умножим ее на вектор $\mathbf a$.
1 2 |
P = b_bT / bT_b P @ a |
1 |
array([3.5, 3.5]) |
Симметрия скалярного произведения
Продемонстрируем с точки зрения проекции, почему $\mathbf a \cdot \mathbf b = \mathbf b \cdot \mathbf a $. Возьмем два вектора $\mathbf a$ и $\mathbf b$.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
a = np.array([1, 3]) b = np.array([4, 1]) i = np.array([1, 0]) j = np.array([0, 1]) ax = plt.axes() plt.xlim([-0.07, 4]) plt.ylim([-0.07, 4]) plt.grid() ax.arrow(0, 0, a[0], a[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'r', ec = 'r') ax.arrow(0, 0, b[0], b[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'k', ec = 'k') ax.arrow(0, 0, i[0], i[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') ax.arrow(0, 0, j[0], j[1], width = 0.02, head_width = 0.1, head_length = 0.2, length_includes_head = True, fc = 'g', ec = 'g') ax.plot([0, 4], [0, 4], linestyle = 'dashed') plt.show() |
![симметрия скалярного произведения](https://www.dmitrymakarov.ru/wp-content/uploads/2023/01/dot_product_symmetry.png)
Выше мы сказали, что $ \mathbf a \cdot \mathbf b = OB \cdot || \mathbf b|| $. То есть скалярное произведение вектора $\mathbf a$ на вектор $\mathbf b$ равно произведению проекции $\mathbf a$ на $\mathbf b$, умноженной на длину вектора $\mathbf b$.
Продемонстрируем, что произведение проекции вектора $\mathbf a$ на вектор $\mathbf b$, умноженное на длину вектора $\mathbf b$, равно произведению проекции вектора $\mathbf b$ на вектор $\mathbf a$, умноженному на длину вектора $\mathbf a$.
$$ proj_b \mathbf a \times || \mathbf b || = proj_a \mathbf b \times || \mathbf a || $$
1 2 |
scalar_proj_a_on_b = np.dot(a, b) / np.linalg.norm(b) scalar_proj_a_on_b * np.linalg.norm(b) |
1 |
7.0 |
1 2 |
scalar_proj_b_on_a = np.dot(b, a) / np.linalg.norm(a) scalar_proj_b_on_a * np.linalg.norm(a) |
1 |
7.0 |
1 |
np.dot(a, b), np.dot(b, a) |
1 |
(7, 7) |
Видео про скалярное произведение векторов⧉.
Векторное произведение
Векторное произведение (cross product) задано только в трехмерном пространстве. Результатом такого произведения будет вектор, перпендикулярный каждому из исходных векторов. Приведем иллюстрацию из Википедии⧉.
![векторное произведение](https://www.dmitrymakarov.ru/wp-content/uploads/2023/01/cross_product.png)
Математически векторное произведение задается формулой
$$ \mathbf a \times \mathbf b = || \mathbf a || \cdot || \mathbf b || \cdot \sin \theta $$
Геометрически — это площадь параллелограмма, сформированного из исходных векторов $\mathbf a$ и $\mathbf b$.
![векторное произведение как площадь параллелограмма](https://www.dmitrymakarov.ru/wp-content/uploads/2023/01/cross_product_parallelogram-1024x800.png)
Приведем пример.
1 2 3 4 |
a = [1, 2, 3] b = [4, 5, 6] np.cross(a, b) |
1 |
array([-3, 6, -3]) |
Подведем итог
Сегодня мы ввели понятие вектора, познакомились с базовыми операциями с векторами, в частности, изучили скалярное произведение векторов и научились находить скалярную и векторную проекцию одного вектора на другой.
Перейдем к рассмотрению векторного пространства.