در یادگیری بدون نظارت ما اجازه میدهیم، مدل به خودی خود رابطه بین دیتاها را کشف کند. بنابراین در این نوع الگوریتمها ما Train dataset نداریم. یا به عبارتی دیگر نیازی به برچسب زدن دیتاها نداریم. (we dont have labeled y’s). در ادامه این نوشته روش k- means را شرح خواهیم داد.
برای مثال فرض کنیم که دادههای زیر را که مربوط به مشتریان یک فروشگاه هست را داریم و میخواهیم، آنها را به سه دسته تقسیم کنیم:

مشتریان را به سه خوشه یا cluster تقسیم کردهایم. جوان بودن ، میزان درآمد از جمله موارد در نظر گرفته شده برای دستهبندی بوده است.
affluent= خانواده مرفه

تفاوت بین Clustering و Classification :
در کلاسیفیکیشن ( Classification ) یک سری دیتا داریم که label یا برچسب دارند و به صورت پیشفرض دیتاها صفر و یک هستند. بر اساس همین دادهها یک train_set و همچنین test_set داریم. بعد از train شدن مدل ، نمونههای جدید را به مدل میدهیم و سیستم میتواند خروجی را حدس زده یا (predict) کند. این اتفاقی است که درحالت Supervised learning داریم.
اما در کلاسترینگ (Clustering) دیتای ما فاقد برچسب (label) هستند. مدل ابتدا همه دیتا را میبیند و خودش میفهمد (یاد میگیرد) که هرکدام چه ویژگیهای خاصی دارند . سپس هر کدام را در یک دسته خاص قرار میدهد. مثلا ممکن است کلا سه دسته انتخاب کند و بگوید ، سه نوع دیتا داریم و همه را دستهبندی کند و نمونههای مشابه را هم در کنار هم قرار دهد. ویا ممکن است که دو دسته یا چهار دسته و … تشکیل دهد.
بنابراین مهمترین تفاوت در labeled و unlabeled بودن دادهها است:

کاربرد Clustering چیست؟
از جمله کاربردهای این روش میتوان به موارد زیر اشاره کرد:
1- خردهفروشی
2-شناسایی الگوی رفتار مشتری
3- شناسایی سلیقه مشتری و پیشنهاد خرید بیشتر به آنها
4- استفاده در سیستم بانکی
5- پیشبینی اینکه کدام مشتری خوش حساب خواهد بود و اقساط وام خود را پرداخت خواهد کرد.
6- در صنعت بیمه (برای مثال متناسب با سوابق تصادفها و جرایم رانندگی ، مشتریان بیمه را در دسته های متعدد دسته بندی کرده و بیمه با قیمت متفاوتی عرضه خواهند کرد.)

الگوریتمهای متعدد Clustering چه هستند؟
هر چند در این درس بیشتر تمرکز ما روی روش K-means خواهد بود، اما صرفا جهت آشنایی در تصویر زیر روشهای متعدد Clustring را مشاهده میکنیم:

یادآوری: فاصله دو داده از رابطه زیر بدست میآید:

روش K-means به چه صورت عمل میکند؟
این روش در دستهبندی دو نکته را مد نظر قرار میدهد:
1- بیشترین شباهت عضو با همگروهی خودش
2- بیشترین تفاوت با اعضای سایر گروهها
برای شروع، ابتدا سه نقطه به صورت کاملا رندوم از میان دادهها انتحاب میکنیم (این سه نقطه داده نیستند، بلکه مرکز نواحی فرضی هستند):

سپس فاصله هر داده (each data) از این سه نقطه را حساب میکنیم. فاصلهای که کمتر باشد، تعیین میکند که آن داده، (نمونه) در کدام دسته قرار بگیرد:

حال مطابق با شکل زیر دیتا را به سه دسته فرضی تقسیم میکنیم:

سه نقطه اولیهای که انتخاب کردیم در Optimum ترین حالت نبودند. برای حل این مسئله باید در هر سکشن یک نقطه برآیند(یعنی میانگین نقطههای آن سکشن یا دسته) را پیدا کنیم. برای بدست آوردن میانگین نقطهها در هر سکشن به روش زیر عمل میکنیم:

در سکشن 2 تنها دو نقطه داریم که مختصات هرکدام مشخص است. بنابراین برآیند سکشن دوم برابر با میانگین دو نقطه خواهد بود. در مورد سایر سکشنها هم به همین ترتیب عمل میکنیم. یعنی جمع طولها تقسیم بر تعداد آنها و جمع عرضها تقسیم بر تعداد آنها، مختصات طول و عرض برآیند را به ما خواهد داد. مقدار جابجایی مراکز هر سکشن با فلش قرمز مشخص شده است). بعد از انجام این مرحله، مراکز جدیدی (new Centroid) خواهیم داشت. بعد از این عمل ممکن است بعضی از دیتاها از گروهی به گروه دیگر منتقل شوند.

این مراحل را چندین مرتبه تکرار میکنیم و در هر مرحله یک Central point جدید بدست میآوریم.

و مشاهده خواهیم کرد که به تدریج به حالت پایداری خواهیم رسید:

نکته:
تضمینی وجود ندارد که ما به حالت Steady state برسیم. چون این موضوع به انتخاب اولیه نقاط c1, c2, c3 بسیار وابسته است. بنابراین، باید چندین مرتبطه c1,c2,c3 های مختلف را حساب کنیم و از بین آنها Optimum ترین حالت را انتخاب کنیم. ولی اگر به دقت بالایی نیاز نداریم ، همین یک مرتبه کفایت میکند.
از کجا بدانیم که به سه دسته تقسیم کنیم؟
میدانیم که با افزایش تعداد k (تعداد دستهها) مقدار SSE یا جمع فواصل کمتر خواهد شد. با افزایش تعداد k از یک مقدار به بعد کاهش محسوس SSE را مشاهده میکنیم. که نشان دهنده تعداد مطلوب K است. که به آن Elbow یا آرنج (به دلیل شباهت) میگویند.

