Алгоритм разбиения
У меня есть набор точек, которые содержатся внутри прямоугольника. Я хотел бы разбить прямоугольники на подрешетки на основе плотности точек (давая несколько подрешеток или желаемую плотность, в зависимости от того, что проще).
разбиение не должно быть точным (почти любое приближение лучше, чем обычная сетка), но алгоритм должен справляться с большим количеством точек - прибл. 200 миллионов. Однако нужное количество subrectangles существенно ниже (около 1000).
кто-нибудь знает алгоритм, который может помочь мне с данной конкретной задачи?
8 ответов
просто чтобы понять проблему. Следующее грубо и плохо работает, но я хочу знать, является ли результат тем, что вы хотите>
предположение> количество прямоугольников даже
Предположение> распределение точек заметно 2D (нет большого накопления в одной строке)
порядок>
Разделите пополам n / 2 раза по обеим осям, петляя от одного конца к другому каждого ранее определенного прямоугольника, подсчитывая "пройденные" точки и сохраняя количество пройденных точек на каждом итерация. После подсчета разделите прямоугольник пополам, выбрав точки, подсчитанные в каждом цикле.
Это то, чего вы хотите достичь?
вы после стандартного дерева KD-дерева или дерева разбиения двоичного пространства, я думаю. (Вы можете посмотреть его в Википедии.)
поскольку у вас очень много очков, вы можете только приблизительно разделить первые несколько уровней. В этом случае вы должны взять случайную выборку ваших 200M точек-возможно, 200k из них-и разделить полный набор данных в средней точке подвыборки (вдоль какой оси больше). Если вы действительно выбираете точки случайным образом, вероятность того, что вы пропустить огромный кластер точек, которые нужно разделить, будет примерно равно нулю.
теперь у вас есть две проблемы около 100м очков. Разделите каждую по более длинной оси. Повторяйте до тех пор, пока не прекратите брать подмножества и не разделите по всему набору данных. После десяти широтно-первых итераций вы будете сделаны.
Если у вас есть другая проблема-вы должны указать галочки вдоль оси X и Y и заполнить сетку вдоль них, как можно лучше, а не иметь нерегулярное разложение KD-дерева-возьмите подмножество точек и найдите 0/32, 1/32, ..., 32/32 процентили вдоль каждой оси. Нарисуйте линии сетки, а затем заполните полученную 1024-элементную сетку точками.
Я думаю, что начну со следующего, что близко к тому, что уже предложил @belisarius. Если у вас есть какие-либо дополнительные требования, такие как предпочтение "почти квадратных" прямоугольников "длинным и тонким", вам нужно будет изменить этот наивный подход. Для простоты предположу, что точки распределены приблизительно случайным образом.
- разделить начальный прямоугольник на 2 с линией, параллельной короткой стороне прямоугольника и проходящей точно через середина.
- подсчитайте количество точек в обоих полу-прямоугольниках. Если они равны (достаточно), перейдите к шагу 4. В противном случае перейдите к шагу 3.
- на основе распределения точек между полукруглыми, переместите линию, чтобы выровнять вещи снова. Поэтому, если, возможно, первый разрез разделит точки 1/3, 2/3, переместите линию на половину тяжелой половины прямоугольника. Перейдите к Шагу 2. (Будьте осторожны, чтобы не попасть в ловушку здесь, перемещая линию в постоянно уменьшающихся шагах сначала в одну сторону, затем в другую.)
- Теперь передайте каждый из полу-прямоугольников рекурсивному вызову этой функции на шаге 1.
Я надеюсь, что это достаточно хорошо описывает предложение. Он имеет ограничения: он будет производить несколько прямоугольников, равных некоторой мощности 2, поэтому отрегулируйте его, если этого недостаточно. Я назвала это рекурсивно, но он идеально подходит для parallelisation. Каждое разделение создает две задачи, каждая из которых разбивает прямоугольник и создает еще две задачи.
Если вам не нравится этот подход, возможно, вы могли бы начать с регулярной сетки с несколькими (10 - 100, возможно) из числа прямоугольников, которые вы хотите. Подсчитайте количество точек в каждом из этих крошечных прямоугольников. Затем начните склеивать крошечные прямоугольники вместе, пока менее крошечный прямоугольник не будет содержать (приблизительно) правильное количество точек. Или, если он удовлетворяет вашим требованиям достаточно хорошо, вы можете использовать это как метод дискретизации и интегрировать его с моим первым подходите, но только поместите линии резки вдоль границ крошечных прямоугольников. Это, вероятно, будет намного быстрее, так как вам нужно будет только один раз подсчитать точки в каждом крошечном прямоугольнике.
Я действительно не думал о времени работы любого из них; у меня есть предпочтение первому подходу, потому что я делаю изрядное количество параллельного программирования и имею множество процессоров.
хороший вопрос.
Я думаю, что область, которую вам нужно исследовать, - это "вычислительная геометрия" и проблема "K-разбиения". Есть ссылка, которая может помочь вам начать здесь
вы можете обнаружить, что сама проблема NP-hard, что означает, что хороший алгоритм аппроксимации-лучшее, что вы собираетесь получить.
б K-означает кластеризацию или Вороного схемы хорошо подходит для проблемы, которую вы пытаетесь решить?
б дерева квадрантов работы?
a quadtree-это древовидная структура данных, в которой каждый внутренний узел имеет ровно четыре дочерних элемента. Квадранты чаще всего используются для разделения двумерного пространства путем рекурсивного деления его на четыре квадранта или области. Области могут быть квадратными или прямоугольными или иметь произвольную форму. Эта структура данных была названа дерева квадрантов Рафаэль Финкель и Л. Дж. Бентли в 1974 году. Подобное называется также Вопрос-дерево. Все формы Quadtrees имеют некоторые общие черты:
- они разлагают пространство на адаптируемые клетки
- каждая ячейка (или ведро) имеет максимальную емкость. Когда максимальная емкость достигается, ведро splits
- каталог дерева следует за пространственной декомпозицией квадрата