الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

الدليل النهائي لتجميع الوسائل التعليمية K-Means باستخدام Scikit-Learn

المُقدّمة

يعني 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 إحداثيات للمحلات العشرة التي تم جمعها. بعد تنظيمهم في أ 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 باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

كيفية تنفيذ خوارزمية K-Means يدويًا

يمكننا الآن إلقاء نظرة على المتاجر العشرة على الرسم البياني ، والمشكلة الرئيسية هي معرفة هل هناك طريقة يمكن تقسيمها إلى مجموعات مختلفة بناءً على القرب؟ بمجرد إلقاء نظرة سريعة على الرسم البياني ، سنلاحظ على الأرجح مجموعتين من المتاجر - واحدة هي النقاط السفلية إلى أسفل اليسار ، والأخرى هي النقاط العلوية اليمنى. ربما يمكننا حتى التمييز بين هاتين النقطتين في المنتصف كمجموعة منفصلة - وبالتالي إنشاء ثلاث مجموعات مختلفة.

في هذا القسم ، سوف ننتقل إلى عملية تجميع النقاط يدويًا - تقسيمها إلى عدد معين من المجموعات. بهذه الطريقة ، سننتقل بعناية إلى جميع خطوات ملف K- يعني خوارزمية التجميع. بنهاية هذا القسم ، ستكتسب فهمًا بديهيًا وعمليًا لجميع الخطوات التي يتم إجراؤها أثناء تجميع K-Means. بعد ذلك ، سنقوم بتفويضه إلى Scikit-Learn.

ما هي أفضل طريقة لتحديد ما إذا كانت هناك مجموعتان أو ثلاث مجموعات من النقاط؟ تتمثل إحدى الطرق البسيطة في اختيار عدد واحد من المجموعات - على سبيل المثال ، اثنان - ثم محاولة تجميع النقاط بناءً على هذا الاختيار.

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من 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_.

قد يكون من المفيد معرفة أن قياس المسافة الإقليدية يعتمد على نظرية فيثاغورس:

$$
ج ^ 2 = أ ^ 2 + ب ^ 2
$$

عندما تتكيف مع نقاط في الطائرة - (a1, b1) و (a2, b2)، تصبح الصيغة السابقة:

$$
ج ^ 2 = (a2-a1) ^ 2 + (b2-b1) ^ 2
$$

ستكون المسافة هي الجذر التربيعي لـ c، حتى نتمكن أيضًا من كتابة الصيغة على النحو التالي:

$$
euclidean_ {dist} = sqrt [2] [(a2 - a1) ^ 2 + (b2 - b1) ^ 2)]
$$

