Векторы: длина, сложение, скалярное произведение

⏱ 30 мин · 🧩 заданий: 6

Что такое вектор

У вектора два равноправных лица:

  • геометрическое — стрелка из начала координат: у неё есть направление и длина;
  • числовое — упорядоченный список чисел (координат): v = (3, 2).

В ML мы почти всегда думаем о второй стороне, но опираемся на первую. Квартира с площадью 50 м², 2 комнатами и 5-м этажом — это вектор (50, 2, 5) в трёхмерном пространстве. Картинка 8×8 — вектор из 64 чисел, точка в 64-мерном пространстве. Слово в языковой модели — вектор из сотен чисел. Нарисовать 64 измерения нельзя, но все формулы работают точно так же, как на плоскости.

import numpy as np
import vis

a = np.array([3, 1])
b = np.array([1, 2])
vis.vectors([a, b, a + b, 2 * b, -a], labels=["a", "b", "a + b", "2b", "−a"], title="Векторы на плоскости")

Сложение и умножение на число

Обе операции — покоординатные:

  • a + b = (a₁ + b₁, a₂ + b₂) — геометрически: приставить начало b к концу a (правило треугольника);
  • k · a = (k·a₁, k·a₂) — растянуть стрелку в k раз; при k < 0 — развернуть.
import numpy as np

a = np.array([3, 1])
b = np.array([1, 2])
print("a + b =", a + b)
print("a − b =", a - b)        # вектор из конца b в конец a
print("2a    =", 2 * a)
print("0.5(a + b) =", 0.5 * (a + b))   # середина между концами a и b

Линейная комбинация — сумма векторов с коэффициентами: c₁·v₁ + c₂·v₂ + …. Это центральное понятие: умножение матрицы на вектор, работа нейрона, взвешенное среднее в механизме внимания — всё это линейные комбинации.

Длина (норма)

Длина вектора — по теореме Пифагора:

\|v\| = \sqrt{v_1^2 + v_2^2 + \dots + v_n^2}
import numpy as np

v = np.array([3.0, 4.0])
print(np.sqrt((v ** 2).sum()))     # 5.0 — вручную
print(np.linalg.norm(v))           # 5.0 — готовая функция

u = v / np.linalg.norm(v)          # нормализация: тот же вектор, но длины 1
print(u, np.linalg.norm(u))

a, b = np.array([1.0, 2]), np.array([4.0, 6])
print("расстояние между точками:", np.linalg.norm(a - b))
  • Расстояние между точками a и b — длина разности ‖a − b‖.
  • Единичный вектор (длины 1) показывает только направление. Деление на длину называется нормализацией.

Другие нормы

Норма L2 (евклидова) — это то, что выше. Норма L1 — сумма модулей |v₁| + |v₂| + … («манхэттенское расстояние»). Обе встретятся в уроке про переобучение как штрафы за большие веса.

Скалярное произведение

Скалярное произведение (dot product) — сумма произведений координат:

a \cdot b = a_1 b_1 + a_2 b_2 + \dots + a_n b_n

Результат — одно число. В NumPy: a @ b или np.dot(a, b).

Геометрически оно связано с углом θ между векторами:

a \cdot b = \|a\| \cdot \|b\| \cdot \cos\theta
Угол cos θ Скалярное произведение
0° (сонаправлены) 1 максимально, ‖a‖·‖b‖
острый > 0 положительное
90° (перпендикулярны) 0 ноль
тупой < 0 отрицательное
180° (противоположны) −1 минимально

Иными словами, скалярное произведение измеряет, насколько векторы смотрят в одну сторону.

import numpy as np
import vis

a = np.array([2.0, 0.0])
angles = np.linspace(0, 2 * np.pi, 73)
dots = [a @ np.array([np.cos(t), np.sin(t)]) for t in angles]
vis.line(np.degrees(angles), dots, title="a · b при повороте единичного b вокруг начала",
         xlabel="угол между a и b, градусы", ylabel="a · b")

Проекция

a · u, где u — единичный вектор, это длина тени a на направление u. Например, если u указывает на «восток», то a · u — сколько a продвигается на восток.

import numpy as np
import vis

a = np.array([3.0, 2.0])
u = np.array([1.0, 0.3]); u = u / np.linalg.norm(u)
shadow = a @ u
proj = shadow * u               # проекция a на направление u
print(f"длина проекции = {shadow:.3f}")
vis.vectors([a, u, proj, a - proj], labels=["a", "u", "проекция", "a − проекция"], title="Проекция a на u")
print("остаток перпендикулярен u:", round(float((a - proj) @ u), 10))

Косинусная близость

