Skip to main content

HDBSCAN

HDBSCAN runs DBSCAN at every eps at once, as single linkage on the mutual reachability distance, then keeps the clusters that last longest. Build the spanning tree, condense it with min_cluster_size, score clusters by stability, and solve the blobs that defeated DBSCAN.
ML03.3.4L2 Intermediate30 min
In review (what this means)

The maths and code on this page are checked by automated tests on every change, but an independent reader has not signed it off yet. Spot a mistake or a confusing step? Tell us.

Before this lesson: ML03.3.3 Many densities at once: OPTICS ML03.2 Hierarchical clustering

What you will be able to do
  • Compute the mutual reachability distance and explain how it pushes sparse points away from everyone.
  • Prove that cutting the minimum spanning tree of mutual reachability at eps gives the DBSCAN* clusters at eps.
  • Condense the hierarchy with min_cluster_size and select clusters by their stability, worked by hand on the twelve points.
  • Fit sklearn.cluster.HDBSCAN, read labels_ and probabilities_, and use it on clusters of different density.

The question

OPTICS showed every density at once, but you still had to read the valleys: by eye, or with a steepness threshold you had to choose. Can an algorithm pick the clusters itself, each at the density that suits it, given only the smallest group you would call a cluster?

From the last lesson

1. What is the reachability distance of \(\vect{o}\) from a core point \(\vect{p}\)?

Show answer

The larger of the core distance of \(\vect{p}\) and the distance \(d(\vect{p}, \vect{o})\): the smallest \(\varepsilon\) at which \(\vect{o}\) is directly density-reachable from \(\vect{p}\).

2. On a reachability plot, what does a horizontal line at \(\varepsilon\) give?

Show answer

The DBSCAN clustering for that \(\varepsilon\), up to a few border points: each run of bars below the line is a cluster.

Intuition

Run DBSCAN at a huge \(\varepsilon\) and everything is one cluster. Lower \(\varepsilon\) slowly: the cluster sheds its loneliest points, splits, shrinks, and in the end every point is alone. Record that history as a tree. A cluster that survives over a long range of \(\varepsilon\) is real; one that flickers in and out is an accident of one setting.

A dendrogram titled single linkage on mutual reachability, with eps on the vertical axis from 0 to 5.5 and the twelve points as leaves along the bottom. Vermillion links merge the lower group's points at heights 1.414 and 2, the upper group's in the same way, the two groups through the bridge point at 2.915, and (9, 1) last at 5.099. Each leaf is a dotted grey line up to its core distance and a solid line above, with a pointer saying dotted: noise at this eps. The lower group is shaded blue and labelled cluster 1 and the upper group sky blue, labelled cluster 2, both shadings running from eps = 1.414 up to 2.915. A dashed orange line at eps = 1.5 is labelled cut at eps = 1.5: DBSCAN* at 1.5.
ML03.3.4-F1

The history of DBSCAN over every \(\varepsilon\), for the twelve points with min_samples = 4. Read any horizontal line as one run of DBSCAN* (DBSCAN without border points). The two shaded groups exist from \(\varepsilon = 2.915\) down to 1.414; HDBSCAN keeps them.

That is HDBSCAN, from Campello, Moulavi and Sander (2013). It needs two numbers you can choose without seeing a single distance: min_samples, as in DBSCAN, and min_cluster_size, the smallest group worth calling a cluster.

Build it up

Step 1. DBSCAN without border points. HDBSCAN uses DBSCAN*: clusters are the connected pieces of the core graph, and every non-core point is noise. Dropping border points removes the order dependence of lesson ML03.3.2 and makes the clusters nest neatly as \(\varepsilon\) changes.

Step 2. One distance for both conditions. Two points are in the same DBSCAN* cluster at \(\varepsilon\) when a chain joins them in which every point is core (\({\operatorname{core} \le \varepsilon}\)) and every step is short (\({d \le \varepsilon}\)). Fold the three conditions into one number, the mutual reachability distance:

\[ \begin{aligned} d_{\text{mr}}(\vect{a}, \vect{b}) = \max\big\{&\operatorname{core}(\vect{a}), \\ &\operatorname{core}(\vect{b}), \\ &d(\vect{a}, \vect{b})\big\}. \end{aligned} \]

In a dense region \(d_{\text{mr}}\) is about the plain distance. A sparse point has a large core distance, and all its distances are raised to at least that: it is pushed away from everyone.