ملحوظة: يمكنك أيضًا تعميم صيغة المسافة الإقليدية للنقاط متعددة الأبعاد. على سبيل المثال ، في الفضاء ثلاثي الأبعاد ، تحتوي النقاط على ثلاثة إحداثيات - وتعكس صيغتنا ذلك بالطريقة التالية:
$$
euclidean_ {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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

من الواضح أنه تم تخصيص النقطة الأولى فقط للمجموعة 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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

يبدو أن تجميع نقاطنا هو يتحسن. ولكن لا تزال هناك نقطتان في منتصف الرسم البياني يمكن تخصيصهما لأي من المجموعتين عند النظر في قربهما من كلا المجموعتين. تقوم الخوارزمية التي طورناها حتى الآن بتعيين هاتين النقطتين إلى المجموعة الثانية.

هذا يعني أنه يمكننا على الأرجح تكرار العملية مرة أخرى بأخذ وسائل X و Y ، وإنشاء نقطتين مركزيتين جديدتين (النقطه الوسطى) لمجموعاتنا وإعادة تخصيصها بناءً على المسافة.

لنقم أيضًا بإنشاء وظيفة لتحديث النقط الوسطى. يمكن الآن اختزال العملية برمتها إلى استدعاءات متعددة لهذه الوظيفة:

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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

لاحظ أنه بعد هذا التكرار الثالث ، تنتمي كل نقطة الآن إلى مجموعات مختلفة. يبدو أن النتائج تتحسن - فلنقم بذلك مرة أخرى. يذهب الآن إلى التكرار الرابع من طريقتنا:

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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

هذه المرة الرابعة وصلنا نفس النتيجة كالسابق. لذلك يبدو أن نقاطنا لن تغير المجموعات بعد الآن ، فقد وصلت نتيجتنا إلى نوع من الاستقرار - لقد وصلت إلى حالة غير قابلة للتغيير ، أو تلاقت. إلى جانب ذلك ، لدينا نفس النتيجة تمامًا كما تصورنا للمجموعتين. يمكننا أيضًا معرفة ما إذا كان هذا التقسيم الذي تم التوصل إليه منطقيًا.

دعنا نلخص بسرعة ما فعلناه حتى الآن. قسمنا متاجرنا العشرة جغرافيًا إلى قسمين - قسم في المناطق الجنوبية الغربية السفلية والآخر في الشمال الشرقي. قد يكون من المثير للاهتمام جمع المزيد من البيانات إلى جانب ما لدينا بالفعل - الإيرادات والعدد اليومي للعملاء وغير ذلك الكثير. بهذه الطريقة يمكننا إجراء تحليل أكثر ثراءً وربما الحصول على نتائج أكثر إثارة للاهتمام.

يمكن إجراء دراسات مجمعة مثل هذه عندما تريد علامة تجارية قائمة بالفعل اختيار منطقة لفتح متجر جديد. في هذه الحالة ، هناك العديد من المتغيرات التي تؤخذ في الاعتبار إلى جانب الموقع.

ما علاقة كل هذا بخوارزمية K-Means؟

أثناء اتباع هذه الخطوات ، ربما تساءلت عما يجب عليهم فعله مع خوارزمية K-Means. العملية التي أجريناها حتى الآن هي خوارزمية K-Means. باختصار ، لقد حددنا عدد المجموعات / المجموعات ، واخترنا النقاط الأولية بشكل عشوائي ، وقمنا بتحديث النقط الوسطى في كل تكرار حتى تتقارب المجموعات. لقد أجرينا الخوارزمية بالكامل يدويًا - ونفذنا كل خطوة بعناية.

K في K-Means يأتي من عدد المجموعات التي يجب تعيينها قبل بدء عملية التكرار. في حالتنا هذه K = 2. يُنظر إلى هذه الخاصية أحيانًا على أنها سلبي مع الأخذ في الاعتبار أن هناك طرق أخرى للتجميع ، مثل Hierarchical Clustering ، والتي لا تحتاج إلى عدد ثابت من المجموعات مسبقًا.

نظرًا لاستخدامها للوسائل ، تصبح K-mean أيضًا حساسة للقيم المتطرفة والقيم المتطرفة - إنها تعزز التباين وتجعل من الصعب على النقطتين الوسطى لدينا أن تلعب دورها. لذا ، كن مدركًا للحاجة إلى الأداء القيم المتطرفة والتحليل الناشز قبل إجراء التجميع باستخدام خوارزمية K-Means.

لاحظ أيضًا أن نقاطنا مقسمة إلى أجزاء مستقيمة ، ولا توجد منحنيات عند إنشاء المجموعات. يمكن أن يكون ذلك أيضًا عيبًا في خوارزمية K-Means.

ملحوظة: عندما تحتاج إلى أن يكون أكثر مرونة وقابلية للتكيف مع الأشكال الناقصة والأشكال الأخرى ، جرب استخدام ملف معمم K- يعني نموذج خليط غاوسي. يمكن أن يتكيف هذا النموذج مع مجموعات التجزئة الإهليلجية.

K-Means لديها أيضًا الكثير مزايا! يعمل بشكل جيد على مجموعات كبيرة من البيانات التي يمكن أن يصبح من الصعب التعامل معها إذا كنت تستخدم بعض أنواع خوارزميات المجموعات الهرمية. كذلك يضمن التقاربويمكن بسهولة عمم و تكيف. إلى جانب ذلك ، من المحتمل أن تكون خوارزمية التجميع الأكثر استخدامًا.

الآن بعد أن انتهينا من جميع الخطوات التي تم إجراؤها في خوارزمية K-Means ، وفهمنا جميع مزاياها وعيوبها ، يمكننا أخيرًا تنفيذ K-Means باستخدام مكتبة Scikit-Learn.

كيفية تنفيذ خوارزمية K-Means باستخدام سكيكيت ليرن

لمضاعفة التحقق من نتيجتنا ، لنقم بهذه العملية مرة أخرى ، ولكن الآن نستخدم 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_)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

