Я написал неэффективный, но простой алгоритм на Java, чтобы увидеть, насколько близко я могу подойти к выполнению базовой кластеризации по набору точек, более или менее как описано в вопросе.
Алгоритм работает со списком, если (x, y) совпадает с ps
, которые указаны как int
s. Он также принимает три других параметра:
- radius (
r
): для данной точки какой радиус для сканирования ближайших точек
- макс. адреса (
maxA
): каково максимальное количество адресов (точек) на кластер?
- минимальные адреса (
minA
): минимальное количество адресов на кластер
Установите limitA=maxA
. Основная итерация: инициализировать пустой список possibleSolutions
. Внешняя итерация: для каждой точки p
в ps
. Инициализировать пустой список pclusters
. Определен рабочий список точек wps=copy(ps)
. Рабочая точка wp=p
. Внутренняя итерация: пока wps
не пусто. Убрать точку wp
в wps
. Определите все точки wpsInRadius
в wps
, которые находятся на расстоянии ‹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 адресов.
(источник: paperboyalgorithm на сайте sites.google.com)
Затем, если мы уменьшим минимальное количество адресов на кластер, установив minA=12
, мы найдем 3 кластера по 12/12/8 точек.
(источник: paperboyalgorithm на сайте sites.google.com)
И чтобы продемонстрировать, что алгоритм далек от совершенства, вот результат с maxA=7
, но мы получили 6 кластеров, некоторые из них небольшие. Так что при определении параметров вам все равно придется слишком много гадать. Обратите внимание, что r
здесь всего 5.
(источник: paperboyalgorithm на сайте sites.google.com)
Просто из любопытства я попробовал алгоритм на большем наборе случайно выбранных точек. Я добавил изображения ниже.
Заключение? Это заняло у меня полдня, это неэффективно, код выглядит некрасиво и относительно медленно. Но он показывает, что можно получить какой-то результат за короткий период времени. Конечно, это было просто для развлечения; Превратить это во что-то действительно полезное - это сложная часть.
(источник: paperboyalgorithm на сайте sites.google.com)
(источник: paperboyalgorithm на сайте sites.google.com)
person
eljenso
schedule
01.03.2009