Two panels of the twelve points with the same five edges drawn. Left, titled plain distance d, in blue: (1, 1) to (2, 1) is 1, (2, 2) to (3, 2) is 1, (3, 2) to the bridge is 2.121, the bridge to (6, 5) is 2.121, and (7, 5) to (9, 1) is 4.472. Right, titled mutual reachability, in vermillion: the same edges now read 1.414, 2, 2.915, 2.915 and 5.099.
ML03.3.4-F2

Within a square the distance rises only from 1 to 1.414; the bridge’s links rise from 2.121 to its core distance 2.915, and the link to \((9, 1)\) from 4.472 to 5.099.

Step 3. A spanning tree. Treat \(d_{\text{mr}}\) as edge weights on the complete graph and take its minimum spanning tree: the cheapest set of \(n - 1\) edges that connects every point.

Step 4. Cut it from the top. Remove the tree’s edges from the heaviest down: this is the single-linkage hierarchy of lesson ML03.2.4, run on \(d_{\text{mr}}\). Removing every edge heavier than \(\varepsilon\) leaves the DBSCAN* clusters at \(\varepsilon\).

Step 5. Condense. Most splits are a cluster shedding one or two points. With min_cluster_size \(= s\), a split counts only if both pieces have at least \(s\) points; otherwise the small piece’s points fall out as noise and the cluster carries on under the same name. The result, the condensed tree, has few clusters, each with a birth and with points leaving it over time.

Step 6. Keep the clusters that last. Measure density by \(\lambda = 1/\varepsilon\). A cluster’s stability adds up how long each of its points stayed in it; choose the non-overlapping set of clusters with the largest total stability.

The formal statement

Fix min_samples \(= m\) and write \(\operatorname{core}(\vect{x}) = d_{m-1}(\vect{x})\), so that \(\vect{x}\) is core at \(\varepsilon\) exactly when \(\operatorname{core}(\vect{x}) \le \varepsilon\) (lesson ML03.3.2).

NoteTheorem: single linkage on mutual reachability is DBSCAN* at every eps

For every \(\varepsilon\), delete from a minimum spanning tree of \(d_{\text{mr}}\) every edge heavier than \(\varepsilon\), and call a point with \(\operatorname{core} > \varepsilon\) noise. The pieces that remain, apart from the noise points, are the DBSCAN* clusters at \(\varepsilon\).

Proof. A maximum is at most \(\varepsilon\) exactly when each of its terms is, so

\[ \begin{aligned} &d_{\text{mr}}(\vect{a}, \vect{b}) \le \varepsilon \\ &\iff \operatorname{core}(\vect{a}) \le \varepsilon,\; \operatorname{core}(\vect{b}) \le \varepsilon \\ &\quad\;\text{and } d(\vect{a}, \vect{b}) \le \varepsilon . \end{aligned} \]

The right-hand side says: \(\vect{a}\) and \(\vect{b}\) are both core at \(\varepsilon\) and within \(\varepsilon\), that is, they are joined by an edge of the core graph. So the graph whose edges are the pairs with \(d_{\text{mr}} \le \varepsilon\) is the core graph, and its connected pieces are the DBSCAN* clusters. A point with \(\operatorname{core} > \varepsilon\) has \(d_{\text{mr}} > \varepsilon\) to everyone and is alone: noise.

Finally, two points are connected through pairs with \(d_{\text{mr}} \le \varepsilon\) exactly when they are connected in the spanning tree without its edges heavier than \(\varepsilon\), the property of minimum spanning trees behind lesson ML03.2.4 (proved below). \(\square\)

Go deeper: why the spanning tree keeps every connection below eps

Let \(T\) be a minimum spanning tree of a weighted graph, and suppose \(\vect{a}\) and \(\vect{b}\) are joined by some path of edges of weight at most \(\varepsilon\). The tree path between them could, in principle, use a heavier edge \(e\). Remove \(e\) from \(T\): the tree falls into two parts, with \(\vect{a}\) in one and \(\vect{b}\) in the other. The light path from \(\vect{a}\) to \(\vect{b}\) must cross between the parts somewhere, along an edge \(f\) of weight at most \(\varepsilon\), lighter than \(e\). Then \(T\) with \(e\) replaced by \(f\) is a spanning tree of smaller total weight, which contradicts minimality. So every edge of the tree path weighs at most \(\varepsilon\). The converse is clear, since the tree’s edges are edges of the graph.