المؤامرة الناتجة هي نفسها التي من القسم السابق.

تحقق من دليلنا العملي العملي لتعلم Git ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!

ملحوظة: مجرد النظر إلى كيفية قيامنا بخوارزمية K-Means باستخدام Scikit-Learn قد يمنحك انطباعًا بأن الشخص لا يحتاج إلى تفكير وأنه لا داعي للقلق كثيرًا بشأنه. تقوم ثلاثة أسطر فقط من التعليمات البرمجية بتنفيذ جميع الخطوات التي ناقشناها في القسم السابق عندما تجاوزنا خوارزمية K-Means خطوة بخطوة. ولكن، الشر في التفاصيل في هذه الحالة! إذا كنت لا تفهم كل خطوات وقيود الخوارزمية ، فمن المرجح أنك ستواجه الموقف الذي تمنحك فيه خوارزمية K-Means النتائج التي لم تكن تتوقعها.

باستخدام Scikit-Learn ، يمكنك أيضًا تهيئة K-Means لتقارب أسرع عن طريق تعيين init='k-means++' جدال. بعبارات أوسع ، K- يعني ++ لا يزال يختار 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 = sum (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
$$

$$
دبليو سي إس إس = 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 باستخدام سكيكيت ليرن

لحسن الحظ ، لا نحتاج إلى حساب WCSS يدويًا لكل منهما K. بعد إجراء تجميع K-Means لعدد معين من المجموعات ، يمكننا الحصول على WCSS الخاص به باستخدام inertia_ ينسب. الآن ، يمكننا العودة إلى K-Means for loop ، استخدمها لتبديل عدد المجموعات ، وقم بإدراج قيم 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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

هناك انقطاع في المؤامرة عندما 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 باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

يمكننا تشغيل خوارزمية مجموعة K-Means مرة أخرى ، لنرى كيف ستبدو بياناتنا ثلاث مجموعات:

kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(points)
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

كنا سعداء بالفعل بمجموعتين ، ولكن وفقًا لطريقة الكوع ، ستكون ثلاث مجموعات أكثر ملاءمة لبياناتنا. في هذه الحالة ، سيكون لدينا ثلاثة أنواع من المتاجر بدلاً من اثنين. قبل استخدام طريقة الكوع ، فكرنا في مجموعات المتاجر الجنوبية الغربية والشمالية الشرقية ، والآن لدينا أيضًا متاجر في المركز. ربما يكون هذا موقعًا جيدًا لفتح متجر آخر لأنه سيكون لديه منافسة أقل في مكان قريب.

مقاييس جودة الكتلة البديلة

هناك أيضًا مقاييس أخرى يمكن استخدامها عند تقييم جودة الكتلة:

  • نتيجة صورة ظلية - يحلل ليس فقط المسافة بين نقاط داخل المجموعة ولكن أيضًا بين المجموعات نفسها
  • بين العناقيد مجموع المربعات (BCSS) - متري مكمل لـ WCSS
  • مجموع خطأ المربعات (جنوب شرق أوروبا)
  • أقصى نصف قطر - يقيس أكبر مسافة من نقطة إلى النقطه الوسطى
  • متوسط ​​نصف القطر - مجموع أكبر مسافة من نقطة إلى النقطه الوسطى مقسومًا على عدد العناقيد.

يوصى بإجراء التجربة والتعرف على كل منها نظرًا لأنه اعتمادًا على المشكلة ، يمكن أن تكون بعض البدائل أكثر قابلية للتطبيق من المقاييس الأكثر استخدامًا (WCSS و Silhouette Score).

في النهاية ، كما هو الحال مع العديد من خوارزميات علوم البيانات ، نريد تقليل التباين داخل كل مجموعة وزيادة التباين بين المجموعات المختلفة. لذلك لدينا مجموعات أكثر تحديدًا وقابلة للفصل.

تطبيق K-Means على مجموعة بيانات أخرى

دعنا نستخدم ما تعلمناه في مجموعة بيانات أخرى. هذه المرة ، سنحاول العثور على مجموعات من النبيذ المتشابه.

ملحوظة: يمكنك تنزيل مجموعة البيانات هنا.

نبدأ بالاستيراد pandas لقراءة wine-clustering CSV (قيم مفصولة بفواصل) ملف في ملف 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)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

