4.2. Векторы

Автор: Кирилл Долматов

В этой статье мы будем работать с векторами — одним из фундаментальных объектов линейной алгебры, который играет ключевую роль в анализе данных и машинном обучении.

Мы повторим основные понятия, связанные с векторами, но с акцентом на их применение для решения реальных задач в области обработки данных и обучения моделей. Также покажем, как работать с векторами в Python, используя такие библиотеки, как numpy и pandas.

А начнём мы с определения вектора.

Определение

Вектор — это математический объект, который в зависимости от области применения может иметь различные интерпретации и свойства.

Так векторы можно встретить:

  • в геометрии,
  • компьютерных науках,
  • линейной алгебре.

В геометрии

Геометрически вектор — это направленный отрезок, задаваемый начальной точкой и конечной точкой. Для вектора, заданного точками и , координаты вычисляются следующим образом:

Например, вектор, соединяющий точки и , имеет координаты .

Вектор

Вектор

В компьютерных науках

В программировании и компьютерной графике векторы используются для представления данных в виде упорядоченного списка чисел для последующих вычислений над ними.

Так, в машинном обучении наблюдение может быть представлено в виде вектора, состоящего из чисел, где каждое число соответствует значению соответствующего признака.

Аналогично в NLP (Natural Language Processing, обработка естественного языка) слова или части слов кодируются векторами, чтобы компьютер мог понять их семантику, а затем применить к ним математические операции.

Пример кодирования слов векторами

Пример кодирования слов векторами

В линейной алгебре

Алгебраическое определение вектора в некотором роде объединяет два определения выше, но описывает его более абстрактно. Чтобы с ним разобраться, необходимо изучить понятие векторного пространства.

Векторным пространством называется множество с операциями сложения и умножения на скаляр, удовлетворяющими определённым свойствам. И элементы этого множества называются векторами.

Говоря по-простому, векторное пространство состоит из двух частей:

  • множество элементов,
  • операции над этими элементами, удовлетворяющие заданным свойствам.

Примеры:

  • векторы-столбцы длины ;
  • многочлены степени не выше ;
  • непрерывные функции, определённые на отрезке ;
  • и так далее.

Нас в первую очередь будут интересовать именно векторы-столбцы. Как вы помните из курса школьной геометрии, точку на прямой можно задать с помощью одного числа . Множество всех таких точек есть — то есть вся числовая прямая.

Аналогично, чтобы задать точку на плоскости, нужна уже пара чисел , а множество всех таких пар есть плоскость. В трёхмерном пространстве всё описывается тремя числами , и мы получаем .

Продолжая увеличивать количество измерений, мы приходим к пространству — это обобщение на случай -измерений, и, чтобы задать точку, нам нужно указать координат. Таким образом, в -мерном пространстве вектор представляет собой упорядоченный набор чисел:

где каждое — это -я координата вектора.

Например: в двумерном пространстве вектор имеет координаты по оси и  по оси :

Представим эту запись на графике:

Вектор

Вектор

Примечание: Вектор можно записывать как вектор-столбец или как вектор-строку. Разницы между этими объектами нет, это, скорее, вопрос удобного формализма. Для согласованности мы по умолчанию будем считать, что все векторы — это именно векторы-столбцы. Перейти от вектора-столбца к вектору-строке можно с помощью операции транспонирования, которую мы разберём чуть позже.

Для разбора теоретических концептов нам удобнее смотреть на векторы именно с точки зрения алгебры, но в прикладных задачах мы чаще всего будем будем работать с векторами как упорядоченным набором чисел. Поэтому рассмотрим, как можно создавать векторы с использованием библиотеки numpy.

Представление векторов в Python

В NumPy вектора представлены в виде массивов, позволяющих эффективно выполнять математические операции.

import numpy as np

# Для создания вектора с заданными значениями
# используется функция `np.array()`
v = np.array([2, 5])  # array([2, 5])

# Также можно создавать специальные векторы.
# Например, вектор нулей заданного размера,
# используя функцию `np.zeros()`
zeros = np.zeros(3)  # array([0., 0., 0.])

# Или вектор с равномерным шагом (аналог функции range),
# используя функцию `np.arange()`
a = np.arange(0, 10, 2)  # array([0, 2, 4, 6, 8])

Есть много и других полезных функций и методов в этой библиотеке — о них мы поговорим позже.

