Содержание
  1. Что уменьшается и что означает точка на карте
  2. n_neighbors задаёт масштаб соседства, min_dist — плотность укладки
  3. Сначала выбрать признаки, масштабирование и метрику
  4. Полный датасет и четыре настройки без выдуманной картинки
  5. Проверить соседей в исходном пространстве и проекции
  6. Ограничения расстояний, плотности, кластеров и случайного seed
  7. Отдельно про transform новых данных и границы переноса CPU/GPU
  8. Частые вопросы
Справочник

Что такое UMAP: как читать карту многомерных данных

13 ноября 2026 · 19 минут чтения

Что такое UMAP: как читать карту многомерных данных — это разбор метода снижения размерности, который строит плоскую карту из таблицы со многими признаками. Точка на карте — один объект выборки, а её положение отражает соседство с другими объектами. Расстояния и островки требуют проверки в исходных данных.

Что уменьшается и что означает точка на карте

UMAP расшифровывается как Uniform Manifold Approximation and Projection. В документации проекта метод назван алгоритмом обучения на многообразии общего назначения и снижения размерности, совместимым со scikit-learn: он использует тот же API и встраивается в конвейеры sklearn. В репозитории проекта указаны три допущения о данных: они равномерно распределены на римановом многообразии, риманова метрика локально постоянна, многообразие локально связно. Из этих допущений строится нечёткая топологическая модель, а укладка ищется как низкоразмерная проекция с максимально близкой структурой.

Практический смысл: у вас есть таблица, где каждая строка — объект, а столбцы — признаки. Метод превращает строку из многих чисел в точку с двумя координатами, если оставить значение по умолчанию. В документации проекта на примере набора о пингвинах показано, что после fit_transform получается массив из 333 строк и двух столбцов вместо четырёх исходных признаков. Каждая строка такого массива — двумерное представление соответствующего пингвина, и его можно нарисовать обычной диаграммой рассеяния, раскрасив по известному признаку.

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

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

Отсюда первое практическое правило чтения: карта отвечает на вопрос «кто с кем рядом в многомерном пространстве», и не отвечает на вопрос «сколько здесь классов». Число видимых островков зависит от настроек, которые вы задали, и от того, как алгоритм разложил соседства. Документация проекта описывает это на примере рукописных цифр: часть классов сливается, часть объектов выталкивается в отдельные группы. Островок на карте даёт повод посмотреть исходные объекты. Число групп требует самостоятельной проверки.

Второе правило: оси карты не имеют единиц измерения. По осям нет ни рублей, ни километров, ни лет. Координаты — условные числа, которые алгоритм подобрал так, чтобы сохранить структуру соседства. Поэтому вопрос «на сколько единиц объект А дальше объекта Б» на карте UMAP не имеет содержательного ответа в терминах исходных признаков.

Третье правило: карта строится по всем объектам сразу. В документации проекта на примере digits показано, что после обучения объект-редьюсер хранит укладку в атрибуте embedding_, и вызов transform на тех же данных возвращает те же координаты. Итоговая карта отражает совместную укладку всей обучающей выборки.

n_neighbors задаёт масштаб соседства, min_dist — плотность укладки

Два параметра определяют вид карты сильнее всего. В документации проекта n_neighbors описан как число соседних точек, используемых в локальных приближениях структуры многообразия. Большие значения приводят к сохранению более глобальной структуры за счёт детальной локальной. В репозитории проекта указан рабочий диапазон от 5 до 50, а значение от 10 до 15 названо разумным по умолчанию. Там же отмечено: с ростом n_neighbors всё больше внимания уделяется общей структуре данных.

min_dist в документации проекта описан как параметр, который управляет тем, насколько плотно укладке разрешено сжимать точки. Большие значения распределяют точки равномернее, меньшие позволяют точнее оптимизировать локальную структуру. В репозитории проекта назван диапазон от 0.001 до 0.5 со значением 0.1 как разумным по умолчанию.

Разделение ролей удобно держать в голове так:

