DBSCAN expands clusters from points with enough neighbors inside a chosen radius and leaves unsupported points labeled as noise.
DBSCAN core, border and noise points
Define density in the scaled feature space
A warehouse planner compares sites using intake volume and late-scan rate. After fitting the feature transformation on an allowed reference period, choose a distance, radius and minimum-neighbor count. A core site has at least that count inside its radius, including itself in this implementation. A border site is close to a core site without meeting the count on its own; a noise site is not reached. Scaling changes what a radius means.
Expand only from core sites
Starting at a core site, collect its neighbors. Every newly reached core site adds its neighbors, so a cluster can follow a non-round region. A border site can join a cluster but does not expand it further. The code computes all neighborhoods first and then performs this expansion. It marks an isolated warehouse as noise, rather than forcing it into the nearest cluster. K-means makes a different assignment choice.
Treat parameter choice as part of the finding
A small radius can mark most sites noise; a large radius may join unrelated populations. Raising the minimum count can erase a legitimate small operating regime. Inspect cluster support and rerun over a defensible parameter range. If memberships change with a slight radius adjustment, report that instability. Do not set the radius solely to produce a desired number of named business segments.
Separate unusual from defective
Noise is a geometric label, not a fraud or data-quality verdict. An isolated warehouse might serve a distinct geography, have a broken scan feed or represent a new process worth preserving. Review raw records, measurement units and operational context. For high-dimensional data, distances can concentrate, making one global radius hard to interpret. A projection may aid inspection but can also hide useful separation.
Plan the assignment contract
Classic DBSCAN defines clusters on the fitted sample; assigning a new site requires an explicit policy such as checking core neighborhoods under the frozen scaling and radius. Do not quietly refit all sites each day and assume cluster IDs remain stable. Keep the feature schema, radius and fitted reference data version. The applied review tests whether any resulting segment changes a real decision.
Implementation
from math import dist
warehouse_profiles = [(0.0, 0.0), (0.4, 0.3), (0.8, 0.1),
(8.0, 8.0), (8.3, 8.2), (8.7, 8.1),
(20.0, 3.0)]
radius = 1.0
minimum_neighbors = 3
neighbors = [[other for other, candidate in enumerate(warehouse_profiles)
if dist(profile, candidate) <= radius]
for profile in warehouse_profiles]
core = {index for index, nearby in enumerate(neighbors)
if len(nearby) >= minimum_neighbors}
labels = [None] * len(warehouse_profiles)
cluster_id = 0
for start in range(len(warehouse_profiles)):
if labels[start] is not None:
continue
if start not in core:
labels[start] = -1
continue
queue = [start]
queued = {start}
while queue:
current = queue.pop()
labels[current] = cluster_id
if current in core:
for nearby in neighbors[current]:
if labels[nearby] is None or labels[nearby] == -1:
if nearby not in queued:
queue.append(nearby)
queued.add(nearby)
cluster_id += 1
assert cluster_id == 2
assert labels[-1] == -1
assert labels[:3] == [0, 0, 0]
assert labels[3:6] == [1, 1, 1]Performance and operating cost
The direct all-pairs neighborhood construction takes O(N²F) time and O(N²) memory for N sites with F features; expansion follows the stored neighbor graph. Spatial indexing can help some distance settings, while dense neighborhoods may still require substantial memory. Do not silently scale this teaching implementation to millions of rows.
Common Mistakes
- Do not interpret noise as confirmed bad data or misconduct.
- Do not fit the scale or tune radius using future outcome labels.
- Do not assume cluster numeric IDs are stable across refits.