Теперь, для полного представления о векторном пространстве, давайте разберём операции, которые мы можем выполнять над векторами, и свойства, которым должны удовлетворять эти операции.

Операции с векторами

Сложение

Для векторов и  сумма определяется как:

Свойства:

  • Коммутативность: .
  • Ассоциативность: .
  • Существование нулевого вектора: .
  • Существование противоположного вектора: .

Где:

Умножение на скаляр

Для вектора умножение на число (скаляр) определяется как:

Свойства умножения на скаляр:

  • .
  • .
  • .
  • .

Где

Свойства, приведённые выше для операций сложения и умножения, — ключевые в определении векторного пространства. Мы рассмотрели, как реализованы данные операции на векторах, которые отождествляются с , так как в каком-то смысле это самые полезные и наглядные объекты, удовлетворяющие определению вектора.

Далее мы будем рассматривать и другие объекты, которые также являются векторами, — многочлены, функции, матрицы, бесконечные последовательности. Важно, что все разумные свойства, к которым мы привыкли в , будут выполняться и для этих объектов тоже. Поэтому интуитивно всегда можно ориентироваться на  как на главный пример.

Векторы можно не только складывать и умножать на числа, но также, например, транспонировать или считать скалярное произведение между ними. Эти операции уже не участвуют в определении векторного пространства, однако могут быть очень полезны при практической работе с векторами.

Транспонирование

Для вектора операция транспонирования меняет форму записи: вектор представленный в виде столбца, преобразуется в вектор, представленный в виде строки, и наоборот.

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

Для векторов и , заданных в координатах, скалярное произведение — это операция, которая отображает пару векторов в скаляр и определяется как:

Свойства скалярного произведения:

  • и 

Скалярное произведение играет ключевую роль в машинном обучении, особенно в методах нахождения ближайших соседей и методах классификации, таких как метод опорных векторов (SVM).

Покажем, как выглядит скалярное произведение, на примере.

Предположим, что у нас есть два объекта с более сложными признаками:

  • Вектор признаков для объекта №1:

  • Вектор признаков для объекта №2:

Скалярное произведение этих двух векторов рассчитывается как:

Что это нам говорит? Поскольку скалярное произведение дало отрицательное значение, значит, векторы направлены в противоположные стороны в многомерном пространстве. В контексте, например, метода опорных векторов это может означать, что объекты, представленные этими векторами, принадлежат к разным классам.

Если бы скалярное произведение было положительным, это означало бы, что объекты, вероятно, принадлежат к одному классу (например, они оба «ближе» друг к другу в многомерном пространстве признаков).

Также со скалярным произведением тесно связаны следующие полезные определения:

  • Длина (норма) вектора может быть выражена как:

  • Косинусная мера для векторов и  — это нормированное скалярное произведение, которое показывает, насколько близки направления двух векторов независимо от их длин. Вычисляется как:

 — $\cos \theta=1$ , если векторы направлены в одну сторону;
 — $\cos \theta=0$ , если векторы `ортогональны` (перпендикулярны);
 — $\cos \theta=-1$ , если векторы направлены в противоположные стороны;

Где
.

Косинусная мера очень часто применяется в NLP-моделях для оценки близости слов. Сейчас покажем на примере.

Ранее мы упомянули, что в NLP-моделях слова (для простоты будем считать, что токен — это одно слово) кодируются векторами, которые отражают их семантические связи между собой.

Такие векторы часто называют эмбеддингами (англ. word embeddings). Пусть у нас есть два векторных представления слов:

  • Эмбеддинг слова «гитара»: .
  • Эмбеддинг слова «пианино»: .

Мы можем вычислить косинусную меру между этими векторами с помощью следующей формулы:

Сначала находим скалярное произведение этих векторов:

Теперь вычислим нормы этих векторов:

Теперь вычислим косинусную меру:

Это значение довольно близко к 1, что означает, что слова «гитара» и «пианино» схожи в семантическом смысле. Это подтверждается тем, что они часто встречаются в похожих контекстах, что делает их векторные представления близкими.

Ещё пример: в рекомендательных системах мы можем использовать косинусную меру для сравнения пользователей или товаров. Например, если два пользователя имеют похожие предпочтения, векторные представления таких пользователей будут схожи, и это отразится в высоком значении косинусной меры. Это поможет системе рекомендовать товары или фильмы, которые понравятся похожим пользователям.

Векторные представления пользователей

Векторные представления пользователей

