Vous pouvez utiliser le regroupement hiérarchique. C'est une approche plutôt basique, donc il existe de nombreuses implémentations disponibles. Par exemple, il est inclus dans scipy de Python.
Voyez par exemple le script suivant :
import matplotlib.pyplot as plt
import numpy
import scipy.cluster.hierarchy as hcluster
# générer 3 clusters de 100 points environ et un point orphelin
N=100
data = numpy.random.randn(3*N,2)
data[:N] += 5
data[-N:] += 10
data[-1:] -= 20
# regroupement
thresh = 1.5
clusters = hcluster.fclusterdata(data, thresh, criterion="distance")
# tracé
plt.scatter(*numpy.transpose(data), c=clusters)
plt.axis("equal")
title = "seuil : %f, nombre de clusters : %d" % (thresh, len(set(clusters)))
plt.title(title)
plt.show()
Ce qui produit un résultat similaire à l'image suivante.
Le seuil donné en tant que paramètre est une valeur de distance sur la base de laquelle la décision est prise quant à savoir si les points / clusters seront fusionnés en un autre cluster. La métrique de distance utilisée peut également être spécifiée.
Notez qu'il existe diverses méthodes pour calculer la similarité intra-/inter-cluster, par exemple la distance entre les points les plus proches, la distance entre les points les plus éloignés, la distance aux centres des clusters, etc. Certaines de ces méthodes sont également prises en charge par le module de regroupement hiérarchique de scipy (liaison simple/complète/moyenne...). Selon votre message, je pense que vous voudriez utiliser le regroupement à liaison complète.
Remarquez que cette approche permet également des petits clusters (un seul point) s'ils ne remplissent pas le critère de similarité des autres clusters, c'est-à-dire le seuil de distance.
Il existe d'autres algorithmes qui fonctionneront mieux, ce qui sera pertinent dans des situations avec beaucoup de points de données. Comme le suggèrent d'autres réponses/commentaires, vous voudrez peut-être également regarder l'algorithme DBSCAN :
Pour un bel aperçu de ces algorithmes et d'autres, jetez également un œil à cette page de démonstration (de la bibliothèque scikit-learn de Python) :
Image copiée de cet endroit :
Comme vous pouvez le voir, chaque algorithme fait certaines hypothèses sur le nombre et la forme des clusters qui doivent être pris en compte. Que ce soit des hypothèses implicites imposées par l'algorithme ou des hypothèses explicites spécifiées par la paramétrisation.