Я написал неэффективный, но простой алгоритм на Java, чтобы увидеть, насколько близко я смог выполнить базовую кластеризацию по набору точек, более или менее, как описано в вопросе.
Алгоритм работает со списком, если координаты (x, y) ps
указаны как int
s. Он также принимает три других параметра:
- радиус (
r
): с учетом точки, каков радиус для сканирования ближайших точек
- макс. Адресов (
maxA
): каково максимальное количество адресов (точек) на кластер?
- минимальные адреса (
minA
): минимальные адреса на кластер
Набор limitA=maxA
.
Основная итерация:
Инициализировать пустой список possibleSolutions
.
Внешняя итерация: для каждой точки p
в ps
.
Инициализировать пустой список pclusters
.
Рабочий список точек wps=copy(ps)
определен.
Рабочая точка wp=p
.
Внутренняя итерация: , пока wps
не пусто.
Удалить точку wp
в wps
. Определите все точки wpsInRadius
в wps
, которые находятся на расстоянии <<code>r от wp
. Сортировать wpsInRadius
по возрастанию в соответствии с расстоянием от wp
. Оставьте первые min(limitA, sizeOf(wpsInRadius))
баллов в wpsInRadius
. Эти точки образуют новый кластер (список точек) pcluster
. Добавьте pcluster
к pclusters
. Удалить точки в pcluster
из wps
. Если wps
не пусто, wp=wps[0]
и продолжите внутреннюю итерацию.
Завершить внутреннюю итерацию.
Список кластеров pclusters
получается. Добавьте это к possibleSolutions
.
Завершить внешнюю итерацию.
У нас есть для каждого p
в ps
список кластеров pclusters
в possibleSolutions
. Каждый pclusters
затем взвешивается. Если avgPC
- это среднее число точек на кластер в possibleSolutions
(глобальное), а avgCSize
- среднее количество кластеров на pclusters
(глобальное), то эта функция использует обе эти переменные для определения вес:
private static WeightedPClusters weigh(List<Cluster> pclusters, double avgPC, double avgCSize)
{
double weight = 0;
for (Cluster cluster : pclusters)
{
int ps = cluster.getPoints().size();
double psAvgPC = ps - avgPC;
weight += psAvgPC * psAvgPC / avgCSize;
weight += cluster.getSurface() / ps;
}
return new WeightedPClusters(pclusters, weight);
}
Лучшим решением сейчас является pclusters
с наименьшим весом. Мы повторяем основную итерацию, пока можем найти лучшее решение (меньший вес), чем предыдущее лучшее с limitA=max(minA,(int)avgPC)
. Завершение основной итерации.
Обратите внимание, что для одних и тех же входных данных этот алгоритм всегда будет давать одинаковые результаты. Списки используются для сохранения порядка, и в них нет случайных .
Чтобы увидеть, как этот алгоритм ведет себя, это изображение результата на тестовом шаблоне из 32 точек. Если maxA=minA=16
, то мы найдем 2 кластера из 16 адресов.
Далее, если мы уменьшим минимальное количество адресов на кластер, установив minA=12
, мы найдем 3 кластера по 12/12/8 точек.
И чтобы продемонстрировать, что алгоритм далек от совершенства, вот результат с maxA=7
, но мы получаем 6 кластеров, некоторые из которых небольшие. Таким образом, вам все равно придется слишком много угадывать при определении параметров. Обратите внимание, что r
здесь только 5.
Просто из любопытства я попробовал алгоритм на большем наборе случайно выбранных точек. Я добавил изображения ниже.
Вывод? Это заняло у меня полдня, это неэффективно, код выглядит уродливо, и это относительно медленно. Но это показывает, что можно получить некоторый результат за короткий промежуток времени. Конечно, это было просто для удовольствия; превратить это во что-то действительно полезное - сложная часть.