Как эффективно найти k-ближайших соседей в многомерных данных? - PullRequest
15 голосов
/ 18 октября 2010

Итак, у меня есть около 16 000 75-мерных точек данных, и для каждой точки я хочу найти ее k ближайших соседей (используя евклидово расстояние, в настоящее время k = 2, если это облегчает его)

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

Моей следующей идеей будет использование PCA (Анализ основных компонентов), чтобы уменьшить количество измерений, но мне было интересно: есть ли какой-нибудь умный алгоритм или структура данных, чтобы решить это точно в разумные сроки?

Ответы [ 6 ]

3 голосов
/ 19 октября 2010

В статье Википедии для kd-деревьев есть ссылка на библиотеку ANN :

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

Основываясь на собственном опыте, ANN выполняет довольно эффективно для точки наборы размером от тысячи до сотни тысяч, а в размеры достигают 20 . ( Для приложений значительно выше размеры, результаты довольно пятнистый, но вы все равно можете попробовать .

Что касается алгоритма / структуры данных:

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

Я бы попробовал сначала напрямую, и если это не даст удовлетворительных результатов, я бы использовал его с набором данных после применения PCA / ICA (поскольку маловероятно, что у вас будет достаточно измерений для kd дерево для обработки).

2 голосов
/ 03 сентября 2017

использовать kd-дерево

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

уменьшить количество измерений

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

Под точностью я имею в виду нахождение точного ближайшего соседа (NN).

Анализ основных компонентов ( PCA ) - это хорошая идея, если вы хотите уменьшить размерное пространство, в котором живут ваши данные.

Есть ли какой-нибудь умный алгоритм или структура данных, чтобы решить это точно в разумные сроки?

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

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

Подробнее об ANNS вы можете прочитать во введении к нашему документу kd-GeRaF .

Хорошая идея - объединить ANNS с уменьшением размерности.

Хеширование с учетом локальных особенностей ( LSH ) - современный подход к решению проблемы ближайшего соседа в больших размерах. Основная идея заключается в том, что точки, которые находятся близко друг к другу, хэшируются в одно и то же ведро. Поэтому, когда запрос поступит, он будет хэширован в сегмент, где этот сегмент (и обычно его соседние) содержит хорошие NN-кандидаты).

FALCONN - хорошая реализация C ++, которая фокусируется на сходстве косинусов. Другой хорошей реализацией является наша DOLPHINN , которая является более общей библиотекой.

1 голос
/ 19 октября 2010

BK-Tree не такая уж плохая мысль. Взгляните на Блог Ника по автоматам Левенштейна . В то время как его фокус - струны, он должен дать вам трамплин для других подходов. Другая вещь, о которой я могу думать, это R-Trees , однако я не знаю, были ли они обобщены для больших измерений. Я не могу сказать больше, потому что я не использовал их напрямую и не реализовывал сам.

1 голос
/ 19 октября 2010

Нет оснований полагать, что это NP-полная.Вы ничего не оптимизируете, и мне будет трудно понять, как преобразовать это в другую NP-полную проблему (у меня на полке Гэри и Джонсон , и я не могу найти ничего подобного),На самом деле, я бы просто использовал более эффективные методы поиска и сортировки.Если у вас есть n наблюдений, вы должны рассчитать nxn расстояний прямо перед собой.Затем для каждого наблюдения нужно выбрать из топ k ближайших соседей.Это n в квадрате для расчета расстояния, n log (n) для сортировки, но вы должны выполнить сортировку n раз (разные для КАЖДОГО значения n).Грязное, но все же полиномиальное время, чтобы получить ваши ответы.

1 голос
/ 19 октября 2010

Можно предположительно использовать Мортоновские коды , но с 75 измерениями они будут огромными.И если все, что у вас есть, - это 16 000 точек данных, исчерпывающий поиск не должен занимать слишком много времени.

0 голосов
/ 31 мая 2015

Одной из наиболее распространенных реализаций будет сортировка ближайших соседей массив , которые вы вычислили для каждой точки данных. Поскольку сортировка всего массива может быть очень дорогой, вы можете использовать такие методы, как косвенная сортировка, например Numpy.argpartition в библиотеке Python Numpy, для сортировки только самых близких значений K, которые вас интересуют. Не нужно сортировать весь массив.

@ Ответ Грембо выше должен быть значительно уменьшен. так как вам нужно только K ближайших значений. и нет необходимости сортировать все расстояния от каждой точки.

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

если вам нужно отсортировать K соседей, снова отсортируйте вывод

см

Документация для argpartition

...