Параметр Что задаёт Малые значения Большие значения
n_neighbors масштаб соседства, который алгоритм считает локальным карта дробится на мелкие группы, видна локальная фактура карта показывает общий контур, локальные детали сглаживаются
min_dist плотность укладки точек в проекции точки слипаются в компактные сгустки точки распределяются равномернее, сгустки разрыхляются
n_components число координат в проекции одна или две координаты для просмотра больше координат для дальнейших задач
metric способ измерения расстояния в исходном пространстве зависит от выбранной метрики зависит от выбранной метрики

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

Метрика задаёт способ измерения расстояния в исходном пространстве. В документации проекта сказано, что поддерживаются пользовательские метрики при условии, что они компилируются numba в режиме nopython. В репозитории проекта отмечено, что поддерживаются неметрические функции расстояния, включая косинусное расстояние и корреляционное расстояние, и что это позволяет корректно встраивать векторные представления слов.

Практический порядок подбора: начните с n_neighbors около 15 и min_dist около 0.1, постройте карту, затем увеличьте n_neighbors и посмотрите, сохраняется ли интересующая вас группа. Если группа рассыпается при росте соседства, она держалась на очень локальной структуре. Если группа сохраняется, структура устойчивее. Отдельно меняйте min_dist: он влияет на укладку точек. После изменения перепроверьте соседей в проекции.

В интерактивной статье Google PAIR описан механизм выбора радиуса: UMAP выбирает радиус локально, опираясь на расстояние до n-го ближайшего соседа точки. Там же отмечено, что выбор радиуса критичен: слишком малый радиус даёт мелкие изолированные группы, слишком большой соединяет всё вместе. Это объясняет, почему n_neighbors меняет масштаб карты: он управляет тем, какой радиус считается локальным.

Сначала выбрать признаки, масштабирование и метрику

Порядок подготовки важнее подбора параметров укладки. В документации проекта на примере пингвинов показана последовательность: взять только столбцы измерений, привести признаки к z-оценкам через StandardScaler, затем обучить редьюсер. Причина названа прямо: измерения находятся в совершенно разных масштабах, и приведение к числу стандартных отклонений от среднего делает их сопоставимыми.

Шаги подготовки выглядят так.

  1. Определите задачу. Просмотр структуры выборки требует одних признаков, подготовка к кластеризации — других. Признаки, которые вы включите, задают пространство, в котором считается соседство.
  2. Уберите пропуски и служебные столбцы. В документации проекта на примере пингвинов строки с пропусками удалены, а столбец года исключён из признакового набора.
  3. Приведите признаки к сопоставимому масштабу. Стандартизация через StandardScaler — рабочий вариант, показанный в документации проекта.
  4. Выберите метрику под смысл признаков. Евклидово расстояние подходит для сопоставимых непрерывных величин. Косинусное и корреляционное расстояние применяют к векторным представлениям, где важнее направление, чем длина.
  5. Зафиксируйте random_state, если нужна воспроизводимость.
  6. Постройте карту и проверьте соседства в исходном пространстве.

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

Отдельно про выбросы. Один объект с экстремальными значениями может стать отдельной точкой на карте. Это не обязательно ошибка: в документации проекта на примере digits отдельные группы объектов объясняются их видом. Проверяйте такие точки по исходным данным.

Отдельно про число признаков. В документации проекта на примере digits отмечено, что 64 измерения избыточны для задачи, и разумно ожидать меньшего числа скрытых признаков, достаточных для описания данных. Матрица диаграмм рассеяния по первым десяти измерениям оказывается недостаточной для этого набора. UMAP применяют именно потому, что попарный просмотр признаков перестаёт работать при росте их числа.

Полный датасет и четыре настройки без выдуманной картинки

Ниже — учебный пример, который создаёт двенадцать четырёхмерных точек, масштабирует их, строит четыре карты с разными настройками и печатает долю сохранённых соседей для каждой карты. Точки образуют две группы по шесть: первая группа задана как [i/10, i/10, 0, 0], вторая — как [3 + i/10, 3 − i/10, 1, 1], где i пробегает значения от 0 до 5. Цвета на картах означают происхождение учебных точек. Это условный вход примера. Найденные алгоритмом классы здесь не заданы.

PYTHON38 строк
# Учебный воспроизводимый пример. Редакция не запускала UMAP на этом наборе.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import NearestNeighbors
from umap import UMAP

