Evaluating Clustering Algorithms
DBSCAN stands for density-based spatial clustering of applications with noise.
Starting With the Smallest Possible Run
DBSCAN stands for density-based spatial clustering of applications with noise. It is a clustering algorithm that groups points by how crowded their neighborhoods are, and it can also flag points that belong to no group at all. This article begins with code rather than theory, because the most useful way to understand DBSCAN is to run it and look at what comes back.
DBSCAN()with no arguments uses the default eps andmin_samplesvaluesfit_predictperforms both the fitting and the labeling in one callnp.uniquelists each distinct label once, so the output summarizes the whole result
What do you think happens?
If the printed output is [-1], what has DBSCAN done with the data?
Reveal answer
Every point was labeled as noise, so DBSCAN formed no clusters at all.
The label -1 is reserved for noise. A result containing only -1 means no point satisfied the density rule, so no cluster was born. The source treats this as a signal to adjust parameters, not as evidence about the structure of the data.
How DBSCAN Decides Without a Cluster Count
Many clustering methods ask you to choose the number of clusters before they run. DBSCAN does not. It looks for points that sit in crowded regions of the feature space, where many data points lie close together. These crowded regions are called dense regions. The core idea is that a cluster is a dense region of data, and clusters are separated from one another by regions that are comparatively empty.
DBSCAN has exactly two parameters, and every label it returns is a consequence of them. The first is eps, a distance. Two points count as close when the distance between them is eps or less. The second is min_samples, a count. It is the minimum number of data points that must lie within eps of a given point before that point counts as belonging to a dense region.
eps controls what counts as close. min_samples controls the minimum size of a dense group and how many points end up labeled as noise. Neither parameter sets a number of clusters; the number of clusters is an outcome.
There is a trade-off in exchange for this flexibility. The source notes that DBSCAN is somewhat slower than agglomerative clustering and k-means, although it still scales to relatively large datasets.
Core, Boundary, and Noise Points
After DBSCAN finishes, every point falls into exactly one of three kinds. Core points are dense enough to satisfy the min_samples rule: they have at least min_samples points within eps. Boundary points lie within distance eps of a core point but do not satisfy the rule themselves. Noise points are the rest; they belong to no cluster and receive the label -1.
The distinction between core and boundary points matters for reproducibility. Running DBSCAN repeatedly on the same dataset always gives the same clustering of core points, and the same points are always labeled as noise. A boundary point, however, may sit next to core samples from more than one cluster. Its membership then depends on the order in which points are visited. The source points out that there are usually only a few boundary points, so this dependence is rarely important in practice.
Tracing How One Cluster Grows
DBSCAN does not look at all points at once. It works through the dataset one unvisited point at a time, deciding for each point whether it starts a new cluster, joins an existing one, or is noise. Follow one starting point through this flow. If it lacks enough neighbors, it is set aside as noise and the algorithm moves on. If it has enough neighbors, a cluster is born, and growth proceeds outward through core samples only. A neighbor that is not itself a core sample joins the cluster but does not extend it further.
Read the flowchart as a loop. A cluster grows only when a newly reached point is itself a core sample. A boundary point is reached and labeled, but its own neighbors are not used to pull in further points. This is the mechanism behind the core and boundary distinction from the previous section.
Reading the Labels Array
DBSCAN labels each data point either as noise or as a member of a cluster. Cluster members receive non-negative integer labels such as 0, 1, and 2. Noise points receive the label -1. A result of [-1] therefore means every point was classified as noise and the algorithm formed no clusters. The position of each label in the returned array matches the position of the input point it describes, so labels[i] is the label for the i-th row of the data.
A useful way to think about -1 is that it is not a cluster at all. It is a bin for points that DBSCAN could not place in any density-based group. Because -1 is negative, it cannot be counted directly with a function that only accepts non-negative integers, so the source shifts every label up by one before counting. The noise bin then lands at index 0 of the count array, and the first number in the count is always the number of noise points.
- labels + 1 shifts every label so that the noise bin is non-negative
- counts[0] is the noise bin because -1 has become 0
- counts[1:] gives the size of each real cluster in label order
Common mistake Treating -1 as a real cluster when counting or plotting
Why it failsThe label -1 marks points that belong to no cluster. Including it as an ordinary group distorts the cluster count and sizes.
Do this insteadHandle -1 explicitly, for example by masking it out before summarizing clusters.
Common mistake Using -1 as a direct index into another array
Why it failsPython interprets -1 as the last element, so the lookup silently pulls the wrong row.
Do this insteadSelect noise with a boolean mask such as labels == -1 rather than indexing with the label values.
Changing eps and min_samples
The source uses a two-moons dataset, which consists of two interleaved half-circles. The data is rescaled to zero mean and unit variance before clustering, and DBSCAN runs with its default settings. With those defaults, the source reports that DBSCAN finds the two half-circles and separates them, which is the desired result. The default eps is 0.5.
What do you think happens?
If eps is lowered from 0.5 to 0.2 on the same data, how many clusters do you expect?
Reveal answer
Eight clusters, which the source describes as clearly too many.
A smaller eps means fewer points count as close, so dense regions break into fragments. Raising eps to 0.7 does the opposite and produces one cluster. Changing one number changes the whole answer.
Why lowering min_samples alone was not enough
When every point comes back as noise, which parameter should change first, and what does the source's experiment show?
- 1Identify the two adjustable parameters
eps sets the neighborhood size around each point.
min_samplessets how many points are needed before a group counts as a cluster. - 2Change min_samples first
Lowering
min_sampleslets smaller groups qualify, which seems like the direct fix for an all-noise result. - 3Observe the labels
In the source experiment, lowering
min_samplesalone did not produce any clusters. - 4Increase eps as well
Because the neighborhood also has to reach far enough, eps must increase along with
min_samplesto form clusters.
Change one parameter, observe the labels, and decide what the result tells you before changing the next parameter.
A single trial is rarely enough to choose eps. The source loops over several eps values with min_samples held constant and prints the clusters present and the size of each one. Read that sweep from both directions. At the low end, noise dominates. Near the middle, many small clusters sit alongside a large noise group. At the high end, one big cluster accounts for most of the data. The source observes that there is never more than one large cluster at any setting.
Noise Points as Outliers
Once DBSCAN has produced a result with both noise and clusters, the noise points can be pulled out and examined. The source uses a boolean mask, labels == -1, to select the images DBSCAN labeled as noise. Those images did not fit any dense group. Finding the odd one out in this way is called outlier detection, and DBSCAN can perform it, because noise is simply the set of points that do not belong to a cluster.
- labels == -1 produces a boolean mask over the input points
- Indexing with the mask keeps only the rows DBSCAN labeled as noise
In the source's eps=15 run, DBSCAN produced 27 noise points. Because there were so few, it was practical to inspect every one. Comparing them with typical faces suggested why each was labeled as noise. One image showed a person drinking from a glass, several showed people wearing hats, one had a hand in front of the face, and others had odd angles or crops that were too close or too wide. The source adds that some of these issues can be fixed by better cropping, while others, such as hats or hands in front of faces, must simply be handled by any algorithm applied to this data.
DBSCAN Versus k-Means Cluster Sizes
The source then applies k-means to the same PCA data. The key difference is that k-means must be told how many clusters to produce, and it partitions every point into one of them. With n_clusters set to 10, the source reports cluster sizes ranging from 64 to 386, which it describes as relatively similarly sized. This differs strongly from the DBSCAN result, where cluster sizes were very uneven and noise was present.
| Aspect | DBSCAN | k-means |
|---|---|---|
| Cluster count | Emerges from eps and min_samples | Chosen in advance with n_clusters |
| Every point assigned? | No, points can be noise labeled -1 | Yes, every point is partitioned |
| Cluster sizes | Can be very uneven | Relatively even in the source example |
| Outlier handling | Flags far points as noise | Forces far points into a cluster |
| Speed | Somewhat slower, still scales | Generally faster per the source |
DBSCAN and k-means on the same PCA-transformed faces dataset
The source also notes a consequence of k-means partitioning everything. Points far from a cluster center are still forced into that cluster, so their assignments can look arbitrary. Because k-means has no concept of noise, it cannot flag these points the way DBSCAN does. A larger number of clusters might reveal finer distinctions, but more clusters also make manual inspection harder.
To ask whether two methods agree, the source uses the adjusted Rand index, written ARI. It runs agglomerative clustering with 10 clusters and computes the ARI between its labels and the k-means labels. An ARI of 0.13 indicates the two partitions have little in common. The source reads this as expected, because points far from k-means centers have little in common with each other.
Finding Where a Result Goes Wrong
Most unexpected clustering results trace back to one of a few places in the workflow: the parameter values, the interpretation of labels, or the assumption that a clustering reflects real structure. Work through the pipeline in order and check each stage before blaming the algorithm. The earliest stage that looks wrong is usually where the surprise begins.
- 1Load the data and confirm its shape and feature units.
- 2Scale the features. The source's two-moons example rescales the data to zero mean and unit variance before clustering; features measured in different units can otherwise distort the distances DBSCAN relies on.
- 3Choose eps and
min_samples, starting from the defaults and changing one parameter at a time. - 4Fit the model and read the labels, checking for -1 explicitly.
- 5Count clusters and noise, then inspect the points in each group against what you expect.
Predicting Labels Before Running the Code
A DBSCAN run on your data returns mostly -1 labels, with a few small groups. Before changing anything, predict whether lowering eps or raising min_samples would increase or decrease the number of noise points, and explain your reasoning in terms of the core, boundary, and noise definitions.
Hints
- Recall that eps defines which points count as close.
- Recall that
min_samplesdefines how many neighbors a point needs to be core. - Think about what happens to a boundary point when its core neighbors stop qualifying.
Write a short loop that tries three eps values with min_samples held constant, and prints the number of noise points and the size of each cluster. Predict the direction of change in noise count before you run it, then check the output.
Hints
- Use labels == -1 to count the noise points.
- Use
np.uniquewithreturn_counts=True to get the cluster sizes.
Key Takeaways From the Evaluation
- DBSCAN builds clusters from dense regions, not from a preset cluster count, and it can flag points as noise.
- eps defines closeness and
min_samplesdefines how many neighbors make a point core; together they govern every label. - Core points give stable clusters, boundary points can depend on visit order, and noise points carry the label -1.
- When a result looks wrong, check the parameters and the handling of -1 labels before concluding that the algorithm failed.
At a glance
- DBSCAN groups points by density and proximity and does not need the number of clusters set in advance.
- eps sets the distance for closeness and
min_samplessets the neighbor count needed for a dense region, so both parameters shape every label. - Core samples, boundary points, and noise points are the three kinds of result; noise points carry the label -1.
- Noise points can be selected with labels == -1 as one form of outlier detection.
- An unexpected result usually traces back to parameter values, label handling, or scaling, so check those stages first.