Ближайшие соседи по многомерным данным? - PullRequest
148 голосов
/ 22 апреля 2011

Я задал вопрос несколько дней назад о том, как найти ближайших соседей для данного вектора. Мой вектор теперь 21 измерения, и прежде чем я продолжу дальше, потому что я не из области машинного обучения или математики, я начинаю задавать себе некоторые фундаментальные вопросы:

  • Является ли евклидово расстояние хорошей метрикой для поиска ближайших соседей? Если нет, то какие у меня варианты?
  • Кроме того, как можно определить правильный порог для определения k-соседей? Можно ли провести анализ, чтобы выяснить это значение?
  • Ранее мне предлагалось использовать kd-Trees, но на странице Википедии четко сказано, что для больших размеров kd-Tree почти эквивалентно поиску методом грубой силы. В таком случае, как лучше всего найти ближайших соседей в наборе данных на миллион точек?

Может кто-нибудь уточнить некоторые (или все) из приведенных выше вопросов?

Ответы [ 14 ]

169 голосов
/ 25 апреля 2011

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

Вас может заинтересовать Приблизительный ближайший сосед ( ANN ) алгоритмы.Идея состоит в том, что вы позволяете алгоритму возвращать достаточно вблизи соседей (возможно, не ближайшего соседа);тем самым вы уменьшаете сложность.Вы упомянули дерево kd ;это один пример.Но, как вы сказали, kd-tree плохо работает в больших измерениях.Фактически, все современные методы индексации (основанные на разделении пространства) превращаются в линейный поиск для достаточно больших измерений [1] [2] [3].

Среди ANN Алгоритмы, предложенные недавно, возможно, наиболее популярными являются Локально-чувствительное хеширование ( LSH ), которое отображает набор точек в многомерном пространстве в набор бинов, т.е.хеш-таблица [1] [3].Но в отличие от традиционных хэшей, чувствительные к локальности места хешей рядом указывают в одну и ту же корзину.

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

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

Наконец, LSH совместим с любой нормой Lp для 0 < p <= 2.Поэтому, чтобы ответить на ваш первый вопрос, вы можете использовать LSH с евклидовой метрикой расстояния, или вы можете использовать ее с метрикой расстояния Манхэттена (L1).Существуют также варианты расстояния Хэмминга и сходства косинусов.

Достойный обзор был написан Малкольмом Слэни и Майклом Кейси для журнала IEEE Signal Processing в 2008 году [4].

LSH было применено, казалось бы, повсюду.Возможно, вы захотите попробовать.


[1] Datar, Indyk, Immorlica, Mirrokni, "Схема хеширования с учетом локальных особенностей, основанная на p-стабильных распределениях", 2004.

[2] Вебер, Шек, Блотт, «Количественный анализ и исследование производительности для методов поиска сходства в многомерных пространствах», 1998.

[3] Гионис, Индик, Мотвани, «Поиск сходства вбольшие размеры с помощью хеширования, "1999.

[4] Слэни, Кейси," Хеширование с учетом локальных особенностей для поиска ближайших соседей ", 2008.

75 голосов
/ 24 апреля 2011

I. Метрика расстояния

Во-первых, количество объектов (столбцов) в наборе данных не является фактором при выборе метрики расстояния для использования в kNN. Есть довольно много опубликованных исследований, направленных именно на этот вопрос, и обычные основы для сравнения:

  • базовый статистический распространение ваших данных;

  • связь между функциями которые составляют ваши данные (являются ли они независимый - то есть, что делает ковариационная матрица выглядит так); и

  • координатное пространство, из которого ваш данные получены.

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

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

