Skip to content

Commit 5525348

Browse files
Select the core distance instead of sorting each row
Only the min_samples-th smallest distance per row is needed. Sorting the whole row made it the dominant cost of the whole algorithm: 5.4s of 6.3s on a 4969 point dataset.
1 parent b1a9a5a commit 5525348

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

lib/scholar/cluster/hdbscan.ex

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,19 @@ defmodule Scholar.Cluster.HDBSCAN do
178178
# overflows, and on an unsigned one the subtraction wraps, which makes the matrix
179179
# asymmetric and the clustering meaningless. Floating point first.
180180
distances = metric.(to_float(x), to_float(x))
181-
core = Nx.sort(distances, axis: 1)[[.., min_samples - 1]]
181+
182+
# Only the min_samples-th smallest distance in each row is needed, so select it
183+
# rather than sorting the whole row. `min_samples` is validated to be at most the
184+
# number of samples above, so `k` is always in range. Negated because `top_k/2`
185+
# takes the largest.
186+
core =
187+
distances
188+
|> Nx.negate()
189+
|> Nx.top_k(k: min_samples)
190+
|> elem(0)
191+
|> Nx.negate()
192+
|> Nx.slice_along_axis(min_samples - 1, 1, axis: 1)
193+
|> Nx.squeeze(axes: [1])
182194

183195
Nx.max(Nx.max(Nx.new_axis(core, 1), Nx.new_axis(core, 0)), distances)
184196
end

0 commit comments

Comments
 (0)