Векторы: длина, сложение, скалярное произведение
Что такое вектор
У вектора два равноправных лица:
- геометрическое — стрелка из начала координат: у неё есть направление и длина;
- числовое — упорядоченный список чисел (координат):
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₂ + …. Это центральное понятие: умножение матрицы на вектор, работа нейрона, взвешенное среднее в механизме внимания — всё это линейные комбинации.
Длина (норма)
Длина вектора — по теореме Пифагора:
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) — сумма произведений координат:
Результат — одно число. В NumPy: a @ b или np.dot(a, b).
Геометрически оно связано с углом θ между векторами:
| Угол | 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:
Она сравнивает направления, игнорируя длины. Так работают поиск похожих документов, рекомендации и эмбеддинги слов: похожие по смыслу объекты получают векторы, смотрящие в похожую сторону.
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 — это шаблон, а сдвиг 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
Чему равно скалярное произведение векторов a = (1, 2, 3) и b = (4, -5, 6)?
Чему равна длина (евклидова норма) вектора (3, 4)?
Скалярное произведение двух ненулевых векторов равно 0. Что это значит?
Каким будет знак скалярного произведения?
| > 0 | = 0 | < 0 | |
|---|---|---|---|
(1, 0) и (1, 1) |
|||
(1, 0) и (0, 5) |
|||
(2, 1) и (-1, -3) |
|||
(1, 2) и (2, -1) |
Напишите без 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 — посчитайте сами"
import math
def dot(a, b):
return sum(x * y for x, y in zip(a, b))
def norm(a):
return math.sqrt(dot(a, a))
def cosine(a, b):
return dot(a, b) / (norm(a) * norm(b))
Поиск похожих. Дана матрица 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
import numpy as np
def most_similar(E, q):
sims = (E @ q) / (np.linalg.norm(E, axis=1) * np.linalg.norm(q))
return int(np.argmax(sims))
Войдите, чтобы отмечать пройденные уроки.