Stability. Write \(\lambda = 1/\varepsilon\). A cluster \(C\) of the condensed tree is born at \(\lambda_{\text{birth}}(C)\), when it splits off its parent, and each of its points \(\vect{x}\) leaves it at some \(\lambda_{\vect{x}}\), by falling out or because \(C\) splits or ends. Following Campello et al., its stability is

\[ S(C) = \sum_{\vect{x} \in C} \big(\lambda_{\vect{x}} - \lambda_{\text{birth}}(C)\big). \]

A cluster scores highly when many points stay in it over a long range of densities.

Selection (excess of mass, scikit-learn’s default "eom"). Work up from the leaves, which start selected. At each cluster compare \(S(C)\) with the best total of its descendants: if \(S(C)\) is at least as large, select \(C\) and drop them; otherwise keep them and pass their total up. The root may not win unless allow_single_cluster=True.

Worked example

The twelve points with min_samples = 4 and min_cluster_size = 4.

Mutual reachability. The core distances are the 3-distances: 1.414 for six corners, 1 for \((2, 2)\) and \((7, 6)\), 2 for \((3, 2)\) and \((8, 6)\), 2.915 for the bridge, 5.099 for \((9, 1)\). So two adjacent corners of a square are \(\max(1.414, 1.414, 1) = 1.414\) apart; \((2, 2)\) and \((3, 2)\) are 2; the bridge and \((3, 2)\) are \(\max(2.915, 2, 2.121) = 2.915\), and so are the bridge and \((6, 5)\); \((7, 5)\) and \((9, 1)\) are \(\max(1.414, 5.099, 4.472) = 5.099\).

The spanning tree. Its eleven edges: three of weight 1.414 inside each square, one of weight 2 to each of \((3, 2)\) and \((8, 6)\), two of weight 2.915 through the bridge, and one of 5.099 to \((9, 1)\). Any direct link between the groups is dearer: \((3, 2)\) to \((6, 5)\) costs \(\max(2, 1.414, 4.243) = 4.243\). Ties make the tree not unique (the bridge is 2.915 from five points), but every choice has these weights and the same hierarchy; the figure shows SciPy’s.

The twelve points with the eleven edges of the minimum spanning tree of mutual reachability in vermillion. Solid edges join the corners of each square, labelled 1.414. Dashed edges, labelled with their weights, run from (2, 1) to (3, 2) and from (7, 5) to (8, 6) with weight 2, from (2, 2) and from (6, 5) to the bridge with weight 2.915, and from (6, 5) to (9, 1) with weight 5.099. The core points at eps 1.5 are filled blue; (3, 2), (8, 6), the bridge and (9, 1) are reddish purple rings, labelled noise: core > 1.5. Notes read solid: weight at most 1.5, kept, and dashed: cut at eps = 1.5.
ML03.3.4-F3

Deleting the dashed edges, those heavier than 1.5, leaves the two squares: DBSCAN* at \(\varepsilon = 1.5\), where \((3, 2)\) and \((8, 6)\) are noise rather than border points.

The condensed tree, from \(\lambda = 0\) down.

  • At \(\lambda = 1/5.099 = 0.196\) the edge to \((9, 1)\) goes. A piece of one point is smaller than 4, so \((9, 1)\) falls out and the root carries on with 11 points.
  • At \(\lambda = 1/2.915 = 0.343\) both bridge edges go. The pieces are the lower five, the upper five and the bridge alone. Two pieces have at least 4 points: a true split. Clusters A and B are born; the bridge falls out.
  • At \(\lambda = 1/2 = 0.5\) the edges to \((3, 2)\) and \((8, 6)\) go; each falls out of its cluster.
  • At \(\lambda = 1/1.414 = 0.707\) the square’s three edges go together and A ends with its last four points; B likewise.
A condensed tree drawn as columns, with lambda = 1/eps increasing downwards from 0 to 0.707. A grey root column, 12 points wide, narrows at lambda 0.196 where (9, 1) falls out (eps 5.099), and splits at lambda 0.343 (eps 2.915), where the bridge falls out, into a blue column A and a sky-blue column B, each 5 points wide. Each narrows to 4 at lambda 0.5, where (3, 2) or (8, 6) falls out, and ends at 0.707. Labels give A: stability 1.613, B: stability 1.613, and root: stability 3.969, but never chosen.
ML03.3.4-F4

The condensed tree with min_cluster_size = 4. Column widths count the points still in each cluster. A and B each have stability 1.613.

Stabilities. For A, born at 0.343: \((3, 2)\) stays until 0.5 and the four corners until 0.707, so

