Скалярное произведение: проекция, угол и косинусная близость
Скалярное произведение превращает два вектора в одно число, которое говорит, насколько они «смотрят в одну сторону».
Скалярное произведение (dot product) векторов a и b — сумма произведений соответствующих координат:
a·b = a1·b1 + a2·b2 + ... + an·bn. Результат — число (скаляр).
Формула и реализация
Берём по координате из каждого вектора, перемножаем, складываем всё. Одна строка кода — и при этом одна из самых важных операций во всём ML.
def dot(a, b):
return sum(x * y for x, y in zip(a, b))
a = [1, 2, 2]
b = [2, 0, 1]
print("a·b =", dot(a, b)) # 1*2 + 2*0 + 2*1 = 4
print("a·a =", dot(a, a)) # = квадрат длины a
Вывод:
a·b = 4 a·a = 9
Геометрический смысл: проекция и угол
Есть вторая, геометрическая формула того же числа: a·b = |a|·|b|·cos(θ), где |a| и |b| — длины векторов, а θ — угол между ними. Отсюда читается смысл:
- Векторы смотрят в одну сторону (θ ≈ 0°, cos ≈ 1) → произведение большое положительное.
- Векторы перпендикулярны (θ = 90°, cos = 0) → произведение ноль. Это и есть определение «ортогональности».
- Векторы смотрят в разные стороны (θ > 90°, cos < 0) → произведение отрицательное.
То есть скалярное произведение измеряет «согласованность направлений». А ещё это проекция: a·b с точностью до длины b показывает, насколько a «вкладывается» в направление b. В нейросети сигнал нейрона — это скалярное произведение входа на веса: «насколько вход похож на то, что нейрон ищет».
Вычисляем угол между векторами
Развернём геометрическую формулу: cos(θ) = (a·b) / (|a|·|b|). Зная косинус, найдём сам угол через math.acos.
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))
a = [1, 2, 2]
b = [2, 0, 1]
cos_theta = dot(a, b) / (norm(a) * norm(b))
angle_rad = math.acos(cos_theta)
print("cos(theta) =", round(cos_theta, 4))
print("Угол в градусах =", round(math.degrees(angle_rad), 2))
Вывод:
cos(theta) = 0.5963 Угол в градусах = 53.4
Косинусная близость — мера похожести в ML
Сам cos(θ) называют косинусной близостью (cosine similarity). Это любимая метрика похожести для текстов, рекомендаций и эмбеддингов: она смотрит только на направление, игнорируя длину. Два текста про одно и то же будут иметь близость около 1, даже если один длиннее другого. Значение лежит в диапазоне от −1 (противоположны) до 1 (сонаправлены).
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_similarity(a, b):
return dot(a, b) / (norm(a) * norm(b))
x = [1, 1, 0] # документ 1
y = [2, 2, 0] # документ 2 — то же направление, но длиннее
z = [0, 0, 1] # документ 3 — про другое
print("sim(x, y) =", round(cosine_similarity(x, y), 4)) # ~1: похожи
print("sim(x, z) =", round(cosine_similarity(x, z), 4)) # 0: ортогональны
Вывод:
sim(x, y) = 1.0 sim(x, z) = 0.0
Итог
- Скалярное произведение = сумма произведений координат = одно число.
- Геометрически
a·b = |a|·|b|·cos(θ): измеряет согласованность направлений. - Ноль означает перпендикулярность; косинусная близость — стандартная мера похожести в ML.