ضمنا این محاسبات زمانی بدرد میخورد که ما Domain Knowledge لازم نسبت به دیتا را نداشته باشیم. یعنی ممکن است، دیتا را بشناسیم و مقدار k را به راحتی تعیین کنیم.

حال به سراغ پایتون میرویم:
ابتدا کتابخانههای مورد نیاز را فراخوانی میکنیم:
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
در این مسئله با استفاده از family موسوم به dataset در scikitlearn کتابخانه make_blobs را ایمپورت کرده و یک دیتاست میسازیم. در پرانتز hyper parameter ها را تعیین میکنیم. تعداد نمونهها 200 تا، تعداد فیچر یا ستونها 2 تا، تعداد مراکز 4 تا، std یا میزان پراکندگی را 1.8 تعیین میکنیم. یعنی نه خیلی پراکنده و نه خیلی متراکم. پارامترrandom_state را نیز برای یکسان شدن نتایج (ویدئوی آموزشی و دانشجو) یک عدد معین میگیریم.
from sklearn.datasets import make_blobs
# Create Data
data = make_blobs(n_samples=200, n_features=2,
centers=4, cluster_std=1.8,random_state=101)
نگاهی به داده خود میاندازیم و با استفاده از type متوجه میشویم که داده ما از نوع تاپل است:
--> data
-->type(data)
دیتای ما دو آرایه دارد آرایه اول خود از دو ستون تشکیل شده است که همان فیچرهای ما (مشابه نقاطی با مختصات x و y در صفحه مختصات) هستند:
len(data)-->
--> data[0]--> an array with 2 member
data[0][1,0]--> 5.868678884919712
data[0][1,1]--> 5.201103558017895

و آرایه دوم یک لیست است که نشانگر مختصات central points است:
data[1]--> a list
data[1][5]--> 1

در ادامه سعی میکنیم دیتای خود را مصورسازی کنیم. در تصویر زیر xهای ما ستون اول از data[0] و yها همان ستون دوم از data[0] هستند. یعنی به سادگی نقاط با مختصات xوy را ترسیم نمودهایم. ضمن اینکهhue را برابر با central points گذاشتهایم که به وضوح مشخص باشد که هر نقطه در کدام دسته قرار دارد:
sns.scatterplot(x=data[0][:,0],y=data[0][:,1],hue=data[1],palette='tab10')

تا اینجا متوجه شدیم که دیتای ما در چه وضعیتی قرار دارد. حال میخواهیم ببینیم آیا با استفاده از روش k-means میتوانیم تعداد دستههای دیتای موجود را تعیین کنیم یا نه. ابتدا کتابخانه KMeans را از cluster family ایمپورت میکنیم. سپس نام kmeans را برای آن انتخاب و تعداد دسته را برابر با 4 میگذاریم و روی data[0] که در واقع همان نقاط با مختصات x و y هستند، فیت میکنیم.
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=4)
kmeans.fit(data[0])
بعد از زمان کوتاهی، مدل ما نقاط مرکز دستهها را تشخیص داده است و با دستور زیر میتوان به آن دست یافت:
kmeans.cluster_centers_

با دستور زیر میتوان تعیین کرد که هر داده در کدام دسته قرار گرفته است:
kmeans.labels_

حال با استفاده از مصورسازی میخواهیم ببینیم که آیا نقاط بدست آمده با استفاده از روش kmeans و آنچه که در data[1] وجود داشت، با هم همخوانی دارند یا نه.
centers_1=data[1]
centers_2=kmeans.labels_
#print(len(centers_1))--> 200
#print(len(centers_2))--> 200
#----------------------------------------
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,6))
ax1.set_title('centers_1')
ax1.scatter(x=[i for i in range(0,200)],y=centers_1)
ax2.set_title("centers_2")
ax2.scatter(x=[i for i in range(0,200)],y=centers_2)

روش دیگر برای مقایسه:
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,6))
ax1.set_title('K Means')
ax1.scatter(x=data[0][:,0],y=data[0][:,1],c=kmeans.labels_,cmap='tab10')
ax2.set_title("Original")
ax2.scatter(x=data[0][:,0],y=data[0][:,1],c=data[1],cmap='tab10')

حال به صورت عمدی تعداد clusterها را برابر با 3 میگیریم و روی دیتای خود فیت میکنیم.
kmeans = KMeans(n_clusters=3)
kmeans.fit(data[0])
حال مجددا تصویر را رسم میکنیم:
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,6))
ax1.set_title('K Means')
ax1.scatter(x=data[0][:,0],y=data[0][:,1],c=kmeans.labels_,cmap='tab10')
ax2.set_title("Original")
ax2.scatter(x=data[0][:,0],y=data[0][:,1],c=data[1],cmap='tab10')

که همانگونه که مشخص است تعداد دستهها در سمت چپ، سه تا است.
در پایان میتوان مقادیر مختلف را به clusters نسبت داد و نتیجه را مشاهده نمود. برای مثال اگر تعدا دستهها را برابر ده بگیریم خواهیم داشت:
kmeans = KMeans(n_clusters=10)
kmeans.fit(data[0])
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,6))
ax1.set_title('K Means')
ax1.scatter(x=data[0][:,0],y=data[0][:,1],c=kmeans.labels_,cmap='tab10')
ax2.set_title("Original")
ax2.scatter(x=data[0][:,0],y=data[0][:,1],c=data[1],cmap='tab10')

منابع:
1- ویدئو – خانوم مونا حاتمی (آموزش دیتا ساینس)
2-