Как только мы представили данные в виде чисел и векторов, возникает естественный вопрос: как понять, что два объекта похожи или, наоборот, сильно отличаются? Машинное обучение почти всегда сводится к сравнению. Этот текст ближе к тому или к этому, этот пользователь похож на другого или нет, это изображение относится к классу A или B и т.д.
Чтобы формализовать такие рассуждения, нам нужны меры расстояния и меры сходства. В математике и ML это не абстрактные термины, а конкретные функции, которые принимают два вектора и возвращают число. По этому числу алгоритм и принимает решения.
В этой главе мы разберем три ключевых инструмента: евклидово расстояние, скалярное произведение (dot product) и косинусное сходство (cosine similarity). Они лежат в основе k-NN, линейных моделей, рекомендательных систем, поиска по текстам и эмбеддингов.
Евклидово расстояние – "обычная" геометрия
Евклидово расстояние – это расстояние "по линейке" между двумя точками в пространстве.
Если у нас есть два вектора
то евклидово расстояние между ними определяется формулой:
Если , это расстояние между точками на прямой, если , то это расстояние между точками на плоскости, при – уже в трёхмерном пространстве и т.д. Если или, например, , то по сути геометрия остается той же самой, просто ее уже нельзя нарисовать напрямую, так как человек не в состоянии воспринимать изображения в пространстве, имеющем больше, чем 3 измерения.

Рис. 1. Евклидово расстояние в 2D
Но, при этом, на плоскости это выглядит очень наглядно: две точки и отрезок между ними. В машинном обучении мы делаем ровно то же самое, только в пространстве большей размерности.
Как вы наверняка запомнили из предыдущей главы – евклидово расстояние чувствительно к масштабу и поэтому перед использованием такого расстояния данные часто нормализуют или стандартизируют, если признаки имеют разные масштабы.
Интуитивно: два объекта похожи, если расстояние между их векторами маленькое.
PHP-пример
function euclideanDistance(array $a, array $b): float {
$n = count($a);
if ($n !== count($b)) {
throw new InvalidArgumentException('Vectors must have the same length');
}
$sum = 0.0;
for ($i = 0; $i < $n; $i++) {
$diff = $a[$i] - $b[$i];
$sum += $diff ** 2;
}
return sqrt($sum);
}
Пример:
$a = [1, 2, 3];
$b = [4, 6, 3];
$distance = euclideanDistance($a, $b);
echo $distance;
// Результат: 5
// Объяснение: √((1 - 4)^2 + (2 - 6)^2 + (3 - 3)^2) = √(9 + 16 + 0) = √(25) = 5
Этот код уже можно использовать в простейшем k-NN классификаторе: мы просто ищем объекты с минимальным расстоянием среди имеющейся выборки.
Скалярное произведение (dot product) – мера согласованности
Скалярное произведение двух векторов определяется как:
На первый взгляд это просто сумма произведений соответствующих координат и выглядит всего лишь как удобный способ перемножить два набора чисел. Однако у скалярного произведения есть и геометрический смысл:
где – угол между векторами, а длина (модуль) вектора, определяется как:

Рис. 1.3-2. Два вектора и угол между ними
Скалярное произведение становится больше, когда одновременно выполняются два условия:
- Векторы смотрят почти в одну сторону\ Если угол между ними маленький, их направления совпадают – вклад направления максимален ( ).
- Векторы длинные\ Чем больше длины векторов, тем больше итоговое значение (произведение модулей велико), даже при фиксированном направлении.
Проще говоря:
скалярное произведение = насколько направления совпадают × насколько векторы "крупные"
Это ключевой момент: скалярное произведение учитывает и направление, и масштаб. Из-за этого скалярное произведение смешивает два разных эффекта:
- направление (похожи ли векторы)
- масштаб (насколько они большие)
Поэтому его нельзя считать "чистой" мерой сходства. Два вектора могут быть идеально сонаправлены, но если один из них в 10 раз длиннее, скалярное произведение вырастет в 10 раз – хотя направление осталось тем же.
В машинном обучении это используется осознанно. В линейных моделях большое скалярное произведение означает сильную активацию. В нейросетях и attention-механизмах оно интерпретируется как мера важности или связи.

Рис. 1.3-3. Скалярное произведение как проекция одного вектора на другой
Если представить геометрически, то это можно интерпретировать как длину проекции одного вектора на направление другого, умноженную на длину второго вектора.
PHP-пример
function dotProduct(array $a, array $b): float {
$n = count($a);
if ($n !== count($b)) {
throw new InvalidArgumentException('Vectors must have the same length');
}
$sum = 0.0;
for ($i = 0; $i < $n; $i++) {
$sum += $a[$i] * $b[$i];
}
return $sum;
}
Пример:
$a = [1, 2, 3];
$b = [4, 5, 6];
$result = dotProduct($a, $b);
echo $result;
// Результат: 32
// Объяснение: (1 * 4) + (2 * 5) + (3 * 6) = 4 + 10 + 18 = 32
Косинусное сходство – сравнение направлений
Как мы уже упоминали в прошлой главе - косинусное сходство отвечает на вопрос: насколько векторы направлены в одну сторону, независимо от их длины.
Оно определяется следующей формулой (нетрудно заметить, что она выводится из формулы скалярного произведения векторов):
Результат лежит в диапазоне от -1 до 1, и хотя в практических задачах NLP и эмбеддингов отрицательные значения встречаются редко, но математически они возможны:
- 1 – одинаковое направление
- 0 – ортогональные векторы
- -1 – противоположные направления

Рис. 1.3-4. Один и тот же угол, разные длины векторов
На этой картинке важно увидеть: длины разные, но угол одинаковый – значит, косинусное сходство одинаковое.
Это делает косинусное сходство идеальной мерой для текстов и эмбеддингов, где длина вектора часто отражает не смысл, а масштаб (длина текста, частота слов).
PHP-пример
function cosineSimilarity(array $a, array $b): float {
$dot = dotProduct($a, $b);
$normA = sqrt(dotProduct($a, $a));
$normB = sqrt(dotProduct($b, $b));
if ($normA == 0 || $normB == 0) {
throw new InvalidArgumentException('Zero vector');
}
return $dot / ($normA * $normB);
}
Пример:
$a = [1, 2];
$b = [2, 1];
$similarity = cosineSimilarity($a, $b);
echo $similarity;
// Результат: 0.8
// Объяснение:
// dot = 1 * 2 + 2 * 1 = 4
// normA = sqrt(1 * 1 + 2 * 2) = sqrt(5)
// normB = sqrt(2 * 2 + 1 * 1) = sqrt(5)
// cosine = 4 / (sqrt(5) * sqrt(5)) = 4 / 5 = 0.8
В данном случае результат 0.8 означает, что векторы довольно похожи по направлению, но не совпадают полностью.
Ресурсы
Адаптированный материал из книги "Искусственный интеллект для PHP-разработчиков":
https://apphp.gitbook.io/ai-for-php-developers
Online Demo:
https://aiwithphp.org/books/ai-for-php-developers/examples/part-1/distances-and-similarity
Top comments (0)