Давайте рассмотрим применение операций с векторами в библиотеке numpy, которые там представлены в виде векторизованных массивов. Это ускоряет вычисления и позволяет эффективно работать с многомерными данными.

{​% cut «Операции с векторами в Python» %​}

Размер векторов может быть различен в зависимости от используемой модели. Например:

  • BERT — 768.
  • DeepSeek-V3 — 7 168.
  • ChatGPT-3 — 12 288.
  • Llama 3 — 16 384.

Давайте разберём несколько наглядных примеров с эмбеддингами намного меньшего размера, равного 5. Данные примеры также будут отражать суть семантической близости. Для этого будем выполнять операции сложения и вычитания векторов и оценивать косинусное сходство результирующего вектора.

import numpy as np

def cosine_similarity(vec1: np.array, vec2: np.array) -> float:
    """Вычисляет косинусную меру двух векторов."""
    return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

def evaulate_result(embeddings: np.array, result_embedding: np.array) -> None:
    """Вычисляет косинусное сходство результата с каждым словом в словаре."""
    print("Косинусное сходство результата с каждым словом:")
    for word, vec in embeddings.items():
		    print(f"{word}: {cosine_similarity(result_embedding, vec):.3f}")

# Пример 1: ebook ≈ book - pages + digital
embeddings = {
    "book":     np.array([0.5, 0.7, 0.6, 0.4, 0.3]),
    "pages":    np.array([0.2, 0.3, 0.1, 0.0, 0.2]),
    "digital":  np.array([0.1, 0.2, 0.4, 0.3, 0.4]),
    "ebook":    np.array([0.3, 0.6, 1.0, 0.7, 0.5]),
    "magazine": np.array([0.3, 0.5, 0.5, 0.2, 0.1])
}

result = embeddings["book"] - embeddings["pages"] + embeddings["digital"]
evaulate_result(embeddings, result)

# Output:
# Косинусное сходство результата с каждым словом:
# book: 0.951
# pages: 0.737
# digital: 0.953
# ebook: 0.996
# magazine: 0.921

В результате получаем, что .

Рассмотрим ещё один пример:

# Пример 2: hybrid ≈ motor - gasoline + electricity

embeddings = {
    "motor":       np.array([0.6, 0.7, 0.4, 0.2, 0.3]),
    "gasoline":    np.array([0.2, 0.3, 0.1, 0.0, 0.1]),
    "electricity": np.array([0.4, 0.5, 0.3, 0.4, 0.3]),
    "hybrid":      np.array([0.8, 0.9, 0.7, 0.6, 0.5]),
    "battery":     np.array([0.1, 0.4, 0.2, 0.5, 0.2])
}

result = embeddings["motor"] - embeddings["gasoline"] + embeddings["electricity"]
evaulate_result(embeddings, result)

# Output:
# Косинусное сходство результата с каждым словом:
# motor: 0.975
# gasoline: 0.896
# electricity: 0.995
# hybrid: 0.998
# battery: 0.873


В результате получаем, что .

И, наконец, последний пример:

# Пример 3:  profit ≈ investment - risk + opportunity

embeddings = {
    "investment":   np.array([0.7, 0.8, 0.6, 0.7, 0.5]),
    "risk":         np.array([0.3, 0.4, 0.2, 0.2, 0.3]),
    "opportunity":  np.array([0.5, 0.6, 0.4, 0.5, 0.6]),
    "profit":       np.array([0.9, 0.9 , 0.8, 1. , 0.8]),
    "loss":         np.array([-0.6, -0.7, -0.5, -0.6, -0.4])
}

result = embeddings["investment"] - embeddings["risk"] + embeddings["opportunity"]
evaulate_result(embeddings, result)

# Output:
# Косинусное сходство результата с каждым словом:
# investment: 0.997
# risk: 0.969
# opportunity: 0.989
# profit: 0.999
# loss: -0.995


В результате получаем, что .

Существуют и другие интересные применения векторных операций над эмбеддингами. То есть кодировать векторами можно не только тексты, но и другую информацию. Так, в компьютерном зрении используют векторы изображений (англ. image embeddings), полученные, например, из промежуточных слоёв свёрточных нейронных сетей, чтобы описывать изображения для классификации, поиска или кластеризации.

Изучив векторы и базовые операции над ними, мы можем исследовать их взаимосвязи через понятие линейной зависимости. Оно поможет нам определить, насколько один набор векторов достаточен для описания всего пространства.

Линейная зависимость

