-
Notifications
You must be signed in to change notification settings - Fork 662
[BUG] HDBSCAN treats min_samples as excluding the point itself despite documented inclusive semantics #8545
Description
Describe the bug
cuml.cluster.HDBSCAN labels all samples as noise for a dataset containing two clearly separated three-point clusters when both min_cluster_size=3 and min_samples=3.
cuML returns:
[-1 -1 -1 -1 -1 -1]
The equivalent sklearn.cluster.HDBSCAN call returns the two expected clusters:
[0 0 0 1 1 1]
Both the cuML HDBSCAN documentation and the scikit-learn HDBSCAN documentation state that min_samples includes the point itself. The observed cuML result appears to require an additional neighboring point, which is inconsistent with the documented parameter semantics.
Steps/Code to reproduce bug
cuML reproducer:
import numpy as np from cuml.cluster import HDBSCAN print(HDBSCAN(min_cluster_size=3,min_samples=3,).fit_predict(np.array([[0., 0.],[1., 0.],[0., 1.],[10., 10.],[11., 10.],[10., 11.],])))
Output:
[-1 -1 -1 -1 -1 -1]
For comparison, the equivalent scikit-learn code:
import numpy as np from sklearn.cluster import HDBSCAN print(HDBSCAN(min_cluster_size=3,min_samples=3,).fit_predict(np.array([[0., 0.],[1., 0.],[0., 1.],[10., 10.],[11., 10.],[10., 11.],])))
Output:
[0 0 0 1 1 1]
Expected behavior
With min_cluster_size=3 and min_samples=3, each compact group of three points should be eligible to form a cluster because the min_samples count includes the point itself.
cuML should therefore identify the two separated clusters, equivalent up to label permutation to:
[0 0 0 1 1 1]
It should not mark all six points as noise.
Environment details (please complete the following information):
- Environment location: Docker
- Linux Distro/Architecture: Ubuntu 24.04 / x86_64
- GPU Model/Driver: NVIDIA GeForce RTX 4090 / 595.71.05
- CUDA: 13.2
- Method of cuDF & cuML install: conda
conda list:
conda list
# packages in environment at /opt/conda/envs/rapids-26.08:
#
# Name Version Build Channel
# Name Version Build Channel
python 3.14.6 h242f9ac_102_cp314 conda-forge
numpy 2.4.6 py314h2b28147_0 conda-forge
scipy 1.16.3 py314hf07bd8e_2 conda-forge
scikit-learn 1.9.0 np2py314hf09ca88_0 conda-forge
rapids 26.08.00 cuda13_260806_c2656556 rapidsai
cuml 26.08.00 cuda13_cp311_abi3_260805_265b9da6 rapidsai
libcuml 26.08.00 cuda13_260805_265b9da6 rapidsai
cudf 26.08.00 cuda13_cp311_abi3_260805_ff5b362d rapidsai
libraft 26.08.00 cuda13_260805_ebf92684 rapidsai
libraft-headers 26.08.00 cuda13_260805_ebf92684 rapidsai
pylibraft 26.08.00 cuda13_cp311_abi3_260805_ebf92684 rapidsai
cuvs 26.08.01 cuda13_cp311_abi3_260806_25b1be43 rapidsai
libcuvs 26.08.01 cuda13_260806_25b1be43 rapidsai
cupy 14.1.1 py314hdea9c46_0 conda-forge
cupy-core 14.1.1 py314hcd3b49b_0 conda-forge
numba 0.64.0 py314h8169c2f_0 conda-forge
numba-cuda 0.30.4 py314h42812f9_0 conda-forge
rmm 26.08.00 cuda13_cp311_abi3_260805_42d059f1 rapidsai
librmm 26.08.00 cuda13_260805_42d059f1 rapidsai
cuda-version 13.3 hcbadf70_3 conda-forge
cuda-bindings 13.3.1 py314h42812f9_1 conda-forge
cuda-cudart 13.3.29 hecca717_0 conda-forge
cuda-nvrtc 13.3.33 hecca717_0 conda-forge
libcublas 13.6.0.2 h676940d_0 conda-forge
libcusolver 12.2.6.9 h676940d_0 conda-forge
libcusparse 12.8.2.51 hecca717_0 conda-forge
libcurand 10.4.3.29 h676940d_0 conda-forge
Additional context
The input consists of two identical triangular configurations separated by a large distance:
cluster 1: [0, 0], [1, 0], [0, 1]
cluster 2: [10, 10], [11, 10], [10, 11]
Each group contains exactly three samples, matching min_cluster_size=3. For every point, the neighborhood needed by min_samples=3 consists of the point itself and the two other members of its group.
The cuML documentation describes min_samples as:
The number of samples in a neighborhood for a point to be considered as a core point. This includes the point itself.
Scikit-learn documents the same inclusive behavior. Therefore, passing the same parameter values should not introduce the one-sample offset associated with implementations where min_samples excludes the point itself.
The labels themselves need not use the exact numeric identifiers shown by scikit-learn; any permutation representing two three-point clusters would be correct. The issue is that cuML returns only the noise label -1.