الدرس 9 من 9

التعلم غير الموجّه: Clustering

لما مفيش label، والموديل يكتشف المجموعات لوحده.

المشكلة

سلسلة سوبر ماركت عندها بيانات آلاف العملاء: بيصرفوا قد إيه وبييجوا كام مرة. مفيش حد قال مين «عميل مميز» ومين «عميل عابر». الـ Clustering بيجمّع العملاء اللي شبه بعض في مجموعات، وانت تفهم كل مجموعة وتعمل لها عروض مناسبة.

K-Means: خطوة خطوة

  • اختار عدد المجموعات K، وحط K نقطة عشوائية كمراكز.
  • كل عميل ينضم لأقرب مركز ليه (بالمسافة اللي اتعلمناها في درس المتجهات).
  • حرّك كل مركز لمتوسط العملاء اللي انضموا له.
  • كرر لحد ما المراكز تثبت.
kmeans.py
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

elbow.py
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 النصوص بنفس الطريقة.
الدرس اللي فات