\[ \begin{aligned} S(A) &= (0.5 - 0.343) \\ &\quad + 4\,(0.707 - 0.343) \\ &= 0.157 + 1.456 = 1.613 . \end{aligned} \]

\(B\) has the same shape, so \(S(B) = 1.613\). The root, born at 0, keeps \((9, 1)\) until 0.196 and the other eleven until 0.343: \({0.196 + 11 \times 0.343} = 3.969\).

Selection. A and B are leaves, so both are selected. Their parent is the root, which is not allowed to win by default; the answer is A and B. (With allow_single_cluster=True the root’s 3.969 beats the 3.227 of A and B together, and the answer is one cluster of eleven with \((9, 1)\) as noise.) Points that fell out of a selected cluster, like \((3, 2)\), keep its label: two clusters of five, as DBSCAN found. Each point also gets a membership strength, probabilities_: for these points it is the point’s \(\lambda_{\vect{x}}\) over the largest \(\lambda\) in its cluster, so \((3, 2)\) gets \({0.5 / 0.707} = 0.707\) and the corners 1.

The bridge. Its two edges tie at 2.915. Removed together, they leave the bridge alone: noise. scikit-learn 1.9 returns it instead as A’s weakest member, with probability \({0.343 / 0.707} = 0.49\), as if it left A at the moment A was born. The other ten points do not depend on the tie.

Code

From scratch as far as the spanning tree, then the cut at \(\varepsilon = 1.5\), checked against DBSCAN’s core points.

import numpy as np
from scipy.sparse.csgraph import connected_components, minimum_spanning_tree
from sklearn.cluster import DBSCAN, HDBSCAN

X = np.array([(1, 1), (2, 1), (1, 2), (2, 2), (3, 2), (6, 5), (7, 5), (6, 6),
              (7, 6), (8, 6), (4.5, 3.5), (9, 1)], dtype=float)

D = np.sqrt(((X[:, None, :] - X[None, :, :]) ** 2).sum(axis=-1))
core = np.sort(D, axis=1)[:, 3]                         # min_samples = 4
M = np.maximum(np.maximum(core[:, None], core[None, :]), D)
np.fill_diagonal(M, 0)

T = minimum_spanning_tree(M).toarray()
weights = np.sort(T[T > 0])
print("tree edge weights:", np.round(weights, 3))

eps = 1.5
kept = np.where(T <= eps, T, 0)                          # delete the edges heavier than eps
_, piece = connected_components(kept, directed=False)
is_core = core <= eps
print("DBSCAN* pieces of the core points:", piece[is_core])
tree edge weights: [1.414 1.414 1.414 1.414 1.414 1.414 2.    2.    2.915 2.915 5.099]
DBSCAN* pieces of the core points: [0 0 0 0 2 2 2 2]

The stabilities of the worked example, from the \(\lambda\) at which points leave:

lam = 1 / np.array([np.sqrt(26), np.sqrt(8.5), 2.0, np.sqrt(2)])   # 0.196, 0.343, 0.5, 0.707
S_A = (lam[2] - lam[1]) + 4 * (lam[3] - lam[1])
S_root = lam[0] + 11 * lam[1]
print(f"S(A) = S(B) = {S_A:.3f},  S(root) = {S_root:.3f}")

h = HDBSCAN(min_cluster_size=4, min_samples=4, copy=True).fit(X)
print("labels_:", h.labels_)
print("probabilities_:", np.round(h.probabilities_, 3))
one = HDBSCAN(min_cluster_size=4, min_samples=4, allow_single_cluster=True, copy=True).fit(X)
print("allow_single_cluster:", one.labels_)
S(A) = S(B) = 1.613,  S(root) = 3.969
labels_: [ 0  0  0  0  0  1  1  1  1  1  0 -1]
probabilities_: [1.    1.    1.    1.    0.707 1.    1.    1.    1.    0.707 0.485 0.   ]
allow_single_cluster: [ 0  0  0  0  0  0  0  0  0  0  0 -1]

Now the blobs of two densities, where no single eps worked.

from sklearn.datasets import make_blobs

Xb, yb = make_blobs(n_samples=[100, 100, 100], centers=[(0, 0), (1.2, 0), (4.5, 3)],
                    cluster_std=[0.15, 0.15, 1.5], random_state=1)
