التجميع وتخفيض الأبعاد
درس 7 من 8
7التجميع وتخفيض الأبعاد
الصورة الكبيرةالتجميع وتخفيض الأبعاد يعملان بلا جواب صحيح، ولهذا هما أسهل أداتين في خداع نفسك. k-means سيعطيك مجموعات حتى لو لم توجد، وPCA سيعطيك محاور حتى لو لم تعنِ شيئًا. السؤال دائمًا: هل هذا اكتشاف أم وهم جميل؟
ماذا تشاهد في الرسم: نقاط مبعثرة تتجمّع حول ثلاثة مراكز، كما يفعل k-means: ينسب كل نقطة إلى أقرب مركز، ثم ينقل كل مركز إلى متوسط نقاطه. لكنه سيعطيك مجموعات حتى على ضجيج عشوائي، فالرسم الجميل وحده ليس دليلًا.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
عندك كومة صور بلا أسماء، وتريد أن تجمع المتشابه معًا. التجميع يضع كل صورة في أقرب مجموعة، ثم يعدّل مركز كل مجموعة، ويكرر. وتخفيض الأبعاد مثل التقاط صورة لمجسّم من أفضل زاوية: تخسر بعض التفاصيل، لكنك ترى الشكل بوضوح.
k-means يختار k مراكز ويكرر الإسناد والتحديث حتى الاستقرار، ويُختار k بمنحنى المرفق أو معامل silhouette. وPCA يُسقط البيانات على اتجاهات أكبر تباين. والمجموعات قد تكون أثرًا للمقياس أو للخوارزمية لا حقيقة في البيانات، فتتحقق منها.
قبل أن تبدأ
🔧توحيد المقاييس
تعرف من درس هندسة السمات أن الخوارزميات المعتمدة على المسافة تحتاج مدخلات موحّدة.
🧭المتجه والمسافة
ترى كل صف نقطة في فضاء، كما في درس الجبر الخطي، وتعرف معنى المسافة بين نقطتين.
الفكرة الجوهرية
هنا لا يوجد جواب صحيح، وهذا ما يجعل خداع النفس سهلًا. تبني k-means على مجموعات حقيقية، ثم تختار k بمقياسين، ثم تشغّله على ضجيج لترى الوهم، ثم تقلّل الأبعاد بـ PCA.
1k-means على مجموعات حقيقية
k-means يبحث عن k مراكز بحيث تكون كل نقطة قريبة من أقرب مركز لها. يفترض مجموعات مستديرة متقاربة الحجم.
نصنع ثلاث مجموعات بأيدينا، ثم نرى هل يجدها.
import numpy as np
from sklearn.cluster import KMeans
rng = np.random.default_rng(0)
centres = np.array([[2, 2], [8, 3], [5, 8]])
points = np.vstack([c + rng.normal(scale=0.8, size=(50, 2)) for c in centres])
km = KMeans(n_clusters=3, n_init=10, random_state=0).fit(points)
for c in sorted(km.cluster_centers_.round(1).tolist()):
print("centre:", c)
print("sizes:", sorted(np.bincount(km.labels_).tolist()))
صنعنا ثلاث مجموعات حول (2,2) و(8,3) و(5,8)، وk-means وجد مراكز قريبة جدًّا منها، وخمسين نقطة في كل مجموعة. هنا الجواب معروف لأننا صنعنا البيانات. في الواقع لن تعرفه، وهذا كل التحدّي.
النتيجة تعتمد على المراكز الأولى العشوائية، لذلك يعيد n_init=10 التشغيل من عشر بدايات ويحتفظ بالأفضل. ووحّد المدخلات قبله دائمًا، لأنه يعتمد على المسافة.
2اختيار k بمقياسين
القصور الذاتي هو مجموع مربّعات المسافات إلى المراكز، وينخفض دائمًا مع زيادة k. السيلويت بين -1 و1، ويقيس كم كل نقطة أقرب إلى مجموعتها منها إلى غيرها.
انظر إلى الرسم: القصور ينهار عند k = 3 ثم يهدأ، وهذا هو الكوع. والسيلويت يبلغ ذروته عند نفس النقطة.
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
rng = np.random.default_rng(0)
centres = np.array([[2, 2], [8, 3], [5, 8]])
points = np.vstack([c + rng.normal(scale=0.8, size=(50, 2)) for c in centres])
for k in range(2, 7):
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(points)
print(f"k={k} inertia={km.inertia_:7.1f} silhouette={silhouette_score(points, km.labels_):.3f}")
القصور الذاتي يسقط من 1080 إلى 193 بين k=2 وk=3، ثم ينخفض ببطء: هذا هو الكوع. والسيلويت يبلغ ذروته 0.750 عند k=3 ثم يهبط. المقياسان يتفقان، وهذا نادر في البيانات الحقيقية، حيث يكون الكوع غالبًا منحنى ناعمًا بلا زاوية واضحة.
3مجموعات من لا شيء
k-means يعطيك دائمًا k مجموعات، حتى على ضجيج عشوائي تمامًا. لا يقول لك أبدًا «لا توجد مجموعات هنا».
نقاط موزّعة بانتظام عشوائي على مربّع، بلا أي مجموعات. اطلب من k-means أربع مجموعات.
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
rng = np.random.default_rng(0)
noise = rng.uniform(0, 10, size=(150, 2))
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(noise)
print("sizes:", sorted(np.bincount(km.labels_).tolist()))
print(f"silhouette: {silhouette_score(noise, km.labels_):.3f}")
أربع مجموعات بأحجام معقولة، وسيلويت 0.396 الذي قد يبدو مقبولًا. لو رسمتها بأربعة ألوان لبدت «شرائح عملاء» مقنعة جدًّا. لهذا قارن دائمًا بالضجيج: إن كان السيلويت على بياناتك قريبًا مما تعطيه بيانات عشوائية بنفس الشكل، فلا توجد مجموعات حقيقية.
السيلويت فوق 0.5 فصل واضح، وحول 0.25 فصل ضعيف. لكن المرجع الحقيقي هو ما يعطيه الضجيج بنفس الشكل: 0.750 على بياناتنا مقابل 0.396 على الضجيج.
4PCA: كم بعدًا تحتاج
PCA يدوّر المحاور ويرتّبها حسب التباين. الأول هو الاتجاه الذي تنتشر فيه البيانات أكثر، والثاني عمودي عليه.
انظر إلى الرسم: كم مكوّنًا تحتاج من 64 لتحتفظ بنسبة من المعلومات.
صور الأرقام المكتوبة بخط اليد في scikit-learn: كل صورة 8×8، أي 64 عمودًا.
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X, y = load_digits(return_X_y=True)
pca = PCA().fit(StandardScaler().fit_transform(X))
cum = pca.explained_variance_ratio_.cumsum()
print("original dims:", X.shape[1])
for target in [0.5, 0.8, 0.95]:
print(f"{int(target * 100)}% variance -> {int((cum < target).sum()) + 1} components")
ثمانية مكوّنات تحمل نصف المعلومات، وأربعون تحمل 95%. أي أن ربع الأعمدة تقريبًا زائد. لكن تذكّر: «التباين» ليس «الفائدة». اتجاه بتباين صغير قد يكون بالضبط ما يميّز الفئتين اللتين تهمّانك.
كيف يعمل، خطوة بخطوة: كيف يجد k-means مجموعاته
ضع k مراكز في مواضع عشوائية.
انسب كل نقطة إلى أقرب مركز إليها.
انقل كل مركز إلى متوسط النقاط المنسوبة إليه.
كرّر الخطوتين حتى تستقر المراكز، وأعِد ذلك كله من عدة بدايات بـ n_init واحتفظ بالأفضل.
مثال محلول
k-means يبحث عن k مراكز بحيث تكون كل نقطة قريبة من أقرب مركز. الخوارزمية بسيطة: ضع مراكز عشوائية، انسب كل نقطة لأقرب مركز، انقل كل مركز إلى متوسط نقاطه، وكرّر حتى تستقر.
٢. n_init يحمي من البداية السيئة
النتيجة تعتمد على المراكز العشوائية الأولى. n_init=10 يعيد الخوارزمية عشر مرات من بدايات مختلفة ويأخذ الأفضل. وحّد المدخلات قبل k-means دائمًا، لأنه يعتمد على المسافة.
جرّب بلا كود
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| إذا أعطى k-means مجموعات، فالمجموعات موجودة. | على نقاط عشوائية موزّعة بانتظام أعطى أربع مجموعات معقولة الحجم وسيلويت 0.396. قارن دائمًا بما يعطيه الضجيج. |
| التباين الأكبر في PCA يعني الاتجاه الأهم. | التباين ليس فائدة. اتجاه تباينه صغير قد يكون بالضبط ما يفصل الفئتين اللتين تهمّانك. |
| يمكن تسمية المجموعة بعد التشغيل الأول مباشرة. | أعِد التجميع على عيّنة أخرى أو ببذرة مختلفة أولًا. إذا تغيّرت المجموعات كثيرًا، فاسم مثل «العملاء الأوفياء» قصة اخترعتها. |
جرّب بنفسك
شغّلت k-means على بيانات العملاء دون توحيد، وفيها «الإنفاق السنوي» بالآلاف و«عدد الزيارات» من 1 إلى 30. ما النتيجة المتوقّعة؟
المسافة الإقليدية تهيمن عليها السمة ذات الأرقام الأكبر. فرق ألف ريال يساوي في المسافة ألف زيارة، فتصير الزيارات غير مرئية تقريبًا. وحّد السمات قبل أي خوارزمية تعتمد على المسافة.
PCA أظهر أن أول مكوّنين يفسّران 92% من التباين. ماذا يعني هذا؟
التباين المفسَّر يقول كم من انتشار البيانات يلتقطه المكوّنان، فالرسم بهما أمين لشكل البيانات. لكنه لا يقول إن الـ8% الباقية بلا فائدة للتصنيف، ولا علاقة له بعدد المجموعات.
بطاقات مراجعة سريعة
تحقق من فهمك
لماذا ينخفض القصور الذاتي دائمًا مع زيادة k، ولماذا يعني ذلك أنه لا يصلح وحده لاختيار k؟
لأن مركزًا إضافيًا لا يمكن أن يزيد المسافات: في أسوأ الحالات يبقى بلا فائدة، وغالبًا يقرّب بعض النقاط. وعند k يساوي عدد النقاط يصير القصور الذاتي صفرًا، كل نقطة مجموعة بنفسها. فأقل قصور ذاتي يعني دائمًا أكبر k، ولهذا نبحث عن النقطة التي يتوقّف بعدها التحسّن الكبير، ونستعين بالسيلويت أو بمعنى المجموعات.
لماذا يفشل k-means على المجموعات المتطاولة أو المتداخلة؟
لأنه ينسب كل نقطة إلى أقرب مركز، فيفترض مجموعات مستديرة متقاربة الحجم. المجموعة المتطاولة تُقطع أجزاءً، والمتداخلة تُدمج خطأً.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي1
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.