[GIS] Clustering geographic points

clusteringpostgisshapely

I have a bunch of thousands of points.
I'd like to group them, in a user-defined number of clusters for example or based on some kind of "best number of clusters", based for example on their relatives distances.
Which kind of algorithm is available on postGIS and/or shapely (preferred) to do that?
I can simply make some buffers around them and a union but I wonder if there is some other advanced technique that are computationally efficient on large dataset.

Edit:

I've found the DBSCAN algorithm [1] interesting and it seems rather simple to insert in an existing code. There is also the OPTICS algorithm [2] but it seems harder to find a solution.

[1]https://en.wikipedia.org/wiki/DBSCAN
[2]https://en.wikipedia.org/wiki/OPTICS_algorithm

Anyway, I'm stuck with DBSCAN now.

How to store the cluster label in which a point lays within a new column cluster in a PostgreSQL table? Actually, the points ID are not stored along their coordinates within the cluster…
Some checking operations on coordinates in order to retrieve points IDs in original array would be a bit overrated, in my opinion.

Best Answer

I assume from your question that your points have some kind of natural clustering. You can use the ST_ClusterDBSCAN function to try to assign cluster id's to every point. Since this is a window function, you will have to group the points together youself later on.

Here is an example use case: Say you have clusters of trees where some of them would be seen as a forest and some of them are just small patches of trees, depending on how many trees are together and close they are to eachother. There should be at least 100 trees to call it a forest and they should be no more than 10 meters apart. Your cluster function would look like: ST_ClusterDBSCAN(geom, eps := 10, minpoints := 100)

The result would be a cluster id and one step later you can aggregate these points into whatever you like (e.g.

WITH clusters AS (
  SELECT ST_ClusterDBSCAN(geom, eps := 10, minpoints := 100) as clusterid, geom 
  FROM mybigtable
)
SELECT clusterid, ST_Collect(geom) as cluster_geometry FROM clusters GROUP BY clusterid

).

Now it is up to you to play with the parameters to find the right clusters. Keep in mind that this algorithm assumes a normal distribution for every clusters, so it wouldn't work if every cluster has different eps and minpoints parameters.

Related Question