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

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

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

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

Ответы

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

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

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

см

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

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

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

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