Если поделить скалярное произведение на длины, получится косинус угла — косинусная близость от −1 до 1:

\cos\theta = \frac{a \cdot b}{\|a\|\,\|b\|}

Она сравнивает направления, игнорируя длины. Так работают поиск похожих документов, рекомендации и эмбеддинги слов: похожие по смыслу объекты получают векторы, смотрящие в похожую сторону.

import numpy as np

# игрушечные «эмбеддинги» фильмов: (боевик, комедия, романтика)
films = {
    "Терминатор":     np.array([0.9, 0.1, 0.0]),
    "Крепкий орешек": np.array([0.8, 0.3, 0.1]),
    "Маска":          np.array([0.3, 0.9, 0.2]),
    "Титаник":        np.array([0.2, 0.0, 0.9]),
}

def cosine(a, b):
    return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))

q = films["Терминатор"]
for name, v in films.items():
    print(f"{name:15} {cosine(q, v):.3f}")

Нейрон — это скалярное произведение

Забегая вперёд: искусственный нейрон получает вектор входов x, у него есть вектор весов w и число b (сдвиг). Он считает

z = w \cdot x + b

и пропускает z через нелинейную функцию. Скалярное произведение здесь — «насколько вход похож на то, что ищет нейрон». Веса w — это шаблон, а сдвиг b — порог, с которого нейрон «загорается».

import numpy as np

w = np.array([0.5, -1.0, 2.0])   # что «ищет» нейрон
b = -0.5

for x in ([1, 0, 1], [0, 1, 0], [2, 0, 1]):
    x = np.array(x)
    z = w @ x + b
    print(x, "→ z =", z, "→ активен" if z > 0 else "→ молчит")

Вся линейная алгебра дальше — это способ делать много таких скалярных произведений сразу.

Итог

  • Вектор — стрелка и список чисел одновременно; объект с d признаками — точка в d-мерном пространстве.
  • Сложение и умножение на число — покоординатно; линейная комбинация — главная операция.
  • Длина ‖v‖ = √(Σvᵢ²), расстояние — длина разности, нормализация — деление на длину.
  • Скалярное произведение a·b = Σaᵢbᵢ = ‖a‖‖b‖cos θ показывает, насколько векторы сонаправлены; 0 — перпендикулярны.
  • Косинусная близость сравнивает направления; нейрон считает w·x + b.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Ввод ответа

Чему равно скалярное произведение векторов a = (1, 2, 3) и b = (4, -5, 6)?

Задание 2 Ввод ответа

Чему равна длина (евклидова норма) вектора (3, 4)?

Задание 3 Один вариант ответа

Скалярное произведение двух ненулевых векторов равно 0. Что это значит?

Задание 4 Заполнить таблицу

Каким будет знак скалярного произведения?

> 0= 0< 0
(1, 0) и (1, 1)
(1, 0) и (0, 5)
(2, 1) и (-1, -3)
(1, 2) и (2, -1)
Отметьте ячейку — «+», пустая — «−».
Задание 5 Программа на Python

Напишите без NumPy, на чистом Python, функции для векторов-списков:

  • dot(a, b) — скалярное произведение;
  • norm(a) — длина вектора;
  • cosine(a, b) — косинус угла между векторами: dot(a, b) / (norm(a) * norm(b)).
Какие тесты проверяют код (4)
assert dot([1, 2, 3], [4, -5, 6]) == 12
assert abs(norm([3, 4]) - 5) < 1e-12 and abs(norm([1, 1, 1, 1]) - 2) < 1e-12
assert abs(cosine([1, 0], [0, 7])) < 1e-12 and abs(cosine([2, 2], [5, 5]) - 1) < 1e-12 and abs(cosine([1, 0], [-3, 0]) + 1) < 1e-12
import inspect
assert "numpy" not in inspect.getsource(dot) + inspect.getsource(norm), "Без NumPy — посчитайте сами"

Задание 6 Программа на Python

Поиск похожих. Дана матрица E формы (n, d) — векторы n объектов (например, фильмов), и вектор запроса q формы (d,). Напишите most_similar(E, q), возвращающую индекс строки E с наибольшей косинусной близостью к q. Используйте NumPy, без циклов.

Какие тесты проверяют код (2)
E = np.array([[10.0, 0], [1, 1], [0, 3]])
assert most_similar(E, np.array([1.0, 1.1])) == 1, "Скалярное произведение без деления на длины выберет просто самый длинный вектор"

E = np.array([[1.0, 0, 0], [0, 1, 0], [0, 0, 100]])
assert most_similar(E, np.array([0.9, 0.1, 0.05])) == 0

Войдите, чтобы отмечать пройденные уроки.