من خلال النظر إلى حبكة الزوج ، يبدو أن هناك عمودين واعدتين لأغراض التجميع - Alcohol و OD280 (وهي طريقة لتحديد تركيز البروتين في النبيذ). يبدو أن هناك 3 مجموعات متميزة على قطع الأرض تجمع بين اثنتين منها.

هناك أعمدة أخرى يبدو أنها مرتبطة أيضًا. الجدير بالذكر Alcohol و Total_Phenolsو Alcohol و Flavanoids. لديهم علاقات خطية كبيرة يمكن ملاحظتها في حبكة الزوج.

نظرًا لأن تركيزنا ينصب على التجميع باستخدام K-Means ، فلنختار زوجًا واحدًا من الأعمدة ، على سبيل المثال Alcohol و OD280، واختبر طريقة الكوع لمجموعة البيانات هذه.

ملحوظة: عند استخدام المزيد من أعمدة مجموعة البيانات ، ستكون هناك حاجة للتخطيط في 3 أبعاد أو تقليل البيانات إلى المكونات الرئيسية (استخدام PCA). هذا نهج صالح وأكثر شيوعًا ، فقط تأكد من اختيار المكونات الأساسية بناءً على مقدار شرحها وتذكر أنه عند تقليل أبعاد البيانات ، يكون هناك بعض فقدان المعلومات - لذا فإن المؤامرة هي تقريب من البيانات الحقيقية ، وليس كيف هي بالفعل.

دعنا نرسم مخطط التشتت مع هذين العمودين المعينين ليكونا محوره لإلقاء نظرة فاحصة على النقاط التي نريد تقسيمها إلى مجموعات:

sns.scatterplot(data=df, x='OD280', y='Alcohol')

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

الآن يمكننا تحديد أعمدةنا واستخدام طريقة الكوع لتحديد عدد المجموعات. سنبدأ أيضًا الخوارزمية باستخدام 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')

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

وفقًا لطريقة الكوع ، يجب أن يكون لدينا 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_)

الدليل النهائي لتجميع K-Means باستخدام ذكاء بيانات PlatoBlockchain من Scikit-Learn. البحث العمودي. منظمة العفو الدولية.

يمكننا أن نرى العناقيد 0, 1و 2 في الرسم البياني. بناءً على تحليلنا ، مجموعة 0 يحتوي على نبيذ يحتوي على نسبة عالية من البروتين ونسبة كحول أقل ، مجموعة 1 يحتوي على نبيذ يحتوي على نسبة عالية من الكحول وبروتين منخفض ، و مجموعة 2 يحتوي على نسبة عالية من البروتين والكحول في النبيذ.

هذه مجموعة بيانات مثيرة جدًا للاهتمام وأنا أشجعك على المضي قدمًا في التحليل من خلال تجميع البيانات بعد التطبيع و PCA - أيضًا من خلال تفسير النتائج وإيجاد اتصالات جديدة.

وفي الختام

K- الوسائل التجميع هو خوارزمية تعلم آلي بسيطة لكنها فعالة للغاية غير خاضعة للإشراف لتجميع البيانات. يقوم بتجميع البيانات بناءً على المسافة الإقليدية بين نقاط البيانات. تحتوي خوارزمية التجميع K-Means على العديد من الاستخدامات لتجميع المستندات النصية والصور ومقاطع الفيديو وغير ذلك الكثير.

الطابع الزمني:

اكثر من ستاكابوز