2017-11-20 3 views
2

Ich habe eine Reihe von Punkten (~ 1000) und eine Reihe von Cluster-Zentren (~ 100). Ich möchte nun die Menge der Punkte unter Berücksichtigung der bereits bekannten Clusterzentren zusammenfassen. Alle Cluster sollten von den bereits bekannten Clusterzentren ausgehen, die nach außen wachsen und alle Punkte sammeln, die weniger als x Meter von dem nächsten Punkt entfernt sind, der sich bereits innerhalb des Clusters befindet.Clustering Punkte um bereits bekannte Cluster-Zentren

Ich habe jetzt die folgenden ziemlich Standard PostGIS DBSCAN query:

WITH clusters AS (
    SELECT 
    landmark_id, coordinate, 
    ST_ClusterDBSCAN(coordinate, eps := (30/111111.0), minpoints := 10) OVER() AS cluster_id 
    FROM landmarks 
    WHERE coordinate IS NOT NULL 
) 
SELECT 
    cluster.id, cluster.landmark_ids, 
    ST_Centroid(cluster.geometry) AS coordinate, 
    ST_AsGeoJSON(cluster.geometry) AS geometry 
FROM (
    SELECT 
    cluster_id AS id, 
    array_agg(landmark_id) AS landmark_ids, 
    ST_ConvexHull(ST_Collect(coordinate)) AS geometry 
    FROM clusters 
    WHERE cluster_id IS NOT NULL 
    GROUP BY cluster_id 
) AS cluster; 

Alle Hinweise, wie ich die obige Abfrage anpassen kann oder eine andere Abfrage schreiben zu tun, was ich zu prozeduralen Code ohne Rückgriff wollen (wenn ja würde ich schätze auch einige Hinweise)?

Antwort

1

Schon im Cluster war ich nicht sicher, ob Sie diejenigen gemeint hatten, die vom ersten Cluster aufgenommen wurden oder diejenigen, die Sie rekursiv abholen würden.

Diese Lösung vergleicht nur mit dem ursprünglichen Cluster, versucht nicht basierend auf rekursivem Clusterabgleich. Das würde eine rekursive Abfrage erfordern, und ich frage, ob es bessere Antworten geben würde.

Auch nicht sicher, warum Sie sich entschieden haben, mit Convexhull zu gehen, um Ihren Schwerpunkt gegen zu berechnen, würde ich annehmen, dass Sie den wahren Schwerpunkt, der gegen die Ausgabe ST_Collect getan werden kann.

WITH cluster1 AS (
    SELECT 
    landmark_id, coordinate, 
    ST_ClusterDBSCAN(coordinate, eps := (30/111111.0), minpoints := 10) OVER() AS cluster_id 
    FROM landmarks 
    WHERE coordinate IS NOT NULL 
), 
clustered AS (SELECT * FROM cluster1 WHERE cluster_id IS NOT NULL) 
clusterall AS (
SELECT 
    l.landmark_id, l.coordinate, c.cluster_id 
FROM landmarks AS l 
    CROSS JOIN 
    -- find closest cluster 
     LATERAL (SELECT cluster_id 
       FROM clustered AS c 
      ORDER BY c.coordinate <-> l.coordinate LIMIT 1) AS c 
    -- only look for landmarks not matched to a cluster 
    WHERE l.landmark_id NOT IN(SELECT c.landmark_id FROM clustered AS c) 
UNION ALL 
SELECT c.landmark_id, c.coordinate, c.cluster_id 
    FROM cluster1 
) 
SELECT 
    cluster.id, cluster.landmark_ids, 
    ST_Centroid(cluster.geometry) AS coordinate, 
    ST_AsGeoJSON(cluster.geometry) AS geometry 
FROM (
    SELECT 
    cluster_id AS id, 
    array_agg(landmark_id) AS landmark_ids, 
    ST_ConvexHull(ST_Collect(coordinate)) AS geometry 
    FROM clusterall 
    GROUP BY cluster_id 
) AS cluster; 
+0

Ich bin mir nicht sicher, ob das, was ich will, noch Clustering genannt werden kann. Grundsätzlich sollte es so funktionieren: *** 1) *** Von einem bestimmten Punkt aus nach außen wachsen und alle Punkte x Meter oder weniger von diesem Punkt sammeln. *** 2) *** Von allen neu gesammelten Punkten, wiederhole 1. Dies wird so lange fortgesetzt, bis keine Punkte mehr innerhalb von x Metern von den zuletzt hinzugefügten Punkten übrig sind. (Dies scheint dort zu sein, wo Rekursion stattfindet) *** 3) *** Nachdem es fertig ist, erstelle ich aus allen gesammelten Punkten eine konvexe Hülle. Ich muss immer noch sehen, welchen Schwerpunkt ich verwenden möchte. –