Эффективное сравнение 100 000 векторов - PullRequest
14 голосов
/ 15 июня 2009

Я сохраняю 100.000 векторов в базе данных. Каждый вектор имеет размерность 60. (int vector [60])

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

Я использую Tanimoto Classifier для сравнения 2 векторов:

alt text

Существуют ли какие-либо методы, позволяющие не выполнять все записи в базе данных?

Еще одна вещь! Мне не нужно сортировать все векторы в базе данных. Я хочу получить топ-20 самых похожих векторов. Так что, может быть, мы можем приблизить порог к 60% записей и использовать остальные для сортировки. Что ты думаешь?

Ответы [ 10 ]

24 голосов
/ 18 июня 2009

Во-первых, предварительно обработайте ваш список векторов, чтобы сделать каждый вектор нормализованным ... единичная величина. Теперь обратите внимание, что ваша функция сравнения T () теперь имеет значения величин, которые становятся постоянными, и формулу можно упростить, чтобы найти наибольшее произведение точек между вашим тестовым вектором и значениями в базе данных.

Теперь подумайте о новой функции D = расстояние между двумя точками в 60D пространстве. Это классическое L2 расстояние , взять разность каждого компонента, возвести в квадрат каждый, сложить все квадраты и взять квадратный корень из суммы. D (A, B) = sqrt ((A-B) ^ 2) где A и B - каждый из 60 размерных векторов.

Это может быть расширено до D (A, B) = sqrt (A * A -2 * точка (A, B) + B * B). А и В - единичная величина, то. И функция D является монотонной, поэтому она не изменит порядок сортировки, если мы удалим sqrt () и посмотрим на квадратные расстояния. Это оставляет нам только -2 * точка (A, B). Таким образом, расстояние минимизации точно эквивалентно максимизации точечного произведения.

Таким образом, исходную метрику классификации T () можно упростить, чтобы найти произведение высшей точки между нормированными векторами. И это сравнение показано эквивалентным нахождению ближайших точек к точке выборки в пространстве 60-D.

Так что теперь все, что вам нужно сделать, - это решить эквивалентную проблему «заданной нормализованной точки в пространстве 60D, перечислить 20 точек в базе данных нормализованных векторов выборок, которые находятся ближе всего к ней».

Эта проблема хорошо понятна .. это K Ближайшие соседи. Есть много алгоритмов для решения этой проблемы. Наиболее распространенными являются классические KD деревья .

Но есть проблема. Деревья KD имеют O (e ^ D) поведение. Высокая размерность быстро становится болезненной. И 60 измерений определенно в этой чрезвычайно болезненной категории. Даже не пытайтесь.

Однако существует несколько альтернативных общих методов для ближайшего соседа с высоким D. Эта статья дает четкий метод.

Но на практике есть отличное решение, включающее еще одно преобразование. Если у вас есть метрическое пространство (что вы делаете, или вы не будете использовать сравнение Tanimoto), вы можете уменьшить размерность задачи на 60-мерное вращение. Это звучит сложно и страшно, но это очень часто ... это форма разложения по сингулярным значениям или разложения по собственным значениям. В статистике он известен как Анализ основных компонентов.

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

Наконец, вы сделаете классическое K ближайших соседей, вероятно, только в 3-10 измерениях ... вы можете экспериментировать для лучшего поведения. Для этого есть потрясающая библиотека под названием Ranger , но вы можете использовать и другие библиотеки. Большим дополнительным преимуществом является то, что вам даже больше не нужно хранить все 60 компонентов данных образца!

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

Итак, краткое изложение выше:

  1. Нормализуйте свои векторы, превратив вашу проблему в задачу K-ближайшего соседа в 60 измерениях
  2. Использование анализа основных компонентов для уменьшения размерности до приемлемого предела, скажем, 5 измерений
  3. Используйте алгоритм K Nearest Neighbor, например, библиотеку KD-дерева Ranger, чтобы найти соседние сэмплы.
3 голосов
/ 15 июня 2009

Обновление:

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


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