X = np.array([[i / 10, i / 10, 0, 0] for i in range(6)] +
             [[3 + i / 10, 3 - i / 10, 1, 1] for i in range(6)])
X = StandardScaler().fit_transform(X)
colors = [0] * 6 + [1] * 6  # происхождение точек, не результат кластеризации

def neighbors(array, k=3):
    indices = NearestNeighbors(n_neighbors=k + 1).fit(array).kneighbors(
        array, return_distance=False)
    return [set(int(j) for j in row if j != i) for i, row in enumerate(indices)]

original = neighbors(X)
print({"original_neighbors@3": [sorted(ids) for ids in original]})  # Индексы соседей в исходном пространстве.
fig, axes = plt.subplots(2, 2, figsize=(9, 8))
embeddings = []
for ax, (n, d) in zip(axes.flat, [(3, .1), (3, .8), (5, .1), (5, .8)]):
    Y = UMAP(n_neighbors=n, min_dist=d, metric="euclidean",
             random_state=42).fit_transform(X)
    projected = neighbors(Y)
    print({"projected_neighbors@3": [sorted(ids) for ids in projected]})  # Индексы соседей на текущей карте.
    retained = sum(len(a & z) / 3 for a, z in zip(original, projected)) / len(X)
    print({"n_neighbors": n, "min_dist": d, "neighbor_retention@3": retained})
    ax.scatter(Y[:, 0], Y[:, 1], c=colors)
    ax.set_title(f"neighbors={n}, min_dist={d}")
    embeddings.append(Y)
low = np.min(np.vstack(embeddings), axis=0)
high = np.max(np.vstack(embeddings), axis=0)
for ax in axes.flat:
    ax.set_xlim(low[0] - 1, high[0] + 1)
    ax.set_ylim(low[1] - 1, high[1] + 1)
fig.tight_layout()
fig.savefig("umap_comparison.png")

Четыре настройки в примере: (n_neighbors, min_dist) равны (3, 0.1), (3, 0.8), (5, 0.1) и (5, 0.8). Значение random_state=42 фиксирует случайность, чтобы повторный запуск дал тот же результат. Метрика задана евклидовой.

Что делает пример по шагам. Сначала создаётся массив из двенадцати строк и четырёх столбцов. Затем StandardScaler приводит столбцы к сопоставимому масштабу. Функция neighbors считает три ближайших соседа для каждой точки в исходном пространстве и возвращает множества индексов без самой точки. Затем цикл строит четыре карты, для каждой считает три ближайших соседа уже в проекции и вычисляет долю соседей, сохранившихся из исходного набора. Результат печатается словарём с ключами n_neighbors, min_dist и neighbor_retention@3. Четыре карты рисуются в общей сетке с одинаковым масштабом осей, чтобы их можно было сравнивать визуально.

Что менять под себя. Замените массив X на свою таблицу признаков, приведённую к числовому виду. Замените список настроек в цикле на те значения, которые хотите сравнить. Замените metric на подходящую вашему смыслу признаков. Замените random_state на любое целое число, если нужна другая фиксация случайности. При изменении k одновременно обновите знаменатель 3 и имя метрики neighbor_retention@3, чтобы они соответствовали новому числу соседей.

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

Проверить соседей в исходном пространстве и проекции

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

Ручная проверка выглядит так.

  1. Возьмите точку, которая на карте стоит отдельно или на границе группы.
  2. Найдите её ближайших соседей в исходной таблице по выбранной метрике.
  3. Найдите её ближайших соседей на карте.
  4. Сравните два списка. Совпадения подтверждают, что карта отражает исходное соседство для этой точки. Расхождения показывают, где проекция переставила связи.
  5. Повторите для нескольких точек из разных областей карты.

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

Что проверять в первую очередь:

Что смотреть Как проверить Что это значит
Отдельная точка вдали от всех найти её соседей в исходных данных объект может быть выбросом или редким случаем
Плотный сгусток посмотреть несколько объектов из него сгусток может быть реальной группой похожих объектов
Мост между двумя группами найти объекты в области моста часть объектов имеет признаки обеих групп
Разрыв внутри одной метки сравнить объекты по обе стороны разрыва метка объединяет разные по признакам объекты
Совпадение метки и группы посчитать долю объектов метки внутри группы метка согласуется со структурой признаков

