TDA To Rule Them All: ToMATo Clustering | by Meryll Dindin | Towards Data Science

Do you miss applied mathematics ? Once again, my goal is to promote Topological Data Analysis and the multiple possibilities it offers. The previous article mentioned machine-learning and deep-learning, but there is a field among others in which TDA find purposes: clustering.
towardsdatascience.com
The concept of clustering powered by TDA has been introduced into the (not so) famous ToMATo (Topological Mode Analysis Tool) algorithm, introduced in this paper. This algorithm has two strengths, compared to more usual (scikit-learn kind) clustering algorithms:
It gives you a way to know how many clusters your data seems to have;
It gives you a way to gather this data into distinct sets for clustering.
I developed the code relative to this article as a proof of concept, and there are surely elements that may be improved ! Do not ditch taking a look, and I’ll be happy to receive your critics ;) !
For explanation purposes, I will limit myself to two-dimensional considerations. The core idea is to apply TDA on the density estimate of our data points, to extract its maxima, and thus extract its apparent centroids. Great, but how ?
To get back to practical TDA, you’ll need to build the simplex tree* (nested family of simplicial complex*, ending up in basically being a graph), corresponding to that density function.
First, compute the density estimate and initialize the structure;
Second, give an index to every point of your data set;
Third, insert each data point through their index into your simplex tree by attributing them the corresponding density value as filtration* value;
Fourth, link each point to its neighborhood graph through their averaged filtration values.
You end up with an instantiated graph and you can compute the corresponding persistence by upper-levels filtering (~ defines the nested family of simplicial complex through a decreasing ordering of the obtained filtration values), for which further illustrations are given on my Github repository.
(*) See Below for Concept Explanations
By computing the persistence diagram (and persistence barcode) of such filtration, you obtain something like that:
gen = ClusterGenerator(structure=’anisotropy’, randomize=45)clf = ToMaTo(*gen.generate())_ = clf.estimate_clusters(graph=True)
The previous results gives you real insights about the data: Two elements do show off of the diagonal, corresponding to objects with the biggest persistence. Persistence, in this case, characterizes how much the structure that has been created is difficult to overlap in your graph. It basically refers to global maxima (for upper-levels filtering) or global minima (for sub-levels filtering). In our case, we just observe that your data owns two centroids, corresponding to two density peaks. Now, you need to link each data point to those two centroids to build your distinct clusters. This is achievable thanks to an UnionFind structure (disjoint-set data structure), and follows the idea presented in the algorithm below.
The concept is solely based on the decreasing order of the filtration values. A good point is that you will just need a one-pass over all your data points. For each ordered data point, you then have two possibilities:
either it has no neighbors that do have higher filtration values, then it is considered as a local density maximum;
nor it has, and you need to look over the different neighbors, and merge the roots to link that same edge to its corresponding root of heaviest weight (the closer to a given centroid, the higher the weight is).
To avoid the creation of multiple clusters, there is a condition over the filtration values given by tau, which makes sure small clusters will be linked to bigger ones. Pythonized, it gives you the following (extracted from a larger function, explaining the object methods):
After comparing the different roots/parents of each data point:
gen = ClusterGenerator(structure='moons', randomize=45)clf = ToMaTo(*gen.generate())_ = clf.estimate_density(graph=False)clf.estimate_clusters(graph=False)prd = clf.fit_predict(num_clusters=2, graph=True)
Other examples are provided in my Github repository, as the one dealing with anisotrope data, that k-means (one of the most commonly used clustering algorithm) has troubles to cluster (see scikit-learn example).
gen = ClusterGenerator(structure='anisotropy', randomize=45)clf = ToMaTo(*gen.generate())_ = clf.estimate_density(graph=False)clf.estimate_clusters(graph=False)prd = clf.fit_predict(num_clusters=3, graph=True)
For the ones interested about the inherent theory and its mathematical formalism, here are some elements that may talk to you.
There are lots of possibilities emerging from this theory, and the interface between those results and deep-learning are currently still under development. Lots of ideas are to come, which make the topic hot and really interesting ! Stay tuned for the incoming articles, and clap if you want more ;) !
Gudhi package
Persistence-Based Clustering in Riemannian Manifolds
The Simplex Tree: An Efficient Data Structure for General Simplicial Complexes