Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

#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 smile )

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


Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

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;

Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

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 smile

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

JD a écrit:

Nice !

Ce post est dans mes favoris smile


Merci wink
(animation faite avec le plugin Timemanager de QGIS 3)

Nico

Hors ligne

 

Pied de page des forums

Powered by FluxBB