Пусть — векторное пространство над . Тогда мы можем взять некоторые элементы этого пространства (векторы) и применить к ним операции сложения и умножения, описанные выше. В результате получим новый вектор, который называется линейной комбинацией:

Линейная комбинация называется тривиальной, если все , в противном случае она нетривиальная.

  • Векторы называются линейно зависимыми, если существует нетривиальная линейная комбинация этих векторов, равная нулевому вектору. То есть — линейно зависимы , если существуют , такие, что хотя бы один из  не равен нулю и  .
  • Если никакая нетривиальная комбинация не может дать ноль, то векторы линейно независимы .

Примеры

  1. Рассмотрим , и пусть:

Тогда векторы:
— — линейно независимы;
— — линейно независимы;
— — линейно зависимы ( );
— — линейно зависимы ( ).
2. Один вектор линейно зависим тогда и только тогда, когда он равен нулю.
3. Два вектора линейно зависимы тогда и только тогда, когда они пропорциональны, то есть , где .

С точки зрения анализа данных, проверить линейную зависимость признаков в датасете — значит понять, нет ли там избыточной информации (коллинеарности). Если один признак почти пропорционален другому, это может вызывать проблемы в обучении регрессий и нейронных сетей, а также приводить к переобучению. Как вы думаете почему?

Ответ (не открывайте сразу, сначала подумайте сами!

Нестабильность оценок коэффициентов. В линейной регрессии матрица признаков становится почти вырождённой, и коэффициенты модели могут приобретать очень большие значения, сильно реагировать на малейшие изменения в данных, что снижает их интерпретируемость и надёжность.
Переобучение. Избыточная информация в виде повторяющихся (почти одинаковых) признаков увеличивает сложность модели без добавления новых сведений. Модель может начать подгонять шум в тренировочных данных, что приводит к ухудшению обобщающей способности на новых данных.

После того как мы подробно рассмотрели векторы, освоили базовые операции над ними и исследовали понятие линейной зависимости, следующим логическим шагом будет ввести понятие базиса.

Базис позволяет описывать любое векторное пространство с помощью минимального набора линейно независимых векторов, обеспечивая таким образом удобные способы представления данных и решений в выбранном пространстве.

Базис

Базис векторного пространства — это система линейно независимых векторов , которые порождают всё пространство . Это означает, что любой вектор можно представить в виде линейной комбинации базисных векторов:

где — координаты вектора в выбранном базисе.

Рисунок 4.2.5: Канонический базис

Канонический базис в 

Свойства базиса:

  • Всякое векторное пространство обладает базисом.
  • Любой вектор в  единственным образом представляется через базис.
  • Любые два базиса содержат одно и то же число векторов.

Примеры:

  • В  : стандартный базис

  • В  : стандартный базис

Примечание

Смысл базиса заключается в том, что после его выбора можно отождествить с . То есть, если , тогда ему соответствует единственный столбец:

Таким образом, про любое векторное пространство, когда это необходимо, можно думать как просто про .

Выбор базиса очень важен при работе с данными — например, методы снижения размерности (PCA и другие) фактически ищут «хороший» базис, в котором данные выглядят проще (часто это значит, что большинство координат становятся близкими к нулю).

Последнее, о чём поговорим в этой статье, — как раз о размерности.

Размерность

Размерность векторного пространства — это число векторов в базисе этого пространства. Обозначается как . Размерность показывает минимальное число векторов, достаточное для порождения пространства. Говоря по-простому, — это величина, показывающая, насколько векторное пространство большое, она характеризует «количество степеней свободы» в пространстве.

Примеры:

  • В  : размерность равна .
  • В пространстве всех многочленов степени : размерность равна (по числу коэффициентов многочлена).

Примечание

В контексте анализа данных размерность отражает, сколько координат нужно, чтобы описать объекты. А если признак вносит мало информации, иногда его можно исключить или заменить, уменьшая размерность и сохраняя достаточную полноту описания.


Итак, векторы — это не просто набор чисел, а мощное средство для описания и преобразования данных. Именно через векторы мы представляем наборы признаков, вычисляем расстояния и ищем оптимальные решения.

В следующих статьях мы углубимся в тему линейных преобразований и посмотрим, как матричная форма записей упрощает и ускоряет многие вычислительные задачи. Это позволит нам перейти к рассмотрению методов решения систем линейных уравнений — ключевого инструмента в моделировании и оптимизации.