hb = HDBSCAN(min_cluster_size=20, min_samples=5, copy=True).fit(Xb)
table = [[int(((yb == g) & (hb.labels_ == k)).sum()) for k in range(hb.labels_.max() + 1)] for g in range(3)]
print("clusters:", hb.labels_.max() + 1, " noise:", (hb.labels_ == -1).sum())
print("blob by cluster:", table)
clusters: 3  noise: 6
blob by cluster: [[0, 0, 100], [0, 100, 0], [92, 2, 0]]

Three clusters: each tight blob whole, and 92 of the sparse blob’s points together (two join a tight blob, six are noise). Each blob was found at its own density.

Explore

The module’s DBSCAN explorer is in lesson ML03.3.2. Sweep its eps from large to small with min_samples = 4: one group above 2.915, two below, and below 1.414 the outer corners stop being core, where the condensed tree ends each cluster.

Pitfalls

Two panels of the twelve points. Left, marked with a cross and titled single linkage, 2 clusters: vermillion links run from (3, 2) to the bridge and on to (6, 5); eleven points are blue circles in one cluster, labelled chained through the bridge (2.121), and (9, 1) alone is a sky-blue square, labelled a cluster of one. Right, marked with a tick and titled HDBSCAN: the lower group in blue circles and the upper group in sky-blue squares, with (3, 2), (8, 6) and the bridge drawn small; the bridge is labelled weakest member, probability 0.49, and (9, 1) is a reddish purple noise ring.
ML03.3.4-F5

Wrong beside right. Single linkage on plain distances chains the groups through the bridge; HDBSCAN keeps them apart and calls \((9, 1)\) noise.

“HDBSCAN is just single linkage, so it chains like single linkage.”

Single linkage on plain distances merges the groups at 2.121 and calls \((9, 1)\) a cluster of one. Mutual reachability raises the links of sparse points, so a chain of strays joins groups only at a large \(\varepsilon\), and min_cluster_size turns one-point splits into points falling out.

“min_samples and min_cluster_size are the same knob.”

min_samples sets the core distances, and so how readily points become noise; min_cluster_size decides which splits count. scikit-learn sets min_samples to min_cluster_size by default: on the blobs, 20 instead of 5 raises the noise from 6 points to 16.

“probabilities_ are probabilities of belonging to the cluster.”

They are relative strengths: the density \(\lambda_{\vect{x}}\) up to which a point stayed, as a share of the largest \(\lambda\) reached in its cluster. They are not calibrated and do not sum to 1 over clusters.

Check yourself

Recall

1. Write the mutual reachability distance between \(\vect{a}\) and \(\vect{b}\).

Show answer

The largest of the two core distances and the distance between the points:

\[ \begin{aligned} d_{\text{mr}}(\vect{a}, \vect{b}) = \max\big\{&\operatorname{core}(\vect{a}), \\ &\operatorname{core}(\vect{b}), \\ &d(\vect{a}, \vect{b})\big\}. \end{aligned} \]

2. How does DBSCAN* differ from DBSCAN?

Show answer

It has no border points: every non-core point is noise, and clusters are the connected pieces of the core graph.

3. What happens in the condensed tree when a cluster splits into a piece of 10 points and a piece of 2, with min_cluster_size = 5?

Show answer

Not a true split: the 2 points fall out as noise and the cluster carries on with the 10.

4. Write the stability of a cluster \(C\).

Show answer

The sum over its points of how long each stayed, measured in \(\lambda = 1/\varepsilon\):

\[ S(C) = \sum_{\vect{x} \in C} \big(\lambda_{\vect{x}} - \lambda_{\text{birth}}(C)\big). \]

5. On the twelve points with min_samples = 4 and min_cluster_size = 4, what are the stabilities of the two clusters and why does the root, with a larger stability, not win?

Show answer

Each has stability 1.613; the root has 3.969. By default the root is never selected; allow_single_cluster=True lets it win.

Exercises

1. ★ Two points are 1 apart, with core distances 0.5 and 2. A third point is 3 from the first and has core distance 0.5. Give the two mutual reachability distances from the first point.

Show solution

To the second point: \(\max(0.5, 2, 1) = 2\). The second point is sparse, so its link is raised to its core distance.

To the third point: \(\max(0.5, 0.5, 3) = 3\). Both are dense, and the plain distance decides.

2. ★★ In a condensed tree, cluster P (stability 2.0) splits into Q (0.8) and R (0.9), and Q later splits into Q1 (0.6) and Q2 (0.7). Q1, Q2 and R have no children, and P is not the root. Which clusters does the excess-of-mass rule select?

Show solution

