Pages: 1
- Sujet précédent - Identification d'un groupe de points les plus proches entre eux - Sujet suivant
#1 Sun 10 May 2020 10:40
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Identification d'un groupe de points les plus proches entre eux
Bonjour à tous,
Je cherche à créer un polygone (sans trou et d'un seul tenant) qui regroupe X pourcents de points issus d'une même table.
Le polygone à créer doit regrouper les points les plus proches ENTRE EUX. En conséquence, je ne vois pas comment utiliser les fonctions dérivées de st_cluster telles que ST_ClusterDBSCAN ou ST_ClusterKMeans car ma contrainte n'est pas une distance en tant que telle ou un nombre de clusters.
Cela me fait penser à une classe issue d'une classification ascendante hiérarchique mais je sèche complètement pour la requête à effectuer.
Auriez-vous des pistes à me donner svp ? Je vous remercie par avance pour votre aide.
Hors ligne
#2 Mon 11 May 2020 09:56
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1549
Re: Identification d'un groupe de points les plus proches entre eux
Bonjour,
Quels sont les critères pour retenir X % des points de la table ? Plus proches à combien par exemple ?
Peut etre un exemple graphique pourrait aider.
Nicolas
Hors ligne
#3 Mon 11 May 2020 11:01
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Re: Identification d'un groupe de points les plus proches entre eux
Bonjour,
Concernant les X%, l'idée n'est pas d'avoir un critère en particulier. L'idée est justement que l'utilisateur puisse fixer ce pourcentage lui-même.
L'objectif est véritablement d'avoir le plus petit polygone qui regroupe un certain pourcentage des objets présents dans la table et que les objets pris en compte pour constituer ce polygone soient les plus proches entre eux. Le critère est donc la proximité des points entre eux et non par rapport à un point qui sert de référence de manière permanente.
J'imagine qu'il faut mettre en place une fonction avec un loop.
- D'abord on identifie les distances de l'ensemble des couples. Imaginons que nous ayons une table composée de 100 objets, le plus petit polygone qui entoure les deux points les plus proches est le cluster qui regroupe 2% des objets.
- Ensuite on ajoute un troisième objet et on fait la somme des distances entre les trois objets. Si on reprend notre exemple, le plus petit polygone qui entoure le "trouple" dont la somme des distances a la plus petite valeur est le cluster qui regroupe 3% des objets. Nota bene, le trouple ayant la plus petite somme des distances n'est pas forcément issu du couple qui était séparé par la plus petite distance.
- Et on continue à identifier la plus petite somme des distances jusqu'à atteindre le polygone qui regroupe les X% souhaités.
PS : Certains points de la table de référence peuvent être superposés donc, dans les plus petits pourcentages, il est possible qu'il y ait plusieurs couples ou trouples dont la somme des distances est nulle...
Hors ligne
#4 Mon 11 May 2020 13:07
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1549
Re: Identification d'un groupe de points les plus proches entre eux
Ok je vois mieux (enfin je sais pas )
Peut etre avec une CTE récursive, style brute force:
• On prend chaque point comme point de départ d'un cluster potentiel: cluster de multipoints donc
• A chaque itération, on cherche le point le plus proche de notre cluster, on l'ajoute au cluster, on fait la somme des distances pour ce cluster.
• On stocke les ids déjà trouvés dans un tableau histoire de ne pas rechercher parmi des points du cluster
• On s'arrete quand on a construit des clusters ayant le nbre de points requis (qui peut etre le pourcentage du nbre de points dans la table, comme dans l'exemple ci-dessous.
• On prend alors le cluster ayant la somme de distance la plus petite comme bon cluster, on peut construire son convexHull.
En SQL: (ma table de test a 68 points, cf. Image)
Note: Le code utilise l'extension intarray pour classer le tableau des ids des points et eviter ainsi des doublons, mais c'est complètement optionnel en fait:
order by sumdist limit 1 renverra toujours le cluster avec la plus petite somme de distance, peu importe l'ordre des identifiants dans le tableau des ids composant le cluster
Code:
with recursive clusters(idcluster, ids, step, maxpts, sumdist, geom) as ( select gid as idcluster, array[gid] as ids, 1 as step, (select round(count(*) * 0.05)::int as numpts from testpt) as maxpts, 0.0::float as sumdist, st_multi(geom)::geometry(MULTIPOINT, 0) as geom from testpt UNION ALL select c.idcluster, c.ids || t.gid, step+1, c.maxpts, c.sumdist + t.dist, st_multi(st_union(c.geom, t.geom))::geometry(MULTIPOINT, 0) as geom from clusters c cross join lateral ( select tp.gid, c.geom <-> tp.geom as dist, tp.geom from testpt tp where not(tp.gid = any(c.ids)) order by c.geom <-> tp.geom limit 1 ) as t where c.step <= maxpts - 1 ) select sort(ids) as ids, sumdist, st_convexhull(geom) as geom from clusters where step = maxpts group by sort(ids), 2, 3 order by sumdist;
Sur l'image, les convexhulls pour 6, 7 et 8 points dans le cluster
Nicolas
Hors ligne
#5 Mon 11 May 2020 13:43
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Re: Identification d'un groupe de points les plus proches entre eux
Bonjour,
Le résultat que vous mettez en pièce jointe est exactement ce que je cherchais à produire, mais je ne connaissais notamment pas le WITH RECURSIVE.
Un grand MERCI pour votre aide.
Hors ligne
#6 Mon 11 May 2020 14:52
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1549
Re: Identification d'un groupe de points les plus proches entre eux
Oui c'est pratique cette construction itérative, ca permet de faire des boucles, ou de parcourir des arbres. (https://www.postgresql.org/docs/11/queries-with.html)
Pour avoir le convexhull pour 3, 4, 5...n points par cluster (ici 50):
Code:
with recursive clusters(idcluster, ids, step, maxpts, sumdist, geom) as ( select gid as idcluster, array[gid] as ids, 1 as step, -- (select round(count(*) * 0.1)::int as numpts from testpt) as maxpts, 50 as maxpts, 0.0::float as sumdist, st_multi(geom)::geometry(MULTIPOINT, 0) as geom from testpt UNION ALL select c.idcluster, c.ids || t.gid, step+1, c.maxpts, c.sumdist + t.dist, st_multi(st_union(c.geom, t.geom))::geometry(MULTIPOINT, 0) as geom from clusters c cross join lateral ( select tp.gid, c.geom <-> tp.geom as dist, tp.geom from testpt tp where not(tp.gid = any(c.ids)) order by c.geom <-> tp.geom limit 1 ) as t where c.step <= maxpts - 1 ), tmp as ( select ids, step, sumdist, geom, row_number() over (partition by step order by sumdist) as rn from clusters where step > 2 ) select row_number() over () as clusterid, step, sumdist, st_setSRID(st_convexhull(geom), 4326)::geometry(polygon, 4326) as geom from tmp where rn = 1;
Hors ligne
#7 Mon 11 May 2020 15:06
- JD
- Moderateur
- Date d'inscription: 8 Aug 2013
- Messages: 726
Re: Identification d'un groupe de points les plus proches entre eux
Nice !
Ce post est dans mes favoris
Hors ligne
#8 Mon 11 May 2020 15:12
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1549
Re: Identification d'un groupe de points les plus proches entre eux
Nice !
Ce post est dans mes favoris
Merci
(animation faite avec le plugin Timemanager de QGIS 3)
Nico
Hors ligne
Pages: 1
- Sujet précédent - Identification d'un groupe de points les plus proches entre eux - Sujet suivant