الوحدة 1 · ما هو تعلّم الآلة
خطوط الأساس: النموذج الذي يجب التغلّب عليه
17 دقراءة 4 دتمرين Python
الدرس في لمحة
ابنِ خطَّي الأساس اللذين يجب أن يتفوّق عليهما كل نموذج، أي نموذج وهمي يتنبأ بالفئة الأكثر شيوعًا وقاعدة عمل من سطر واحد، واحكم على النموذج بمقدار تحسّنه عليهما لا برقمه المجرّد.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
شجرتك بعمق 3 تتنبأ بالانقطاع بدقة 73% على عملاء لم ترَهم. قبل أن تعرض هذا الرقم على أحد، اطرح السؤال الذي يطرحه كل عالم بيانات متمرّس أولًا: مقارنةً بماذا؟ بلا مقارنة، 73% ليست جيدة ولا سيئة. إنها مجرد رقم.
أغبى نموذج ممكن
خط الأساس الأول يتجاهل الـ features تمامًا. في التصنيف يتنبأ بالفئة الأكثر شيوعًا للجميع. وفي الانحدار يتنبأ بالمتوسط. يوفّر scikit-learn كليهما كـ estimators حقيقية، فيندمجان في الكود نفسه الذي تكتبه لأي نموذج.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.dummy import DummyClassifier
churn = pd.read_csv("churn.csv")
features = ["tenure_days", "orders", "total_spent", "avg_order_value",
"days_since_last_order", "used_coupon", "support_tickets", "mobile_share"]
X_train, X_test, y_train, y_test = train_test_split(
churn[features], churn["churned"], test_size=0.25, random_state=42,
stratify=churn["churned"])
dummy = DummyClassifier(strategy="most_frequent").fit(X_train, y_train)
print("dummy predicts:", dummy.predict(X_test)[:5])
print("dummy accuracy:", dummy.score(X_test, y_test))التنبؤ بـ “منقطع” لكل عميل يصيب في 55% من الحالات، لأن 55% من العملاء انقطعوا فعلًا. هذا هو الحدّ الأدنى. ودقة شجرتك البالغة 73% تزيد عليه بـ 18 نقطة، وهذا تقدّم حقيقي، لكنك لم تنتهِ من الأسئلة بعد.
القاعدة التي كان سيكتبها شخص ما
خط الأساس الثاني هو الذي يؤلم. قبل تعلّم الآلة، كان أحدهم في Cartwheel سيكتب قاعدة: “إذا لم يطلب العميل شيئًا منذ N يومًا، فهو في طريقه إلى الانقطاع”. تختار N بالطريقة التي تدرّب بها نموذجًا: على بيانات التدريب وحدها.
import pandas as pd
from sklearn.model_selection import train_test_split
churn = pd.read_csv("churn.csv")
features = ["tenure_days", "orders", "total_spent", "avg_order_value",
"days_since_last_order", "used_coupon", "support_tickets", "mobile_share"]
X_train, X_test, y_train, y_test = train_test_split(
churn[features], churn["churned"], test_size=0.25, random_state=42,
stratify=churn["churned"])
def rule_accuracy(days, X, y):
predicted = (X["days_since_last_order"] > days).astype(int)
return (predicted == y).mean()
candidates = range(30, 301, 10)
best_days = max(candidates, key=lambda d: rule_accuracy(d, X_train, y_train))
print("best cut-off on training data:", best_days, "days")
print("rule accuracy on test data:", rule_accuracy(best_days, X_test, y_test))تحقق القاعدة 72% على بيانات الاختبار. وتحقق الشجرة 73%. على 100 عميل اختبار، هذا فرق شخص واحد.
هذا ليس فشلًا. بل هو أنفع ما تعلّمته حتى الآن. فهو يخبرك أن معظم الإشارة الدالّة على الانقطاع تكمن في عمود واحد، هو حداثة آخر طلب، وأن شجرة بثمانية features لم تضف عليه حتى الآن شيئًا يُذكر. ويعطيك أيضًا هدفًا: من الآن فصاعدًا، على النموذج أن يتفوّق على 72%، لا على 55%، كي يستحق الإطلاق والشرح والمراقبة.
خطوط الأساس في الانحدار
المقابل في الانحدار هو DummyRegressor، الذي يتنبأ بمتوسط التدريب لكل صف. وقيمة score (أي R²) على بيانات الاختبار قريبة من 0، لأن R² معرَّف على أنه التحسّن مقارنةً بالتنبؤ بالمتوسط. ستستخدمه في القسم 2.
from sklearn.datasets import load_diabetes
from sklearn.dummy import DummyRegressor
from sklearn.model_selection import train_test_split
X, y = load_diabetes(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
dummy = DummyRegressor(strategy="mean").fit(X_train, y_train)
print("predicts", round(dummy.predict(X_test)[0], 1), "for everyone")
print("R² on test:", round(dummy.score(X_test, y_test), 3))التحسّن لا النتيجة
من الآن فصاعدًا، اعرض النموذج بمقدار تحسّنه على خطوط الأساس: “accuracy بنسبة 73%، مقابل 55% للفئة الأكثر شيوعًا و72% لقاعدة الـ 80 يومًا”. هذه الجملة الواحدة تخبر القارئ أكثر مما يخبره أي رقم منفرد، وتحميك من خداع نفسك.
أبقِ خطوط الأساس في كودك، بجانب النماذج، وأعد تشغيلها كلما تغيّرت البيانات أو التقسيم. فخط الأساس المحسوب مرة واحدة على تقسيم قديم ثم المقتبس إلى الأبد أسوأ من عدم وجوده، لأنه يبدو كأنه دليل. عمليًا، يجب أن يضع جدول المقارنة في آخر الـ notebook النموذجَ الوهمي في الأعلى، وأفضل قاعدة تحته، ثم كل النماذج بعد ذلك، وكلها محسوبة على صفوف الاختبار نفسها تمامًا.
وكن صادقًا بشأن الضجيج أيضًا. مع 100 عميل اختبار، العميل الواحد يساوي نقطة مئوية واحدة، لذا قد تظهر فروق من نقطتين أو ثلاث أو تختفي مع خلط مختلف. سيستبدل القسم 4 التقسيمَ الواحد بالتحقق المتقاطع، الذي يخبرك كم تتذبذب النتيجة. وحتى ذلك الحين، عامِل الفجوات الصغيرة على أنها تعادل.
والـ accuracy ليست الطريقة الوحيدة للمقارنة أيضًا. فالنموذج الذي يرتّب العملاء بحسب خطر انقطاعهم يستطيع أن يسلّم فريق التسويق أكثر 30 عميلًا مرجّحًا للانقطاع، وهذا ما لا تستطيعه قاعدة نعم/لا. يقيس القسم 3 ذلك بالضبط. لكن أولًا، يفتح القسم 2 أبسط نموذج على الإطلاق، الخط المستقيم، لترى ما معنى “التعلّم” بالأرقام.
أهم النقاط
- النتيجة لا تعني شيئًا حتى تقارنها بخط أساس (baseline) مبني على التقسيم نفسه.
- يتنبأ
DummyClassifierبالفئة الأكثر شيوعًا ويتنبأDummyRegressorبالمتوسط؛ وهما يحدّدان الحدّ الأدنى. - القاعدة البسيطة المضبوطة على بيانات التدريب هي خط الأساس الذي يُبقيك صادقًا بشأن ما إذا كان النموذج يستحق كلفته.
- حين تهيمن فئة واحدة، تكافئ الـ accuracy تجاهلَ الفئة النادرة؛ فقد تعني نتيجة 95% أن النموذج لم يجد شيئًا.