Это провалилось для меня всего несколько раз, в каждом из этих случаев евклидово расстояние не удавалось, потому что базовая (декартова) система координат была плохим выбором. И вы обычно узнаете это, потому что, например, длины пути (расстояния) больше не являются аддитивными - например, когда метрическое пространство является шахматной доской, манхэттенское расстояние лучше, чем евклидово, аналогично, когда метрическое пространство является Землей, а ваши расстояния транс -континентальные рейсы, метрика расстояния, подходящая для полярной системы координат, является хорошей идеей (например, от Лондона до Вены - 2,5 часа, от Вены до Санкт-Петербурга - еще 3 часа, более или менее в том же направлении, но от Лондона до Санкт-Петербурга Петербург не 5,5 часов, а чуть более 3 часов.

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

Одно важное условие: чтобы расчеты расстояния были значимыми, вы должны изменить масштаб ваших данных - редко можно построить модель kNN для генерации точных прогнозов без делая это. Например, если вы строите модель kNN для прогнозирования спортивных результатов, а вашими переменными ожидания являются рост (см), вес (кг), жировые отложения (%) и пульс покоя (ударов в минуту), тогда типичная точка данных может выглядеть примерно так: [180.4, 66.1, 11.3, 71]. Очевидно, что при расчете расстояния будет доминировать рост, а вклад% жира в организме будет практически незначительным. Иными словами, если вместо этого данные были представлены по-другому, так что вес тела был в граммах, а не в килограммах, тогда исходное значение 86,1 было бы 86,100, что сильно повлияло бы на ваши результаты, а это именно то, что вы делаете. не хочу Вероятно, наиболее распространенным методом масштабирования является вычитание среднего значения и деление на стандартное отклонение (среднее значение и относительное значение sd рассчитываются отдельно для каждого столбца или функции в этом наборе данных; X относится к отдельной записи / ячейке в строке данных):

X_new = (X_old - mu) / sigma


II. Структура данных

Если вас беспокоит производительность структуры дерева kd, A Тесселяция Вороного является концептуально простым контейнером, но он значительно улучшит производительность и масштабируется лучше, чем kd-Trees.

dat

Это не самый распространенный способ сохранения данных обучения kNN, хотя применение VT для этой цели, а также вытекающие из этого преимущества производительности хорошо документированы (см., Например, Отчет Microsoft Research ). Практическая значимость этого заключается в том, что, если вы используете «основной» язык (например, в TIOBE Index ), то вы должны найти библиотеку для выполнения VT. Я знаю, что в Python и R есть несколько вариантов для каждого языка (например, пакет voronoi для R доступен на CRAN )

Использование VT для kNN работает так:

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

Как выбрать центры Вороного? Я использую два ортогональных руководства. После случайного выбора точек w, рассчитайте VT для ваших тренировочных данных. Затем проверьте количество точек данных, назначенных каждому центру Вороного - эти значения должны быть примерно одинаковыми (с учетом равномерной плотности точек по всему пространству данных). В двух измерениях это приведет к VT с тайлами одинакового размера. Это первое правило, вот второе. Выберите w с помощью итерации - запустите алгоритм kNN с параметром w в качестве переменного параметра и измерьте производительность (время, необходимое для возврата прогноза путем запроса VT).

Итак, представьте, что у вас есть миллион точек данных ..... Если бы точки были сохранены в обычной 2D-структуре данных или в kd-дереве, вы бы выполнили в среднем пару миллионов вычислений расстояния для каждой новые точки данных, чью переменную ответа вы хотите предсказать. Конечно, эти расчеты выполняются на одном наборе данных. С помощью V / T поиск ближайшего соседа выполняется в два этапа один за другим по двум различным группам данных - сначала по центрам Вороного, затем, как только ближайший центр найден, точки внутри ячейки, соответствующие этот центр ищется, чтобы найти фактического ближайшего соседа (путем последовательных вычислений расстояния). В совокупности эти два поиска выполняются намного быстрее, чем один поиск методом "грубой силы". Это легко увидеть: предположим, что для 1М точек данных вы выбираете 250 центров Вороного, чтобы тесселяровать пространство данных. В среднем каждая ячейка Вороного будет иметь 4000 точек данных. Таким образом, вместо выполнения в среднем 500 000 вычислений расстояния (грубой силы), вы выполняете намного меньше, в среднем всего 125 + 2000.

III. Расчет результата (прогнозируемая переменная ответа)

Существует два шага для расчета прогнозируемого значения из набора обучающих данных kNN. Первый - это n или количество ближайших соседей , которые будут использоваться для этого расчета. Второй как взвесить их вклад в прогнозируемое значение.

W / r / t первого компонента, вы можете определить наилучшее значение n, решив задачу оптимизации (очень похоже на оптимизацию методом наименьших квадратов). Это теория; на практике большинство людей просто используют n = 3. В любом случае, просто запустить алгоритм kNN для набора тестовых экземпляров (для расчета прогнозируемых значений) для n = 1, n = 2, n = 3 и т. Д. И отобразить ошибку как функцию от n. Если вы просто хотите получить правдоподобное значение для n, чтобы снова начать, просто используйте n = 3.

Второй компонент - как взвешивать вклад каждого из соседей (при условии, что n> 1).

Самым простым методом взвешивания является просто умножение каждого соседа на весовой коэффициент, который составляет всего 1 / (dist * K), или обратное расстояние от этого соседа до тестового экземпляра, часто умноженное на некоторую эмпирически выведенную константу,К. Я не фанат этой техники, потому что она часто перевешивает ближайших соседей (и, соответственно, перевешивает более отдаленных);значение этого в том, что данный прогноз может почти полностью зависеть от одного соседа, что, в свою очередь, увеличивает чувствительность алгоритма к шуму.

Должна лучше взвешивать функцию, которая существенно избегает этого ограничения. Гауссовская функция , которая в python выглядит следующим образом:

def weight_gauss(dist, sig=2.0) :
    return math.e**(-dist**2/(2*sig**2))

Чтобы вычислить прогнозируемое значение, используя ваш код kNN, вы должны определить n ближайших соседей к даннымУкажите точку, ответную переменную которой вы хотите предсказать («тестовый экземпляр»), затем вызовите функцию weight_gauss, один раз для каждого из n соседей, передавая расстояние между каждым соседом контрольной точки. Эта функция будет возвращать вес для каждого соседа, который затем используется в качестве коэффициента этого соседа в средневзвешенном расчете.

16 голосов
/ 22 апреля 2011

То, с чем вы сталкиваетесь, известно как проклятие размерности . Иногда полезно запустить такой алгоритм, как PCA или ICA , чтобы убедиться, что вам действительно нужны все 21 измерение и, возможно, найти линейное преобразование, которое позволит вам использовать менее 21 с примерно таким же качеством результата.

Обновление: Я столкнулся с ними в книге под названием «Обработка биомедицинских сигналов» Рангаяна (надеюсь, я правильно ее помню). ICA не является тривиальным методом, но он был разработан исследователями в Финляндии, и я думаю, что код Matlab для него доступен для скачивания. PCA - более широко используемый метод, и я считаю, что вы должны быть в состоянии найти его R или другая программная реализация. PCA выполняется путем итерационного решения линейных уравнений. Я сделал это слишком давно, чтобы вспомнить как. =)

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

