Блог пользователя goryinyich

Автор goryinyich, 13 лет назад, По-русски

Всегда думал, что задачи типа "дано 100....000 точек, для каждой найти ближайшую" - это олимпиадная блажь, на практике никому не нужная. Оказалось, что понадобилась, причем как раз на работе, причем в усложненном виде.


Задача такая. Дано порядка 10000 точек в N-мерном (N небольшое - не более 10) единичном кубике, для каждой нужно найти K (K < 100) ближайших. Строгих ограничений, понятно, нет, но хотелось бы, чтобы на обычном компьютере это укладывалось в несколько секунд.

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

UPD: оптимизированное решение "в лоб" работает порядка минуты. Нужно ускорить его хотя бы в несколько десятков раз.

UPD^2: после прочтения комментариев и обдумывания, пришел к выводу, что оптимальным по "сложность написания/качество" будет следующий алгоритм: создаем N списков точек, отсортированных по различным измерениям, и перебираем для заданной только точки, входящие в 2К ближайших по какому-либо измерению.
  • Проголосовать: нравится
  • +16
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
кажется, что тупо в лоб будет укладываться в несколько секунд

кстати, может это поможет: http://en.wikipedia.org/wiki/K-d_tree
  • 13 лет назад, # ^ |
      Проголосовать: нравится +13 Проголосовать: не нравится
    Не укладывается. Расстояния считаются за O(1), но на самом деле это OOO(1) =) В лоб где-то минуту работает, нужно ускорить хотя бы в несколько десятков раз.
13 лет назад, # |
Rev. 2   Проголосовать: нравится +10 Проголосовать: не нравится

Как на счет квадро (или в данном случае 2^N-ро) - дерева? Спускаемся до тех пор пока в данном Н-мерном кубике не меньше К^3\2 точек, запомниаем расстояния, и потом пытаемся еще проверить в кубиках, близжайших к данному. Или, к примеру, обрабатываем все К точек по одному - оцениваем, на каком расстоянии находятся точки данного куба (минимум и максимум) от нашей, углубляемся если максимум больше текущего расстояния до И-той точки.


Как другой вариант и читерская замена квадродереву  если не обязательно 100% точное решение - проектируем все на некую прямую и смотрим К^2 близжайших в проекции.

На тестах, которые не пытаются завалить такое решение:) должно работать неплохо.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Спасибо, с проекциями - действительно хорошая идея.
    Нет, тестов, которые пытаются завалить, не будет. Хотя кто его знает - кризис, от фондовых рынков всего можно ожидать =)
13 лет назад, # |
  Проголосовать: нравится +12 Проголосовать: не нравится
Знаете финт, как можно легко-прелегко найти пару ближайших точек среди данного множества в Евклидовом пространстве какой-нибудь размерности? Берём рандомную далеко-далеко удалённую точку,  сортируем наши по расстоянию относительно неё и говорим такую вещь: ну ведь понятно же, что пара кратчайших в нашем порядке сортировки окажутся недалеко друг от друга! Практика показывает, что для 100000 точек достаточно перебрать все пары точек, удалённые друг от друга не более, чем на 50 в порядке нашей сортировки - это гарантированно находит точный ответ.

Аналогично можно искать кратчайшую точку к фиксированной - сортируем относительно случайной удалённой и рассматриваем ближайшие к ней сто точек в порядке сортировки. Мне кажется, тут схожая эвристика тоже должна работать. Вполне можно натыкать сколько-нибудь случайных точек, потом выбирать из них рандомную, сортировать относительно неё и брать тысячу ближайших к нужной точке в порядке нашей сортировки. Можете пострессить с тупым решением, чтобы оценить эффективность.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А чем это отличается от проекции на прямую? Ведь если считать, что точка удалена очень далеко, то сортировка по углу относительно нее - это то же самое, что и сортировка проекций точек на прямую, перпендикулярную прямой, проходящей через эту удаленную точку и любую точку из множества.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Вот честно говоря не знаю. По логике вещей то же самое. Однако мне как-то привычнее относительно точки сортировать. Мне уже самому интересно проверить стало.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        По-моему, оно и есть. Осталось ещё немного упростить, проецируя не на любую прямую, а на одну из координатных осей. Т.е. отсортировать точки по одной из координат.

        М-да... Я в 11-м классе это использовал для своей реализации игрушки Life на бесконечном поле. И до сих пор думал что это гениальная идея. А она оказывается банальная... ;-)
        • 13 лет назад, # ^ |
            Проголосовать: нравится +5 Проголосовать: не нравится
          Вот как раз на координатную ось проецировать не надо. Намного более вероятно, что в реальной задаче очень много точек будут лежать на одной вертикальной прямой или просто близко по иксу, чем то что их проекции на прямую y = e * sqrt(pi) / 2.1 * x будут лежать рядом. Я уже не говорю о более изощренных случаях, когда этот метод валится.
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Естественно если у нас есть повод подозревать множество в анизотропии, то по координатной оси нехорошо. А если задача такова, что с этим проблемы нет - то.

            Метод, спору нет, не является точным.  ;-)
      • 13 лет назад, # ^ |
        Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

        А теперь, когда всё выяснено... Не поделитесь ли, откуда на практике такая задача возникла? (если это не связано с реализацией какого-нибудь советника для какого-нибудь трейдера) Заранее спасибо!


        UPD: Вот зло, точно помню что коммент цеплял ко всему посту, а не к другому комменту! Всем сорри.

        UPD: А вообще "единичный кубик в N-мерном пространстве" это видимо область куда значения N-критериев объекта/факта какого-то попадают. Так что главный вопрос - зачем нужно для каждой из точек искать ближайшие (вместо, скажем, кластеризации и т.п.)

        • 13 лет назад, # ^ |
            Проголосовать: нравится +9 Проголосовать: не нравится
          Это не реализация советника трейдера. Это реализация робота, который торгует в полностью автоматическом режиме. Нагрузка в виде идиота-трейдера ему не нужна.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Спасибо, вот это вообще виртуозно, вы избавили меня от лишней работы. Написание кода не самая неприятная, но и все-таки не самая приятная часть моей работы.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Это нужно для кластеринга или еще для чего?
  • 13 лет назад, # ^ |
      Проголосовать: нравится +2 Проголосовать: не нравится
    Сомнительно... Чтоб разбить на кластеры - алгоритмы уж куча известна... И википедия с гуглом на них отзываются, так что этот пост бы здесь не появился, наверное... ;-)
  • 13 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится
    Скорее для паттерн-рекогнишна. На всех точках задана некоторая функция, и мне нужно среднее ее значение для ближайших K
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
Туплю. Написал не о той задаче, что надо, а о просто поиске ближайшей пары. Sorry.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Но все равно красивое решение, и простое. Спасибо!
    P.S. Кстати, для K точек оно тоже обобщается, но в эффективности не уверен.
  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    (почему-то подумал про двумерное пространство :о))
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Вопрос не в тему. А какая изначальная задача?
  • 13 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится
    По соображениям конфиденциальности я не хотел бы и не могу это обсуждать