Work from the leaves up. Q1, Q2 and R are leaves and start selected.

At Q: its own stability is 0.8, its children’s total is \({0.6 + 0.7} = 1.3\). The children win: keep Q1 and Q2 and pass up 1.3 as Q’s value.

At P: its own stability is 2.0; the best its descendants achieve is \({1.3 + 0.9} = 2.2\). The descendants win again.

The selection is Q1, Q2 and R. (With R at 0.6 the descendants would total 1.9, and P would win.)

3. ★★★ Show that the mutual reachability distance obeys the triangle inequality:

\[ d_{\text{mr}}(\vect{a}, \vect{c}) \le d_{\text{mr}}(\vect{a}, \vect{b}) + d_{\text{mr}}(\vect{b}, \vect{c}). \]

Show solution

The left side is the largest of three terms. It is enough to show each is at most the right side, which we call \(R\). Every term of a maximum is at most the maximum, so \(\operatorname{core}(\vect{a}) \le d_{\text{mr}}(\vect{a}, \vect{b})\) and \(\operatorname{core}(\vect{c}) \le d_{\text{mr}}(\vect{b}, \vect{c})\), and also \(d(\vect{a}, \vect{b}) \le d_{\text{mr}}(\vect{a}, \vect{b})\) and \(d(\vect{b}, \vect{c}) \le d_{\text{mr}}(\vect{b}, \vect{c})\). Distances are not negative, so:

  • \(\operatorname{core}(\vect{a}) \le d_{\text{mr}}(\vect{a}, \vect{b}) \le R\);
  • \(\operatorname{core}(\vect{c}) \le d_{\text{mr}}(\vect{b}, \vect{c}) \le R\);
  • by the triangle inequality for \(d\), the distance \(d(\vect{a}, \vect{c})\) is at most \({d(\vect{a}, \vect{b}) + d(\vect{b}, \vect{c})}\), which is at most \(R\).

All three terms are at most \(R\), so their maximum is too.

Summary card

Run DBSCAN* at every eps as single linkage on mutual reachability, and keep the clusters that last.

The anchor figure again: the single-linkage dendrogram of the twelve points on mutual reachability, with the two shaded clusters lasting from eps 2.915 down to 1.414 and a cut at eps = 1.5.
ML03.3.4-F1

The hierarchy of every eps.

  • Mutual reachability. \(d_{\text{mr}}(\vect{a}, \vect{b})\) is the largest of the two core distances and \(d(\vect{a}, \vect{b})\).
  • Theorem. Cut the spanning tree of \(d_{\text{mr}}\) at \(\varepsilon\): the pieces are DBSCAN* at \(\varepsilon\).
  • Condense with min_cluster_size; score each cluster by its stability \(S(C)\); keep the most stable set.
  • In code. HDBSCAN(min_cluster_size, min_samples): labels_ with \(-1\) for noise, probabilities_.

Sources and next steps

Sources. Each was opened and checked against this lesson on 15 November 2026.

  • Ricardo J. G. B. Campello, Davoud Moulavi and Jörg Sander, Density-based clustering based on hierarchical density estimates, PAKDD 2013, Lecture Notes in Computer Science 7819, pages 160 to 172; repository record with abstract. The abstract states the method: a cluster hierarchy, a simplified tree of significant clusters, a stability measure, and an optimal selection of the most stable flat partition. The full text is not open; the details were checked in the next two sources.
  • scikit-learn developers, User Guide, section 2.3.8 HDBSCAN, version 1.9: the core distance to the min_samples-th neighbour counting the point itself, the mutual reachability distance, connected components of the trimmed graph as DBSCAN*, and the minimum spanning tree cut from its heaviest edges; and the sklearn.cluster.HDBSCAN API page: min_samples defaults to min_cluster_size, allow_single_cluster=False, the "eom" selection, labels_ and probabilities_.
  • How HDBSCAN works, documentation of the hdbscan library (scikit-learn-contrib): mutual reachability, the spanning tree, condensing with a minimum cluster size (points “falling out”), \(\lambda = 1/\text{distance}\), the stability \(\sum (\lambda_p - \lambda_{\text{birth}})\) and the bottom-up selection rule.

Next. Gaussian mixtures (module ML03.4) model each cluster as a density with a formula, and anomaly detection (module ML03.9) turns “noise” into a score.

This lesson unlocks

ML03.4 Gaussian mixtures and the EM algorithm ML03.9 Anomaly detection

Your progress is saved in this browser only. No account, no tracking.
Back to top