9 голосов
/ 15 июля 2016

Лучшие ответы хорошие, но старые, поэтому я хотел бы добавить 2016 ответ .


Как уже говорилось, в многомерном пространстве проклятие размерности скрывается за углом, что делает традиционные подходы, такие как популярное дерево k-d, такими же медленными, как и метод грубой силы. В результате мы обращаем наш интерес к Приблизительный поиск ближайших соседей (ANNS) , что в пользу некоторой точности ускоряет процесс. Вы получите хорошее приближение к точному NN с хорошей вероятностью.


Горячие темы, которые могут быть достойны:

  1. Современные подходы LSH , такие как Разенштейн .
  2. RKD лес : Лес (ы) рандомизированных k-d деревьев (RKD), как описано в FLANN , или в более позднем подходе, частью которого я был, kd-GeRaF .
  3. LOPQ , что означает локально оптимизированное квантование продукта, как описано здесь . Это очень похоже на новый подход Бабенко + Лемптицкого .

Вы также можете проверить мои соответствующие ответы:

  1. Два набора точек с высокой размерностью: найдите ближайшего соседа в другом наборе
  2. Сравнение времени выполнения запросов ближайшего соседа для разных структур данных
  3. Реализация KD-дерева PCL чрезвычайно медленная
8 голосов
/ 22 апреля 2011

Чтобы ответить на ваши вопросы один за другим:

  • Нет, евклидово расстояние - плохая метрика в многомерном пространстве. По большому счету, разница между ближайшим и самым дальним соседом невелика.
  • В больших измерениях содержится много работ / исследований, но большинство вещей требует большого математического смягчения.
  • Дерево KD плохо подходит для данных большого размера ... избегайте его всеми средствами

Вот хорошая статья, чтобы вы начали в правильном направлении. " Когда в ближайшем соседе многозначительно ?" Бейер и др.

Я работаю с текстовыми данными размером 20К и выше. Если вам нужен какой-нибудь текстовый совет, я могу вам помочь.

5 голосов
/ 22 апреля 2011

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

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

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

4 голосов
/ 01 января 2013

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

Но, кроме того, kd-деревья хорошо работают только с нормами Lp для всех, что я знаю, и есть эффект концентрации на расстоянии, который заставляет алгоритмы на основе расстояний ухудшаться с ростом размерности.

Для получения дополнительной информации вы можете прочитать о проклятии размерности и его различных вариантах (есть более чем одна сторона!)

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

3 голосов
/ 09 января 2014

Я столкнулся с той же проблемой и могу сказать следующее.

  1. Евклидово расстояние является хорошей метрикой расстояния, однако оно вычислительно дороже, чем Манхэттенское расстояние , и иногда дает несколько худшие результаты, поэтому я бы выбралпозже.

  2. Значение k можно найти опытным путем.Вы можете попробовать другие значения и проверить полученные ROC-кривые или некоторую другую меру точности / отзыва, чтобы найти приемлемое значение.

  3. Соблюдаются как евклидовы, так и манхэттенские расстояния неравенство треугольника , таким образом, вы можете использовать их в метрических деревьях.Действительно, производительность KD-деревьев сильно снижается, когда данные имеют более 10 измерений (я сам сталкивался с этой проблемой).Я нашел VP-деревья как лучший вариант.

3 голосов
/ 01 апреля 2013

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

3 голосов
/ 25 апреля 2011

KD Деревья отлично работают для 21 измерения, если вы уйдете рано, посмотрев, скажем, 5% всех точек. FLANN делает это (и другие ускорения) для соответствия 128-мерным векторам SIFT.(К сожалению, FLANN делает только евклидову метрику, а быстрый и надежный scipy.spatial.cKDTree делает только метрики Lp; их может или не может быть достаточно для ваших данных.)конечно, компромисс между скоростью и точностью здесь.

(Если бы вы могли описать ваши Ndata, Nquery, распределение данных, которое могло бы помочь людям попробовать похожие данные.)

Добавлено 26 апреля, время выполнениядля cKDTree с отсечкой на моем старом компьютере Mac, чтобы дать очень грубое представление о возможности:

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=1000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.1 % of the 1000000 points, 0.31 % of 188315 boxes; better 0.0042 0.014 0.1 %
3.5 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.253

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=5000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.48 % of the 1000000 points, 1.1 % of 188315 boxes; better 0.0071 0.026 0.5 %
15 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.245
...