الدرس 9 من 9
التعلم غير الموجّه: Clustering
لما مفيش label، والموديل يكتشف المجموعات لوحده.
المشكلة
سلسلة سوبر ماركت عندها بيانات آلاف العملاء: بيصرفوا قد إيه وبييجوا كام مرة. مفيش حد قال مين «عميل مميز» ومين «عميل عابر». الـ Clustering بيجمّع العملاء اللي شبه بعض في مجموعات، وانت تفهم كل مجموعة وتعمل لها عروض مناسبة.
K-Means: خطوة خطوة
- اختار عدد المجموعات K، وحط K نقطة عشوائية كمراكز.
- كل عميل ينضم لأقرب مركز ليه (بالمسافة اللي اتعلمناها في درس المتجهات).
- حرّك كل مركز لمتوسط العملاء اللي انضموا له.
- كرر لحد ما المراكز تثبت.
import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler rng = np.random.default_rng(0) customers = pd.DataFrame({ "visits": np.concatenate([rng.normal(3, 1, 80), rng.normal(12, 2, 60), rng.normal(6, 1.5, 60)]).clip(1), "spend": np.concatenate([rng.normal(400, 120, 80), rng.normal(2500, 400, 60), rng.normal(5200, 700, 60)]).clip(50), }) X = StandardScaler().fit_transform(customers) # distances need same scale! kmeans = KMeans(n_clusters=3, n_init=10, random_state=0).fit(X) customers["segment"] = kmeans.labels_ print(customers.groupby("segment").mean().round(0)) plt.figure(figsize=(7, 3.8)) plt.scatter(customers["visits"], customers["spend"], c=customers["segment"], cmap="viridis", s=25) plt.xlabel("visits per month") plt.ylabel("monthly spend (EGP)") plt.title("Customer segments found by K-Means") plt.show()
الموديل لقى ٣ شرايح واضحة من غير ما حد يقوله: عملاء بييجوا قليل ويصرفوا قليل، وعملاء بييجوا كتير جداً بمبالغ متوسطة (غالباً بيشتروا يومي من جنب البيت)، وعملاء مش بييجوا كتير بس بيصرفوا جامد (مشتريات الشهر الكبيرة). كل شريحة محتاجة عرض مختلف.
⚠ الـ Scaling هنا إجباريالمصروف بالآلاف والزيارات بالآحاد. من غير
StandardScaler المسافة هتتحسب تقريباً على المصروف بس، والزيارات مش هتفرق. نفس المشكلة اللي شفناها في مسافة الشقق في المرحلة ٣.طيب أختار K كام؟ Elbow Method
import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler rng = np.random.default_rng(0) visits = np.concatenate([rng.normal(3, 1, 80), rng.normal(12, 2, 60), rng.normal(6, 1.5, 60)]) spend = np.concatenate([rng.normal(400, 120, 80), rng.normal(2500, 400, 60), rng.normal(5200, 700, 60)]) X = StandardScaler().fit_transform(np.column_stack([visits, spend])) ks = range(1, 9) inertia = [KMeans(n_clusters=k, n_init=10, random_state=0).fit(X).inertia_ for k in ks] plt.figure(figsize=(7, 3.4)) plt.plot(ks, inertia, marker="o", color="#3776AB") plt.xlabel("number of clusters (K)") plt.ylabel("inertia (lower = tighter)") plt.title("Elbow method") plt.grid(alpha=0.3) plt.show()
الـ inertia بتقيس المجموعات متلمّة قد إيه. هي بتقل دايماً كل ما تزود K، بس عند نقطة معينة التحسن بيبقى صغير جداً. النقطة دي هي «الكوع» (elbow)، وهنا واضح إنها عند ٣.
🤖 استخدامات تانيةكشف المعاملات الغريبة (اللي مش قريبة من أي مجموعة ممكن تبقى احتيال)، وتجميع المقالات حسب الموضوع، وضغط الصور بتقليل عدد الألوان. وفي المرحلة ٧ هتجمّع embeddings النصوص بنفس الطريقة.