Отдельно про устойчивость. Постройте карту с другим random_state и сравните расположение интересующей группы. Если группа сохраняется при смене seed, она опирается на устойчивую структуру. Если рассыпается, вывод о группе держится на случайности укладки. В документации проекта отмечено, что UMAP — стохастический алгоритм: случайность используется и для ускорения приближений, и для решения сложных задач оптимизации, поэтому разные запуски могут давать разные результаты. Там же сказано, что алгоритм относительно стабилен и разброс между запусками обычно невелик, но различия всё же возможны.

Ограничения расстояний, плотности, кластеров и случайного seed

Четыре ограничения определяют, что карта может и чего не может.

Расстояния между далёкими точками. Координаты на карте подбираются так, чтобы сохранить структуру соседства. Глобальные расстояния между далёкими группами не сохраняются как величины исходного пространства. Документация проекта на примере digits показывает, что часть классов выталкивается в отдельные области, а часть сливается. Из этого следует практическое правило: судить о близости объектов внутри группы можно, о расстоянии между группами — нельзя.

Плотность точек. min_dist управляет плотностью укладки, поэтому плотность сгустка на карте отражает настройку и структуру соседства вместе. Для сохранения информации о локальной плотности в репозитории проекта описан densMAP: он дополняет UMAP сохранением локальной плотности. Там же указано, что densMAP наследует все параметры UMAP и добавляет свои, включая dens_frac со значением по умолчанию 0.3, dens_lambda со значением по умолчанию 2.0 и dens_var_shift, для которого рекомендуется 0.1. Для надёжной оценки локальной плотности в репозитории проекта рекомендуются большие значения n_neighbors, например 30.

Число кластеров. Алгоритм не выдаёт число групп. Он выдаёт координаты. Число видимых островков зависит от n_neighbors, min_dist и структуры данных. В интерактивной статье Google PAIR отмечено, что случайный шум не всегда выглядит случайным: на карте могут появляться группы, которых нет в исходных данных как отдельных классов. Это прямое предупреждение против подсчёта островков как числа классов.

Случайный seed. В документации проекта сказано, что UMAP — стохастический алгоритм, и для точного воспроизведения результата пользователь задаёт seed. Для исходного совместимого оптимизатора фиксированный random_state ограничивает многопоточность ради точной воспроизводимости. Новые оптимизаторы Adam и momentum накапливают обновления так, что параллельная оптимизация укладки остаётся детерминированной, и фиксированный random_state перестаёт вынуждать однопоточную работу. Adam назван рекомендуемым выбором. При этом смена оптимизатора меняет укладку, поэтому координаты от разных оптимизаторов совпадать не обязаны.

Про воспроизводимость между версиями. В документации проекта указано, что совместимая укладка воспроизводит результаты между релизами: при одинаковых данных, параметрах и random_state запуск с compatibility_layout=True в версии 0.6 даёт ту же укладку, что и финальная линия 0.5.x, при условии совпадения платформы и версий зависимостей, включая Numba, NumPy, библиотеку BLAS, SciPy, scikit-learn и PyNNDescent. Модели, обученные и сохранённые в 0.5.x, загружаются в 0.6 и продолжают использовать совместимый конвейер при transform и обновлении.

Про GPU-реализации. Документация NVIDIA cuML описывает собственную реализацию UMAP с методами fit и transform. Там же сказано, что установка random_state даёт воспроизводимые укладки ценой более медленного обучения и повышенного расхода памяти, а явное указание build_algo='nn_descent' ломает воспроизводимость, поскольку NN Descent строит недетерминированные графы ближайших соседей. Эти утверждения относятся к cuML. Переносить их на umap-learn нельзя: это разные реализации с разными параметрами и разными гарантиями.

Отдельно про transform новых данных и границы переноса CPU/GPU

transform добавляет новые точки в уже построенную укладку. В документации проекта показано, что после fit укладка доступна в атрибуте embedding_, а вызов transform на тех же данных возвращает те же координаты. В репозитории проекта отмечено, что поддержка добавления новых точек в существующую укладку через стандартный метод transform позволяет использовать UMAP как преобразователь в конвейерах sklearn.

