Как эффективно найти k ближайших соседей в многомерных данных?

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

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

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

6 ответов


статья Википедии для KD-trees имеет ссылку на библиотека ANN:

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

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

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

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

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


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


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


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


используйте KD-tree

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

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

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

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

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

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

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

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

вы можете прочитать больше об ANNS во введении нашего kd-GeRaF статьи.

хорошей идеей является объединение ANNS с уменьшением размерности.

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

FALCONN хорошая реализация C++, который занимается в охаи. Еще одна хорошая реализация-наша телевизором с плоским экраном, которая является более общей библиотеки.


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

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

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

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

посмотреть

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