Нет базы данных, о которой я знаю, имеет встроенную поддержку kd-tree, поэтому вы можете попробовать реализовать следующее решение в MySQL, если вы ищете ограниченное количество ближайших записей:

  • Сохранение проекций векторов на каждое из 2 -мерного пространства (возможно, занимает n * (n - 1) / 2 столбцы)
  • Индексируйте каждый из этих столбцов с помощью SPATIAL index
  • Выберите квадрат MBR заданной области в любой проекции. Произведение этих MBR даст вам гиперкуб ограниченного гиперобъема, который будет содержать все векторы с расстоянием, не превышающим заданный.
  • Найти все проекции в пределах всех MBR, используя MBRContains

Вам все равно придется сортировать в этом ограниченном диапазоне значений.

Например, у вас есть набор 4 -мерных векторов с величиной 2:

(2, 0, 0, 0)
(1, 1, 1, 1)
(0, 2, 0, 0)
(-2, 0, 0, 0)

Вам придется хранить их следующим образом:

p12  p13  p14  p23  p24  p34
---  ---  ---  ---  ---  ---
2,0  2,0  2,0  0,0  0,0  0,0
1,1  1,1  1,1  1,1  1,1  1,1
0,2  0,0  0,0  2,0  2,0  0,0
-2,0 -2,0 -2,0 0,0  0,0  0,0

Скажем, вам нужно сходство с первым вектором (2, 0, 0, 0) больше 0.

Это означает наличие векторов внутри гиперкуба: (0, -2, -2, -2):(4, 2, 2, 2).

Вы выдаете следующий запрос:

SELECT  *
FROM    vectors
WHERE   MBRContains('LineFromText(0 -2, 4 2)', p12)
        AND MBRContains('LineFromText(0 -2, 4 2)', p13)
        …

и т. Д. Для всех шести столбцов

2 голосов
/ 15 июня 2009

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

Это то, что вы думаете?

======= Перемещенный комментарий сюда:

Учитывая описание, вы не можете не просматривать все записи, чтобы рассчитать коэффициент подобия. Если вы скажете базе данных использовать коэффициент подобия в предложении «упорядочить по», вы можете позволить ей выполнить всю тяжелую работу. Вы знакомы с SQL?

2 голосов
/ 15 июня 2009

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

  • Норма выбранного вектора
  • Точечное произведение A.B, повторно использующее его как для числителя, так и для знаменателя в данном расчете T (A, B).

Если вам нужны только N ближайших векторов или если вы выполняете один и тот же процесс сортировки несколько раз, могут быть доступны дополнительные приемы. (Наблюдения типа T (A, B) = T (B, A), кэширование векторных норм для всех векторов и, возможно, какой-то порог / пространственная сортировка).

1 голос
/ 18 июня 2009

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

Тогда триангулируйте. если расстояние d между вашим целевым вектором v и некоторым вектором v 'велико, то расстояние между v и всеми другими v' ', близкими к v', также будет большим (-ish), поэтому нет необходимости сравнивать их больше (вам придется найти приемлемые определения «большой», хотя сами). Вы можете поэкспериментировать с повторением процесса и для сброшенных векторов v '' и проверить, сколько вычислений во время выполнения вы можете избежать, прежде чем точность начнет падать. (сделайте тестовый набор «правильных» результатов для сравнения)

удачи.

ДСН

1 голос
/ 15 июня 2009

Более новый ответ

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


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

Поскольку векторы имеют одинаковую длину (60), я думаю, вы слишком много занимаетесь математикой. Разве вы не можете просто сделать точечное произведение выбранного против каждого кандидата?

В 3D: alt text

Три умножения. В 2D это только два умножения.

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

1 голос
/ 15 июня 2009

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

0 голосов
/ 11 августа 2010

Другой вариант - проблема всех пар с заданным порогом для некоторой функции подобия. Взгляните на бумагу Баярдо и код здесь http://code.google.com/p/google-all-pairs-similarity-search/

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

0 голосов
/ 18 июня 2009

Не пройдя через все записи? Это кажется невозможным. Единственное, что вы можете сделать, это сделать математику во время вставки (помня, что эквивалентность http://tex.nigma.be/T%2528A%252CB%2529%253DT%2528B%252CA%2529.png: P)

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

0 голосов
/ 15 июня 2009

Э, нет?

Вы должны сделать только 99,999 против того, который вы выбрали (а не все n(n-1)/2 возможные пары), конечно, но это так же мало, как и раньше.


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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...