Порядок работы с новыми данными:

  1. Обучите редьюсер на обучающей выборке и сохраните объект.
  2. Приведите новые данные к тому же масштабу, что и обучающие. Для этого используйте преобразователь, обученный на обучающей выборке.
  3. Вызовите transform на новых данных. Координаты будут вычислены в уже построенной укладке.
  4. Проверьте, куда попали новые точки. Если они оказались вдали от всех групп, это может означать, что их признаки отличаются от обучающей выборки.

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

Границы переноса между реализациями. umap-learn и GPU-реализация от NVIDIA — разные продукты с разными API и разными параметрами. Документация cuML описывает свои методы fit и transform и свои параметры, включая build_algo. Репозиторий umap-learn описывает свои параметры, включая n_neighbors, min_dist, metric, n_components, random_state и compatibility_layout. Настройки одной реализации не переносятся в другую как есть. Утверждения о воспроизводимости, стоимости фиксации seed и поведении графов соседей относятся к той реализации, в документации которой они приведены.

Про GPU-ускорение в экосистеме umap-learn. В репозитории проекта упоминается torchdr — реализация на PyTorch, которая ускоряет вычисления на GPU, включая поиск ближайших соседей, построение матрицы сродства и оптимизацию укладки. Там же приведён пример создания объекта с параметрами n_neighbors=15, min_dist=0.1, n_components=2 и device='cuda'. Это отдельный продукт со своей документацией.

Про установку. В репозитории проекта перечислены требования: Python 3.10 или выше, numpy 2.0 или выше, scipy 1.13 или выше, scikit-learn 1.6 или выше, numba 0.60 или выше, tqdm и pynndescent 0.7 или выше. Для установки через conda указана команда conda install -c conda-forge umap-learn, через pip — pip install umap-learn. Для функций построения графиков указан вариант pip install umap-learn[plot]. В репозитории проекта отмечено, что с compatibility_layout=False UMAP автоматически использует RINND для наборов от 4096 образцов, когда эта библиотека установлена и совместима с входными данными, а параметр nearest_neighbor_backend позволяет выбрать бэкенд явно. Совместимая укладка всегда использует PyNNDescent.

Про производительность. В репозитории проекта приведены примеры: для набора MNIST из 70000 образцов размерности 784 укладка занимает менее минуты, а реализация t-SNE из scikit-learn на той же задаче требует около 45 минут. Там же указано, что при установленном pynndescent вычисления идут быстрее, особенно на многоядерных машинах. Эти числа относятся к описанной конфигурации и не переносятся на другие наборы и другое железо.

Частые вопросы

Чем UMAP отличается от PCA?

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

Как выбрать n_neighbors и min_dist?

Начните со значений около 15 для n_neighbors и около 0.1 для min_dist. В репозитории проекта для n_neighbors назван диапазон от 5 до 50 со значением 10–15 как разумным по умолчанию, для min_dist — диапазон от 0.001 до 0.5 со значением 0.1. Затем меняйте параметры по одному и смотрите, сохраняется ли интересующая вас группа.

Почему карта меняется при каждом запуске?

UMAP — стохастический алгоритм: случайность используется для ускорения приближений и для решения задач оптимизации. В документации проекта сказано, что разные запуски могут давать разные результаты, а для точного воспроизведения задаётся seed. Зафиксируйте random_state, и повторный запуск на тех же данных с теми же параметрами даст те же координаты.

Можно ли переносить настройки cuML на umap-learn?

Настройки и гарантии одной реализации относятся к ней самой. Документация cuML описывает свои параметры, включая build_algo, и свои утверждения о воспроизводимости. Репозиторий umap-learn описывает свои параметры, включая compatibility_layout и nearest_neighbor_backend. Переносите только те параметры, которые описаны в документации используемой вами библиотеки.

Что делать, если на карте появились группы, которых нет в данных?

Проверьте соседей этих точек в исходном пространстве. В интерактивной статье Google PAIR отмечено, что случайный шум не всегда выглядит случайным, поэтому группы на карте могут не соответствовать отдельным классам в данных. Сравните объекты внутри группы по исходным признакам и посмотрите, что их объединяет. Если объединение не подтверждается, измените n_neighbors и проверьте устойчивость группы при другом seed.

Читайте также

3 материала