Эффективное сравнение 1 миллиона векторов, содержащих (float, integer) кортежи - PullRequest
3 голосов
/ 22 февраля 2010

Я работаю в проекте по химии / биологии. Мы создаем веб-приложение для быстрого сопоставления экспериментальных данных пользователя с прогнозными данными в справочной базе данных. Справочная база данных будет содержать до миллиона записей. Данные для одной записи представляют собой список (вектор) кортежей, содержащий значение с плавающей запятой от 0,0 до 20,0 и целочисленное значение от 1 до 18. Например (7.2394, 2), (7.4011, 1), (9.9367, 3), ... так далее. Пользователь войдет в аналогичный список кортежей, и веб-приложение должно затем вернуть, скажем, 50 лучших подходящих записей в базе данных.

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

Редактировать - перемещенный текст для ответа -

Как мы можем получить эффективное ранжирование 1 запроса на 1 миллион записей?

Ответы [ 5 ]

2 голосов
/ 22 февраля 2010

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

В первой ссылке вы можете прочитать: « Алгоритм SEQUEST для анализа масс-спектров использует автокорреляцию в сочетании с кросс-корреляцией для оценки сходства наблюдаемого спектра с идеализированным спектром, представляющим пептид."

2 голосов
/ 22 февраля 2010

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

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

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

Хорошо, учитывая дополнительную информацию, я все еще не вижу необходимости в чем-то лучше, чем прямой линейный поиск, если есть только 1 миллион опорных векторов и алгоритм такой простой. Я только что попробовал, и даже чистая реализация линейного сканирования на Python заняла всего около трех секунд. Потребовалось в несколько раз больше времени, чтобы составить несколько случайных данных для тестирования. Это в некоторой степени зависит от довольно сумасшедшего уровня оптимизации в библиотеке сортировки Python, но это преимущество языков высокого уровня.

from cmath import *
import random
r = [(random.uniform(0,20), random.randint(1,18)) for i in range(1000000)]
# this is a decorate-sort-undecorate pattern
# look for matches to (7,9)
# obviously, you can use whatever distance expression you want
zz=[(abs((7-x)+(9-y)),x,y) for x,y in r]
zz.sort()
# return the 50 best matches
[(x,y) for a,x,y in zz[:50]]
1 голос
/ 22 февраля 2010

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

Худший случай - журнал (n)

0 голосов
/ 22 февраля 2010

Один из подходов, который мы пробуем сами, который учитывает расхождения между запросом и ссылкой, состоит в том, чтобы связать значения с плавающей точкой. Мы тестируем и хотим предложить пользователю выбор разных размеров бина. Размеры бункера будут 0,1, 0,2, 0,3 или 0,4. Таким образом, binning оставляет от 50 до 200 бинов, каждое с соответствующим целочисленным значением от 0 до 18, где 0 означает, что в этом бине не было значения. Справочные данные могут быть предварительно объединены и сохранены в базе данных. Затем мы можем взять данные запроса и сравнить их со справочными данными. Один подход может быть для всех бинов, вычесть целочисленное значение запроса из ссылочного целочисленного значения. Суммируя все различия, мы получаем оценку сходства с самыми похожими ссылочными записями, приводящими к самым низким оценкам.

Другой (более простой) вариант поиска, который мы хотим предложить, - это когда пользователь вводит только значения с плавающей точкой. Целочисленные значения в обоих запросах в качестве списка ссылок могут затем быть установлены на 1. Затем мы используем расстояние Хэмминга для вычисления разницы между запросом и значениями бинарных ссылок. Ранее я спрашивал об эффективном алгоритме этого поиска.

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

0 голосов
/ 22 февраля 2010

Если вы можете «сопоставить» свои справочные данные с координатами x-y на плоскости, существует изящный метод, который позволяет вам выбрать все точки на заданном расстоянии / допуске (используя кривые Гильберта).

Вот подробный пример .

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