J'ai écrit un algorithme simple mais inefficace en Java pour voir dans quelle mesure je pouvais faire un regroupement de base sur un ensemble de points, plus ou moins comme décrit dans la question.
L'algorithme fonctionne sur une liste de coordonnées (x,y). ps
qui sont spécifiés comme int
s. Il prend également trois autres paramètres :
- rayon (
r
) : étant donné un point, quel est le rayon pour rechercher les points voisins ?
- adresses maximales (
maxA
) : quel est le nombre maximum d'adresses (points) par cluster ?
- adresses mini (
minA
) : adresses minimales par cluster
Définir limitA=maxA
. Itération principale : Initialiser la liste vide possibleSolutions
. Itération externe : pour chaque point p
sur ps
. Initialiser la liste vide pclusters
. Une liste de points à traiter wps=copy(ps)
est défini. Point de travail wp=p
. Itération interne : tandis que wps
n'est pas vide. Retirez le point wp
sur wps
. Déterminez tous les points wpsInRadius
sur wps
qui sont à une distance < r
de wp
. Trier wpsInRadius
de manière ascendante en fonction de la distance de wp
. Gardez le premier min(limitA, sizeOf(wpsInRadius))
points dans wpsInRadius
. Ces points forment un nouveau cluster (liste de points) pcluster
. Ajouter pcluster
à pclusters
. Supprimer les points dans pcluster
de wps
. Si wps
n'est pas vide, wp=wps[0]
et continuer l'itération interne. Fin de l'itération interne. Une liste de clusters pclusters
est obtenu. Ajoutez ceci à possibleSolutions
. Fin de l'itération externe.
Nous avons pour chaque p
sur ps
une liste de clusters pclusters
sur possibleSolutions
. Chaque pclusters
est alors pondéré. Si avgPC
est le nombre moyen de points par cluster dans possibleSolutions
(mondial) et avgCSize
est le nombre moyen de clusters par pclusters
(global), alors c'est la fonction qui utilise ces deux variables pour déterminer le poids :
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);
}
La meilleure solution est maintenant la pclusters
avec le plus petit poids. Nous répétons l'itération principale tant que nous pouvons trouver une meilleure solution (moins de poids) que la meilleure solution précédente avec limitA=max(minA,(int)avgPC)
. Fin de l'itération principale.
Notez que pour les mêmes données d'entrée, cet algorithme produira toujours les mêmes résultats. Les listes sont utilisées pour préserver l'ordre et il y a pas de hasard impliqué.
Pour voir comment cet algorithme se comporte, voici une image du résultat sur une mire de 32 points. Si maxA=minA=16
alors nous trouvons 2 clusters de 16 adresses.
Ensuite, si nous diminuons le nombre minimum d'adresses par cluster en définissant minA=12
nous trouvons 3 groupes de 12/12/8 points.
Et pour démontrer que l'algorithme est loin d'être parfait, voici le résultat avec maxA=7
et pourtant nous avons 6 groupes, dont certains sont petits. Donc, vous devez encore trop deviner lorsque vous déterminez les paramètres. Notez que r
ici, c'est seulement 5.
Par curiosité, j'ai essayé l'algorithme sur un ensemble plus important de points choisis au hasard. J'ai ajouté les images ci-dessous.
Conclusion ? Ce projet m'a pris une demi-journée, il est inefficace, le code est moche et il est relativement lent. Mais cela montre qu'il est possible de produire un peu de résultat dans un court laps de temps. Bien sûr, c'était juste pour s'amuser ; la partie la plus difficile est de transformer cela en quelque chose de réellement utile.