معرفی
K-به معنای خوشه بندی است یکی از پرکاربردترین الگوریتمهای یادگیری ماشینی بدون نظارت است که بر اساس شباهت بین نمونههای داده، خوشههایی از دادهها را تشکیل میدهد.
در این راهنما، ابتدا نگاهی به یک مثال ساده می اندازیم تا بفهمیم الگوریتم K-Means چگونه کار می کند قبل از اجرای آن با استفاده از Scikit-Learn. سپس، نحوه تعیین تعداد خوشه ها (Ks) در K-Means و همچنین معیارهای فاصله، واریانس، و مزایا و معایب K-Means را مورد بحث قرار خواهیم داد.
انگیزه
وضعیت زیر را تصور کنید. یک روز، هنگامی که در اطراف محله قدم می زدید، متوجه شدید که 10 فروشگاه رفاه وجود دارد و شروع به تعجب کردید که کدام فروشگاه ها شبیه به هم هستند - در نزدیکی به یکدیگر. در حالی که به دنبال راه هایی برای پاسخ به این سوال هستید، با رویکرد جالبی مواجه شده اید که فروشگاه ها را بر اساس مختصات آنها روی نقشه به گروه هایی تقسیم می کند.
به عنوان مثال، اگر یک فروشگاه در 5 کیلومتری غرب و 3 کیلومتری شمال قرار داشت - شما آن را اختصاص می دهید (5, 3)
مختصات آن است و آن را در یک نمودار نشان می دهد. بیایید این اولین نقطه را ترسیم کنیم تا آنچه را که اتفاق میافتد تجسم کنیم:
import matplotlib.pyplot as plt
plt.title("Store With Coordinates (5, 3)")
plt.scatter(x=5, y=3)
این فقط اولین نکته است، بنابراین ما می توانیم ایده ای در مورد نحوه نمایندگی یک فروشگاه داشته باشیم. فرض کنید ما در حال حاضر 10 مختصات برای 10 فروشگاه جمع آوری شده داریم. پس از سازماندهی آنها در یک numpy
آرایه، ما همچنین می توانیم مکان های آنها را رسم کنیم:
import numpy as np
points = np.array([[5, 3], [10, 15], [15, 12], [24, 10], [30, 45], [85, 70], [71, 80], [60, 78], [55, 52],[80, 91]])
xs = points[:,0]
ys = points[:,1]
plt.title("10 Stores Coordinates")
plt.scatter(x=xs, y=ys)
نحوه پیاده سازی دستی الگوریتم K-Means
اکنون میتوانیم به 10 فروشگاه در یک نمودار نگاه کنیم، و مشکل اصلی این است که آیا راهی وجود دارد که بتوان آنها را بر اساس مجاورت به گروههای مختلف تقسیم کرد؟ فقط با نگاهی گذرا به نمودار، احتمالا متوجه خواهیم شد دو گروه فروشگاه - یکی از نقاط پایین به سمت چپ پایین و دیگری نقاط بالا سمت راست است. شاید حتی بتوانیم آن دو نقطه را در وسط به عنوان یک گروه مجزا از هم متمایز کنیم - بنابراین ایجاد می کنیم سه گروه مختلف.
در این بخش، فرآیند خوشهبندی دستی نقاط را بررسی میکنیم – تقسیم آنها به تعداد معینی از گروهها. به این ترتیب، ما اساساً تمام مراحل را با دقت مرور خواهیم کرد الگوریتم خوشه بندی K-Means. در پایان این بخش، درک بصری و عملی از تمام مراحل انجام شده در طول خوشه بندی K-Means به دست خواهید آورد. پس از آن، آن را به Scikit-Learn واگذار می کنیم.
بهترین راه برای تعیین وجود دو یا سه گروه از نقاط چیست؟ یک راه ساده این است که به سادگی یک تعدادی از گروه ها را انتخاب کنید - به عنوان مثال، دو - و سپس سعی کنید نقاط را بر اساس آن انتخاب گروه بندی کنید.
بیایید بگوییم که ما تصمیم گرفته ایم وجود داشته باشد دو گروه از فروشگاه های ما (نقاط). حال باید راهی پیدا کنیم تا بفهمیم کدام نقاط به کدام گروه تعلق دارند. این را می توان با انتخاب یک نقطه برای نشان دادن انجام داد گروه 1 و یکی برای نمایندگی گروه 2. این نقاط به عنوان مرجع در هنگام اندازه گیری فاصله از تمام نقاط دیگر به هر گروه استفاده می شود.
به این ترتیب، نکته را بگویید (5, 3)
به گروه 1 تعلق می گیرد و امتیاز می گیرد (79, 60)
به گروه 2. هنگام تلاش برای اختصاص یک نقطه جدید (6, 3)
به گروه ها، باید فاصله آن را تا آن دو نقطه اندازه گیری کنیم. در مورد نقطه (6, 3)
is نزدیک به (5, 3)
، بنابراین به گروهی تعلق دارد که توسط آن نقطه نشان داده شده است - گروه 1. به این ترتیب به راحتی می توانیم تمام نقاط را در گروه های مربوطه گروه بندی کنیم.
در این مثال، علاوه بر تعیین تعداد گروه ها (خوشه) – ما همچنین برخی از نقاط را به عنوان a انتخاب می کنیم مرجع فاصله امتیازات جدید هر گروه
این ایده کلی برای درک شباهت های بین فروشگاه های ما است. بیایید آن را عملی کنیم - ابتدا می توانیم دو نقطه مرجع را انتخاب کنیم تصادفی. نقطه مرجع از گروه 1 خواهد بود (5, 3)
و نقطه مرجع از گروه 2 خواهد بود (10, 15)
. ما می توانیم هر دو نقطه خود را انتخاب کنیم numpy
آرایه توسط [0]
و [1]
ایندکس ها و ذخیره آنها در g1
(گروه 1) و g2
متغیرهای (گروه 2):
g1 = points[0]
g2 = points[1]
پس از انجام این کار، باید فاصله تمام نقاط دیگر تا آن نقاط مرجع را محاسبه کنیم. این یک سوال مهم را ایجاد می کند - چگونه می توان آن فاصله را اندازه گیری کرد. اساساً میتوانیم از هر اندازهگیری فاصله استفاده کنیم، اما برای هدف این راهنما، از Euclidean Distance_ استفاده میکنیم.
دانستن اینکه اندازه گیری فاصله اقلیدسی بر اساس قضیه فیثاغورث است می تواند مفید باشد:
$$
c^2 = a^2 + b^2
$$
هنگامی که با نقاط یک هواپیما سازگار است - (a1, b1)
و (a2, b2)
، فرمول قبلی می شود:
$$
c^2 = (a2-a1)^2 + (b2-b1)^2
$$
فاصله برابر با جذر خواهد بود c
، بنابراین می توانیم فرمول را به صورت زیر بنویسیم:
$$
اقلیدسی_{dist} = sqrt[2][(a2 - a1)^2 + (b2 - b1) ^2)]
$$
توجه داشته باشید: همچنین می توانید فرمول فاصله اقلیدسی را برای نقاط چند بعدی تعمیم دهید. به عنوان مثال، در یک فضای سه بعدی، نقاط دارای سه مختصات هستند - فرمول ما آن را به شکل زیر منعکس می کند:
$$
اقلیدسی_{dist} = sqrt[2][(a2 – a1)^2 + (b2 – b1) ^2 + (c2 – c1) ^2)]
$$
بدون توجه به تعداد ابعاد فضایی که در آن مشغول به فعالیت هستیم، از همین اصل پیروی می شود.
تا اینجا ما نقاطی را برای نمایش گروه ها انتخاب کرده ایم و می دانیم که چگونه فاصله ها را محاسبه کنیم. حالا بیایید فاصله ها و گروه ها را با تخصیص هر یک از امتیازهای فروشگاه جمع آوری شده به یک گروه کنار هم قرار دهیم.
برای تجسم بهتر آن، سه لیست را اعلام می کنیم. اولین نفری که امتیازهای گروه اول را ذخیره می کند - points_in_g1
. نفر دوم برای ذخیره امتیاز از گروه 2 - points_in_g2
و آخرین مورد - group
، به برچسب نقاط به عنوان هر دو 1
(به گروه 1 تعلق دارد) یا 2
(متعلق به گروه 2)
points_in_g1 = []
points_in_g2 = []
group = []
اکنون میتوانیم نقاط خود را تکرار کنیم و فاصله اقلیدسی بین آنها و هر یک از مراجع گروه خود را محاسبه کنیم. هر نقطه خواهد بود نزدیک به یکی از دو گروه - بر اساس اینکه کدام گروه نزدیکتر است، هر نقطه را به لیست مربوطه اختصاص میدهیم و در عین حال اضافه میکنیم. 1
or 2
به group
لیست:
for p in points:
x1, y1 = p[0], p[1]
euclidean_distance_g1 = np.sqrt((g1[0] - x1)**2 + (g1[1] - y1)**2)
euclidean_distance_g2 = np.sqrt((g2[0] - x1)**2 + (g2[1] - y1)**2)
if euclidean_distance_g1 < euclidean_distance_g2:
points_in_g1.append(p)
group.append('1')
else:
points_in_g2.append(p)
group.append('2')
بیایید به نتایج این تکرار نگاه کنیم تا ببینیم چه اتفاقی افتاده است:
print(f'points_in_g1:{points_in_g1}n
npoints_in_g2:{points_in_g2}n
ngroup:{group}')
که منجر به:
points_in_g1:[array([5, 3])]
points_in_g2:[array([10, 15]), array([15, 12]),
array([24, 10]), array([30, 45]),
array([85, 70]), array([71, 80]),
array([60, 78]), array([55, 52]),
array([80, 91])]
group:[1, 2, 2, 2, 2, 2, 2, 2, 2, 2]
همچنین می توانیم نتیجه خوشه بندی را با رنگ های مختلف بر اساس گروه های اختصاص داده شده با استفاده از Seaborn رسم کنیم. scatterplot()
با group
به عنوان یک hue
بحث و جدل:
import seaborn as sns
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)
به وضوح قابل مشاهده است که تنها نقطه اول ما به گروه 1 اختصاص داده شده است، و تمام نقاط دیگر به گروه 2 اختصاص داده شده است. این نتیجه با آنچه در ابتدا تصور می کردیم متفاوت است. با توجه به تفاوت بین نتایج و انتظارات اولیه ما - آیا راهی وجود دارد که بتوانیم آن را تغییر دهیم؟ به نظر می رسد وجود دارد!
یک رویکرد تکرار فرآیند و انتخاب نقاط مختلف به عنوان مرجع گروه ها است. این نتایج ما را تغییر خواهد داد، امیدواریم که بیشتر مطابق با آنچه در ابتدا تصور می کردیم. این بار دوم، ما میتوانیم آنها را نه بهطور تصادفی مانند گذشته، بلکه با گرفتن یک انتخاب کنیم متوسط از تمام نقاط از قبل گروه بندی شده ما. به این ترتیب، آن نقاط جدید می توانند در وسط گروه های مربوطه قرار گیرند.
به عنوان مثال، اگر گروه دوم فقط امتیاز داشت (10, 15)
, (30, 45)
است. جدید مرکزی نقطه خواهد بود (10 + 30)/2
و (15+45)/2
– که برابر است با (20, 30)
.
از آنجایی که ما نتایج خود را در لیست ها قرار داده ایم، می توانیم ابتدا آنها را به تبدیل کنیم numpy
آرایه ها، xs، ys آنها را انتخاب کرده و سپس آن را بدست آورید متوسط:
g1_center = [np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()]
g2_center = [np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()]
g1_center, g2_center
مشاوره: سعی کنید از آن استفاده کنید numpy
و آرایه های NumPy تا حد امکان. آنها برای عملکرد بهتر بهینه شده اند و بسیاری از عملیات جبر خطی را ساده می کنند. هر زمان که سعی می کنید برخی از مسائل جبر خطی را حل کنید، قطعاً باید نگاهی به آن بیندازید numpy
اسنادی برای بررسی اینکه آیا وجود دارد یا خیر numpy
روش طراحی شده برای حل مشکل شما شانس این است که وجود دارد!
برای کمک به تکرار فرآیند با نقاط مرکزی جدید، بیایید کد قبلی خود را به یک تابع تبدیل کنیم، آن را اجرا کنیم و ببینیم آیا تغییراتی در نحوه گروه بندی نقاط وجود دارد یا خیر:
def assigns_points_to_two_groups(g1_center, g2_center):
points_in_g1 = []
points_in_g2 = []
group = []
for p in points:
x1, y1 = p[0], p[1]
euclidean_distance_g1 = np.sqrt((g1_center[0] - x1)**2 + (g1_center[1] - y1)**2)
euclidean_distance_g2 = np.sqrt((g2_center[0] - x1)**2 + (g2_center[1] - y1)**2)
if euclidean_distance_g1 < euclidean_distance_g2:
points_in_g1.append(p)
group.append(1)
else:
points_in_g2.append(p)
group.append(2)
return points_in_g1, points_in_g2, group
توجه داشته باشید: اگر متوجه شدید که یک کد را بارها و بارها تکرار می کنید، باید آن کد را در یک تابع جداگانه بپیچید. سازماندهی کد به توابع بهترین روش در نظر گرفته می شود، به ویژه به این دلیل که آنها تست را تسهیل می کنند. تست کردن و جداسازی یک کد از یک کد کامل بدون هیچ عملکردی آسانتر است.
بیایید تابع را فراخوانی کنیم و نتایج آن را در آن ذخیره کنیم points_in_g1
, points_in_g2
و group
متغیرها:
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
points_in_g1, points_in_g2, group
و همچنین نمودار پراکندگی را با نقاط رنگی ترسیم کنید تا تقسیم گروه ها را تجسم کنید:
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)
به نظر می رسد خوشه بندی نقاط ما است بهتر شدن. اما با این حال، دو نقطه در وسط نمودار وجود دارد که میتوان به هر یک از گروهها در مجاورت هر دو گروه نسبت داد. الگوریتمی که ما تاکنون ایجاد کرده ایم، هر دوی این نقاط را به گروه دوم اختصاص می دهد.
این بدان معناست که ما احتمالاً میتوانیم با استفاده از مقادیر Xs و Ys یک بار دیگر فرآیند را تکرار کنیم و دو نقطه مرکزی جدید ایجاد کنیم (سنتروئیدها) به گروه های ما و تخصیص مجدد آنها بر اساس فاصله.
بیایید یک تابع برای به روز رسانی سانتروئیدها نیز ایجاد کنیم. اکنون کل فرآیند را می توان به چندین فراخوانی آن تابع کاهش داد:
def updates_centroids(points_in_g1, points_in_g2):
g1_center = np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()
g2_center = np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()
return g1_center, g2_center
g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)
توجه داشته باشید که پس از این تکرار سوم، هر یک از نقاط اکنون به خوشه های مختلفی تعلق دارند. به نظر می رسد نتایج بهتر می شوند - بیایید یک بار دیگر این کار را انجام دهیم. در حال حاضر رفتن به تکرار چهارم روش ما:
g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)
این چهارمین بار رسیدیم همان نتیجه مانند قبلی بنابراین به نظر می رسد امتیازات ما دیگر گروه را تغییر نمی دهد، نتیجه ما به نوعی ثبات رسیده است - به وضعیت غیرقابل تغییر رسیده است، یا همگرا. علاوه بر این، دقیقاً همان نتیجه ای را داریم که برای 2 گروه متصور بودیم. همچنین میتوانیم ببینیم که آیا این تقسیم بندی منطقی است یا خیر.
بیایید به سرعت کارهایی را که تاکنون انجام دادهایم مرور کنیم. ما 10 فروشگاه خود را از نظر جغرافیایی به دو بخش تقسیم کرده ایم - یکی در مناطق جنوب غربی پایین و بقیه در شمال شرقی. جمعآوری دادههای بیشتر علاوه بر آنچه در حال حاضر داریم - درآمد، تعداد روزانه مشتریان و بسیاری موارد دیگر، میتواند جالب باشد. به این ترتیب میتوانیم تجزیه و تحلیل غنیتری انجام دهیم و احتمالاً نتایج جالبتری تولید کنیم.
مطالعات خوشهبندی مانند این میتواند زمانی انجام شود که یک برند از قبل تاسیس شده بخواهد منطقهای را برای افتتاح یک فروشگاه جدید انتخاب کند. در این مورد، متغیرهای بسیار بیشتری علاوه بر مکان در نظر گرفته شده است.
همه اینها چه ربطی به الگوریتم K-Means دارد؟
در حالی که این مراحل را دنبال می کنید، ممکن است تعجب کرده باشید که آنها چه ارتباطی با الگوریتم K-Means دارند. روندی که ما تاکنون انجام داده ایم این است الگوریتم K-Means. به طور خلاصه، تعداد گروهها/خوشهها را تعیین کردهایم، نقاط اولیه را بهطور تصادفی انتخاب کردهایم، و مرکزها را در هر تکرار تا زمانی که خوشهها همگرا شوند، بهروزرسانی کردهایم. ما اساساً کل الگوریتم را با دست انجام داده ایم - هر مرحله را با دقت انجام می دهیم.
La K در K-Means از تعداد خوشه ها که باید قبل از شروع فرآیند تکرار تنظیم شوند. در مورد ما K = 2. این ویژگی گاهی اوقات به عنوان دیده می شود منفی با توجه به روشهای خوشهبندی دیگری مانند خوشهبندی سلسله مراتبی، که نیازی به داشتن تعداد ثابتی از خوشهها از قبل نیست.
به دلیل استفاده از وسیله، K-means نیز می شود نسبت به مقادیر پرت و شدید حساس است - آنها تغییرپذیری را افزایش می دهند و ایفای نقش خود را برای مرکزهای ما دشوارتر می کنند. بنابراین، از نیاز به اجرا آگاه باشید مقادیر شدید و تجزیه و تحلیل بیرونی قبل از انجام یک خوشه بندی با استفاده از الگوریتم K-Means.
همچنین، توجه داشته باشید که نقاط ما در قسمت های مستقیم تقسیم شده اند، هنگام ایجاد خوشه ها منحنی وجود ندارد. این همچنین می تواند یک نقطه ضعف الگوریتم K-Means باشد.
توجه داشته باشید: هنگامی که به انعطاف پذیری و سازگاری بیشتر با بیضی ها و اشکال دیگر نیاز دارید، سعی کنید از a استفاده کنید تعمیم K-means مدل مخلوط گاوسی. این مدل می تواند با خوشه های تقسیم بندی بیضوی سازگار شود.
K-Means نیز بسیاری دارد مزایای! عملکرد خوبی دارد مجموعه داده های بزرگ اگر از انواع الگوریتمهای خوشهبندی سلسله مراتبی استفاده میکنید، رسیدگی به آن دشوار میشود. آن را نیز همگرایی را تضمین می کند، و به راحتی می تواند تعمیم دادن و وفق دادن. علاوه بر آن، احتمالاً پرکاربردترین الگوریتم خوشهبندی است.
اکنون که تمام مراحل انجام شده در الگوریتم K-Means را مرور کردیم و تمام جوانب مثبت و منفی آن را فهمیدیم، در نهایت می توانیم K-Means را با استفاده از کتابخانه Scikit-Learn پیاده سازی کنیم.
نحوه پیاده سازی الگوریتم K-Means با استفاده از Scikit یاد بگیرید
برای بررسی مجدد نتیجه، اجازه دهید این فرآیند را دوباره انجام دهیم، اما اکنون از 3 خط کد با استفاده می کنیم sklearn
:
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=2, random_state=42)
kmeans.fit(points)
kmeans.labels_
در اینجا، برچسب ها مانند گروه های قبلی ما هستند. بیایید به سرعت نتیجه را ترسیم کنیم:
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)
نمودار به دست آمده همانند تصویر بخش قبل است.
راهنمای عملی و عملی ما برای یادگیری Git را با بهترین روش ها، استانداردهای پذیرفته شده در صنعت و برگه تقلب شامل بررسی کنید. دستورات Google Git را متوقف کنید و در واقع یاد گرفتن آی تی!
توجه داشته باشید: فقط نگاه کردن به نحوه اجرای الگوریتم K-Means با استفاده از Scikit-Learn ممکن است به شما این تصور را بدهد که این الگوریتم بیهوده است و نیازی نیست زیاد در مورد آن نگران باشید. زمانی که الگوریتم K-Means را به صورت گام به گام بررسی کردیم، فقط 3 خط کد تمام مراحلی را که در بخش قبل در مورد آن صحبت کردیم انجام می دهد. ولی، شیطان در جزئیات است در این مورد! اگر تمام مراحل و محدودیت های الگوریتم را درک نکنید، به احتمال زیاد با موقعیتی مواجه خواهید شد که الگوریتم K-Means نتایجی را به شما می دهد که انتظارش را نداشتید.
با Scikit-Learn، میتوانید K-Means را برای همگرایی سریعتر با تنظیم init='k-means++'
بحث و جدل. به عبارتی گسترده تر، K-Means++ هنوز هم انتخاب می کند k مرکز خوشه اولیه به صورت تصادفی پس از توزیع یکنواخت. سپس، هر مرکز خوشه بعدی از میان نقاط داده باقیمانده نه با محاسبه اندازه گیری فاصله - بلکه با استفاده از احتمال انتخاب می شود. استفاده از احتمال، الگوریتم را سرعت می بخشد و در هنگام برخورد با مجموعه داده های بسیار بزرگ مفید است.
روش آرنج – انتخاب بهترین تعداد گروه
تا اینجای کار خیلی خوبه! ما 10 فروشگاه را بر اساس فاصله اقلیدسی بین نقاط و مرکزها دسته بندی کرده ایم. اما در مورد آن دو نقطه در وسط نمودار که خوشهبندی آنها کمی سختتر است، چطور؟ آیا نمی توانستند یک گروه جداگانه هم تشکیل دهند؟ آیا واقعاً با انتخاب اشتباه کردیم؟ K = 2 گروه ها؟ شاید واقعا داشتیم K = 3 گروه ها؟ حتی می توانستیم بیش از سه گروه داشته باشیم و از آن آگاه نباشیم.
سوالی که در اینجا مطرح می شود این است نحوه تعیین تعداد گروه ها (K) در K-Means. برای پاسخ به این سوال، باید بدانیم که آیا یک خوشه "بهتر" برای مقدار متفاوت K وجود دارد یا خیر.
راه ساده برای یافتن آن، خوشهبندی نقاط با مقادیر مختلف است K، بنابراین برای K=2، K=3، K=4 و غیره:
for number_of_clusters in range(1, 11):
kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
kmeans.fit(points)
اما، نقاط خوشه بندی برای مختلف Ks تنها کافی نیست برای درک اینکه آیا مقدار ایده آل را برای آن انتخاب کرده ایم یا خیر K. ما به راهی برای ارزیابی کیفیت خوشه بندی برای هر یک نیاز داریم K ما انتخاب کرده ایم
محاسبه دستی درون مجموع مربعها (WCSS)
در اینجا مکان ایده آلی برای معرفی میزان نزدیکی نقاط خوشه ای ما به یکدیگر است. اساساً توضیح می دهد که چقدر واریانس ما درون یک خوشه واحد داریم. این اندازه گیری نامیده می شود در مجموع مجذورات خوشه ای، یا WCSS به طور خلاصه هرچه WCSS کوچکتر باشد، نقاط ما به هم نزدیکتر هستند، بنابراین ما یک خوشه خوش فرم تر داریم. فرمول WCSS را می توان برای هر تعداد خوشه استفاده کرد:
$$
WCSS = مجموع (Pi_1 - Centroid_1)^2 + cdots + sum (Pi_n - Centroid_n)^2
$$
توجه داشته باشید: در این راهنما، ما از فاصله ی اقلیدسی برای به دست آوردن مرکز، اما سایر معیارهای فاصله مانند منهتن نیز می توانند استفاده شوند.
اکنون میتوانیم فرض کنیم که دو کلاستر داشته باشیم و سعی کنیم WCSS را پیادهسازی کنیم تا بهتر بفهمیم WCSS چیست و چگونه از آن استفاده کنیم. همانطور که فرمول بیان می کند، ما باید مجذور اختلاف بین تمام نقاط خوشه و مرکز را جمع کنیم. بنابراین، اگر اولین امتیاز ما از گروه اول باشد (5, 3)
و آخرین مرکز ما (پس از همگرایی) از گروه اول است (16.8, 17.0)
، WCSS خواهد بود:
$$
WCSS = مجموع ((5,3،16.8) - (17.0، 2))^XNUMX
$$
$$
WCSS = مجموع ((5-16.8) + (3-17.0))^2
$$
$$
WCSS = مجموع ((-11.8) + (-14.0))^2
$$
$$
WCSS = جمع ((-25.8))^2
$$
$$
WCSS = 335.24
$$
این مثال نشان می دهد که چگونه WCSS را برای یک نقطه از خوشه محاسبه می کنیم. اما خوشه معمولاً شامل بیش از یک نقطه است و ما باید همه آنها را هنگام محاسبه WCSS در نظر بگیریم. ما این کار را با تعریف تابعی انجام خواهیم داد که خوشه ای از نقاط و مرکزها را دریافت می کند و مجموع مربع ها را برمی گرداند:
def sum_of_squares(cluster, centroid):
squares = []
for p in cluster:
squares.append((p - centroid)**2)
ss = np.array(squares).sum()
return ss
اکنون می توانیم مجموع مربع های هر خوشه را بدست آوریم:
g1 = sum_of_squares(points_in_g1, g1_center)
g2 = sum_of_squares(points_in_g2, g2_center)
و نتایج را جمع کنید تا مجموع را بدست آورید WCSS:
g1 + g2
این نتیجه در:
2964.3999999999996
بنابراین، در مورد ما، چه زمانی K برابر 2، مجموع WCSS است 2964.39. اکنون میتوانیم Ks را تغییر دهیم و WCSS را برای همه آنها محاسبه کنیم. به این ترتیب، ما میتوانیم بینشی در مورد چه چیزی داشته باشیم K ما باید انتخاب کنیم که خوشه بندی ما بهترین عملکرد را داشته باشد.
محاسبه WCSS با استفاده از Scikit یاد بگیرید
خوشبختانه، ما نیازی به محاسبه دستی WCSS برای هر یک نداریم K. پس از انجام خوشه بندی K-Means برای تعداد خوشه های داده شده، می توانیم WCSS آن را با استفاده از inertia_
صفت. اکنون، میتوانیم به K-Means خود برگردیم for
حلقه، از آن برای جابجایی تعداد خوشه ها استفاده کنید و مقادیر WCSS مربوطه را فهرست کنید:
wcss = []
for number_of_clusters in range(1, 11):
kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
kmeans.fit(points)
wcss.append(kmeans.inertia_)
wcss
توجه داشته باشید که مقدار دوم در لیست دقیقاً همان است که قبلاً برای آن محاسبه کرده بودیم K = 2:
[18272.9, # For k=1
2964.3999999999996, # For k=2
1198.75, # For k=3
861.75,
570.5,
337.5,
175.83333333333334,
79.5,
17.0,
0.0]
برای تجسم آن نتایج، بیایید خود را رسم کنیم Ks همراه با مقادیر WCSS:
ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss)
یک وقفه در یک طرح وجود دارد که x = 2
، یک نقطه پایین در خط، و حتی پایین تر زمانی که x = 3
. توجه داشته باشید که آن را به ما یادآوری می کند شکل آرنج. با ترسیم Ks به همراه WCSS، ما از آن استفاده می کنیم روش آرنج برای انتخاب تعداد Ks. و K انتخاب شده دقیقاً پایین ترین نقطه آرنج است، بنابراین، می شود 3
بجای 2
، در مورد ما:
ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss);
plt.axvline(3, linestyle='--', color='r')
میتوانیم الگوریتم خوشهای K-Means را دوباره اجرا کنیم تا ببینیم دادههای ما چگونه به نظر میرسند سه خوشه:
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(points)
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)
ما قبلاً از دو خوشه راضی بودیم، اما طبق روش آرنج، سه خوشه برای دادههای ما مناسبتر بود. در این صورت به جای دو فروشگاه، سه نوع فروشگاه خواهیم داشت. قبل از استفاده از روش زانویی به خوشه های فروشگاه های جنوب غربی و شمال شرقی فکر می کردیم، اکنون در مرکز نیز فروشگاه هایی داریم. شاید این می تواند مکان خوبی برای افتتاح یک فروشگاه دیگر باشد زیرا رقابت کمتری در آن نزدیکی خواهد داشت.
معیارهای کیفی خوشه ای جایگزین
همچنین معیارهای دیگری وجود دارد که میتوان هنگام ارزیابی کیفیت خوشه استفاده کرد:
- امتیاز سیلوئت - نه تنها فاصله بین نقاط درون خوشه ای بلکه بین خود خوشه ها را نیز تجزیه و تحلیل می کند
- بین خوشه ها مجموع مربع ها (BCSS) - متریک مکمل WCSS
- خطای مجموع مربعات (ESS)
- حداکثر شعاع - بزرگترین فاصله یک نقطه تا مرکز آن را اندازه گیری می کند
- شعاع متوسط - مجموع بزرگترین فاصله از یک نقطه تا مرکز آن تقسیم بر تعداد خوشه ها.
توصیه می شود هر یک از آنها را آزمایش کنید و با آنها آشنا شوید زیرا بسته به مشکل، برخی از گزینه ها می توانند از معیارهای پرکاربردتر قابل استفاده باشند. (نمره WCSS و Silhouette).
در پایان، مانند بسیاری از الگوریتمهای علم داده، میخواهیم واریانس درون هر خوشه را کاهش دهیم و واریانس بین خوشههای مختلف را به حداکثر برسانیم. بنابراین ما خوشه های تعریف شده و قابل تفکیک بیشتری داریم.
استفاده از K-Means در یک مجموعه داده دیگر
بیایید از چیزهایی که آموخته ایم در مجموعه داده دیگری استفاده کنیم. این بار سعی خواهیم کرد گروه هایی از شراب های مشابه را پیدا کنیم.
توجه داشته باشید: می توانید مجموعه داده را دانلود کنید اینجا کلیک نمایید.
ما با واردات شروع می کنیم pandas
برای خواندن wine-clustering
CSV (مقادیر جدا شده با کاما) فایل به a Dataframe
ساختار:
import pandas as pd
df = pd.read_csv('wine-clustering.csv')
پس از بارگذاری آن، بیایید نگاهی به پنج رکورد اول داده با آن بیاندازیم head()
روش:
df.head()
این نتیجه در:
Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue OD280 Proline
0 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
2 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
3 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
4 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93 735
ما اندازه گیری های زیادی از مواد موجود در شراب ها داریم. در اینجا، ما همچنین نیازی به تبدیل ستون های دسته بندی نخواهیم داشت زیرا همه آنها عددی هستند. حال بیایید نگاهی به آمار توصیفی با describe()
روش:
df.describe().T
جدول توصیف:
count mean std min 25% 50% 75% max
Alcohol 178.0 13.000618 0.811827 11.03 12.3625 13.050 13.6775 14.83
Malic_Acid 178.0 2.336348 1.117146 0.74 1.6025 1.865 3.0825 5.80
Ash 178.0 2.366517 0.274344 1.36 2.2100 2.360 2.5575 3.23
Ash_Alcanity 178.0 19.494944 3.339564 10.60 17.2000 19.500 21.5000 30.00
Magnesium 178.0 99.741573 14.282484 70.00 88.0000 98.000 107.0000 162.00
Total_Phenols 178.0 2.295112 0.625851 0.98 1.7425 2.355 2.8000 3.88
Flavanoids 178.0 2.029270 0.998859 0.34 1.2050 2.135 2.8750 5.08
Nonflavanoid_Phenols 178.0 0.361854 0.124453 0.13 0.2700 0.340 0.4375 0.66
Proanthocyanins 178.0 1.590899 0.572359 0.41 1.2500 1.555 1.9500 3.58
Color_Intensity 178.0 5.058090 2.318286 1.28 3.2200 4.690 6.2000 13.00
Hue 178.0 0.957449 0.228572 0.48 0.7825 0.965 1.1200 1.71
OD280 178.0 2.611685 0.709990 1.27 1.9375 2.780 3.1700 4.00
Proline 178.0 746.893258 314.907474 278.00 500.500 673.500 985.0000 1680.00
با نگاه کردن به جدول مشخص می شود که مقداری وجود دارد تنوع در داده ها - برای برخی از ستون ها مانند Alchool
بیشتر وجود دارد، و برای دیگران، مانند Malic_Acid
، کمتر اکنون می توانیم بررسی کنیم که آیا وجود دارد یا خیر null
، یا NaN
مقادیر موجود در مجموعه داده ما:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 13 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Alcohol 178 non-null float64
1 Malic_Acid 178 non-null float64
2 Ash 178 non-null float64
3 Ash_Alcanity 178 non-null float64
4 Magnesium 178 non-null int64
5 Total_Phenols 178 non-null float64
6 Flavanoids 178 non-null float64
7 Nonflavanoid_Phenols 178 non-null float64
8 Proanthocyanins 178 non-null float64
9 Color_Intensity 178 non-null float64
10 Hue 178 non-null float64
11 OD280 178 non-null float64
12 Proline 178 non-null int64
dtypes: float64(11), int64(2)
memory usage: 18.2 KB
با توجه به اینکه مقادیر خالی در مجموعه داده وجود ندارد، نیازی به حذف یا وارد کردن داده نیست. ما می توانیم از Seaborn استفاده کنیم pairplot()
برای مشاهده توزیع داده ها و بررسی اینکه آیا مجموعه داده جفت ستون هایی را تشکیل می دهد که می توانند برای خوشه بندی جالب باشند:
sns.pairplot(df)
با نگاه کردن به نمودار زوجی، دو ستون برای اهداف خوشهبندی امیدوارکننده به نظر میرسند - Alcohol
و OD280
(که روشی برای تعیین غلظت پروتئین در شراب ها است). به نظر می رسد که 3 خوشه مجزا در کرت ها وجود دارد که دو تا از آنها را ترکیب می کند.
ستون های دیگری نیز وجود دارند که به نظر می رسد همبستگی دارند. قابل توجه ترین Alcohol
و Total_Phenols
و Alcohol
و Flavanoids
. آنها روابط خطی بسیار خوبی دارند که می توان آنها را در نمودار زوجی مشاهده کرد.
از آنجایی که تمرکز ما خوشهبندی با K-Means است، بیایید مثلاً یک جفت ستون را انتخاب کنیم Alcohol
و OD280
و روش elbow را برای این مجموعه داده آزمایش کنید.
توجه داشته باشید: هنگام استفاده از ستون های بیشتری از مجموعه داده، نیاز به ترسیم نمودار در 3 بعد یا کاهش داده ها به اجزای اصلی (استفاده از PCA). این یک رویکرد معتبر و رایج تر است، فقط مطمئن شوید که اجزای اصلی را بر اساس میزان توضیح آنها انتخاب کنید و در نظر داشته باشید که هنگام کاهش ابعاد داده، مقداری از دست دادن اطلاعات وجود دارد - بنابراین طرح یک تقریب از داده های واقعی، نه اینکه واقعا چگونه است.
بیایید نمودار پراکندگی را با آن دو ستون که به عنوان محور آن تنظیم شده اند رسم کنیم تا نقاطی را که می خواهیم به گروه ها تقسیم کنیم، نگاه دقیق تری بیندازیم:
sns.scatterplot(data=df, x='OD280', y='Alcohol')
حالا میتوانیم ستونهایمان را تعریف کنیم و از روش elbow برای تعیین تعداد خوشهها استفاده کنیم. ما همچنین الگوریتم را با شروع خواهیم کرد kmeans++
فقط برای اطمینان از همگرایی سریعتر:
values = df[['OD280', 'Alcohol']]
wcss_wine = []
for i in range(1, 11):
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
kmeans.fit(values)
wcss_wine.append(kmeans.inertia_)
ما WCSS را محاسبه کرده ایم، بنابراین می توانیم نتایج را رسم کنیم:
clusters_wine = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(clusters_wine, wcss_wine)
plt.axvline(3, linestyle='--', color='r')
طبق روش آرنج باید 3 خوشه در اینجا داشته باشیم. برای مرحله آخر، اجازه دهید نقاط خود را به 3 خوشه خوشه بندی کنیم و آن دسته از خوشه های مشخص شده با رنگ ها را رسم کنیم:
kmeans_wine = KMeans(n_clusters=3, random_state=42)
kmeans_wine.fit(values)
sns.scatterplot(x = values['OD280'], y = values['Alcohol'], hue=kmeans_wine.labels_)
ما می توانیم خوشه ها را ببینیم 0
, 1
و 2
در نمودار بر اساس تحلیل ما، گروه 0 دارای شراب هایی با محتوای پروتئین بالاتر و الکل کمتر، گروه 1 دارای شراب هایی با محتوای الکل بالاتر و پروتئین کم، و گروه 2 هم پروتئین بالا و هم الکل بالا در شراب های خود دارد.
این مجموعه داده بسیار جالبی است و من شما را تشویق میکنم تا با خوشهبندی دادهها پس از نرمالسازی و PCA - همچنین با تفسیر نتایج و یافتن اتصالات جدید، بیشتر به تجزیه و تحلیل بروید.
نتیجه
k-means خوشهبندی یک الگوریتم یادگیری ماشینی ساده و در عین حال بسیار مؤثر برای خوشهبندی داده است. این داده ها را بر اساس فاصله اقلیدسی بین نقاط داده خوشه بندی می کند. الگوریتم خوشه بندی K-Means کاربردهای زیادی برای گروه بندی اسناد متنی، تصاویر، ویدئوها و موارد دیگر دارد.