DBSCAN خوشه را با تراکم همسایگی تعریف میکند: نقطههای هسته به هم وصل میشوند و نقطههای غیرهسته نزدیک به آنها میتوانند در مرز گروه قرار بگیرند. بعضی نقطهها هم بدون عضویت در خوشه باقی میمانند. برای فهم روش، باید «همسایه»، «هسته»، «مرزی» و «نویز» را با قرارداد مشخص از هم جدا کرد.
دو تنظیم و یک قرارداد شمارش
eps شعاع همسایگی در سنجه فاصله انتخابی است. min_samples حداقل تعداد نمونه در آن همسایگی برای هستهشدن را مشخص میکند. در قرارداد این کد، خود نقطه هم شمرده میشود و فاصله کمتر یا مساوی eps داخل همسایگی است. این جزئیات را هنگام مقایسه ابزارها ثبت کنید؛ اختلاف آنها میتواند خروجی را عوض کند.
پنج نقطه را بررسی کنیم
داده یکبعدی ۰،۰٫۱،۰٫۲،۰٫۵ و۲ است؛ eps=۰٫۳۱ و min_samples=۳ انتخاب شدهاند. این مقدارها فقط تمریناند و تنظیم پیشنهادی برای متن، صوت یا رفتار مشتری نیستند. شماره ردیفها در کد از صفر شروع میشود.
| نقطه | تعداد همسایه با احتساب خودش | نقش |
|---|---|---|
| 0 | 3 | هسته |
| ۰٫۱ | 3 | هسته |
| ۰٫۲ | 4 | هسته |
| ۰٫۵ | 2 | مرزی |
| 2 | 1 | نویز |
سه نقطه نخست همسایگی کافی دارند و از مسیر نقطههای هسته به یکدیگر متصلاند. نقطه ۰٫۵ خودش هسته نیست، اما در فاصله ۰٫۳ از هسته ۰٫۲ قرار دارد؛ پس به مرز همان خوشه میپیوندد. نقطه ۲ نه هسته است و نه همسایه هیچ هستهای؛ در این تنظیم بیخوشه میماند.
نقطه مرزی، مسیر گسترش تازه نمیسازد
در ساخت گروه باید اتصال هستهها را دنبال کنیم، نه اینکه هر همسایه غیرهسته بهتنهایی حلقه گسترش جدید شود. وگرنه زنجیرهای از نقطههای کمتراکم ممکن است دو ناحیه را برخلاف قرارداد به هم وصل کند. کد نخست مؤلفههای متصل هستهها را میسازد و بعد مرزیها را نسبت میدهد.
points=[0.0,0.1,0.2,0.5,2.0]
eps,min_samples=0.31,3
neighbors=[[j for j,y in enumerate(points) if abs(x-y)<=eps] for x in points]
# This contract includes the point itself in min_samples.
core={i for i,ns in enumerate(neighbors) if len(ns)>=min_samples}
labels=[-1]*len(points)
cluster=0
for start in sorted(core):
if labels[start]!=-1:
continue
stack=[start]
labels[start]=cluster
while stack:
i=stack.pop()
for j in neighbors[i]:
if j in core and labels[j]==-1:
labels[j]=cluster
stack.append(j)
cluster+=1
for i in range(len(points)):
if i not in core:
adjacent=sorted({labels[j] for j in neighbors[i] if j in core})
if adjacent:
labels[i]=adjacent[0]
roles=['core' if i in core else 'border' if labels[i]>=0 else 'noise'
for i in range(len(points))]
print('neighbors',neighbors)
print('labels',labels,'roles',roles)
assert labels==[0,0,0,0,-1]
assert roles==['core','core','core','border','noise']اگر یک نقطه غیرهسته به هستههای دو خوشه نزدیک باشد، این نسخه شماره کوچکتر خوشه را انتخاب میکند. این قرارداد آشکار ماست؛ در برخی پیادهسازیها ترتیب پیمایش میتواند روی چنین انتسابی اثر بگذارد. داده این تمرین آن ابهام را ندارد. شماره خوشه هم نام دائمی یک موضوع نیست.
نویز را خطا یا تقلب ننامیم
برچسب نویز یعنی نقطه تحت همین تعریف تراکم عضو خوشه نشده است. ممکن است داده معتبر اما کمتکرار باشد. پیش از حذف، واحد، منشأ، کیفیت ثبت و نیاز مسئله را بررسی کنید. افزایش eps نیز میتواند گروههای جدا را ادغام کند؛ کمبودن تعداد نویز، بهخودیخود بهترشدن تحلیل نیست.
K-means هر نقطه را به یک مرکز نسبت میدهد و تعداد مرکز را از پیش میخواهد. اینجا مرکز میانگین یا k ورودی نداریم؛ شعاع و حد تراکم مهماند. برای مقایسه عضویت گروهها در چند اجرا، راهنمای ARI و پایداری خوشهها را با شناسههای همردیف بخوانید.
تمرین کنترلشده و مسیر کاربرد
فقط eps را عوض کنید و تعداد همسایههای هر نقطه را دوباره بسنجید. سپس در گزارشی بنویسید کدام تغییر ناشی از تنظیم بوده است؛ نامگذاری انسانی گروهها را ثابت و بیشاهد فرض نکنید. برای نیاز تحلیل یا رسیدگی به درخواست مشتری، هدف و نمونههای مجاز را در مسیر بررسی اپرا مطرح کنید؛ این مثال دستهبندی واقعی مخاطبان یا قابلیت آماده DBSCAN در محصول را اعلام نمیکند.
فایل تمرین و منابع
دریافت کد کامل این تمرین؛ این فایل فقط از کتابخانه استاندارد پایتون استفاده میکند. ورودیهای آن ساختگی و برای بازتولید محاسبهاند؛ اجرای آموزشی آن نتیجه یک محصول یا مشتری را نشان نمیدهد.
تاریخ بررسی منابع: ۳ نوامبر ۲۰۲۶. منابع، مرجع روشاند؛ دادهها، اعداد و کد مثال برای همین راهنما طراحی شدهاند.