الوحدة 3 · التصنيف
الانحدار اللوجستي: التنبؤ بالاحتمالات
20 دقراءة 4 دتمرين Python
الدرس في لمحة
درّب نموذج انحدار لوجستي على بيانات الانقطاع، واقرأ احتمالاته ومعاملاته، واستخدم الاحتمالات لترتيب العملاء كي يتواصل فريق التسويق مع الأكثر خطرًا أولًا.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
أجابت الشجرة بعمق 3 من القسم 1 بـ “سينقطع” أو “سيبقى”. وفريق التسويق لا يريد ذلك حقًا. لديه ميزانية لبضع عشرات من مكالمات الاسترجاع أسبوعيًا، ويريد أن يعرف بمن يتصل أولًا. هذا يتطلّب درجة ترتّب العملاء بحسب الخطر، والنموذج الكلاسيكي لذلك هو الانحدار اللوجستي (logistic regression).
من خط إلى احتمال
يبدأ الانحدار اللوجستي كالانحدار الخطي: اضرب كل feature في معامل، واجمع النتائج، وأضف intercept. هذا يعطيك درجة z قد تكون أي رقم. ثم يضغط الدرجة عبر دالة الـ sigmoid، أي 1 / (1 + e^-z)، التي تحوّل أي رقم إلى قيمة بين 0 و1. الدرجات الموجبة الكبيرة تعطي احتمالات قرب 1، والسالبة الكبيرة قرب 0، والدرجة 0 بالضبط تعطي 0.5.
أثناء التدريب، يعدّل النموذج المعاملات بحيث ينال المنقطعون احتمالات عالية وغير المنقطعين احتمالات منخفضة. ودالة الخسارة التي يصغّرها هي الـ log loss، التي تعاقب الإجابات الخاطئة الواثقة بشدة: التنبؤ بـ 0.99 لعميل بقي يكلّف أكثر بكثير من التنبؤ بـ 0.6. لا توجد معادلة دقيقة للقاع، فيجده scikit-learn بمُحسِّن تكراري، وهو قريب مهذَّب للـ gradient descent الذي كتبته في القسم السابق.
تدريبه على بيانات الانقطاع
لأن المُحسِّن تكراري وللنموذج عقوبة (المزيد عن ذلك أدناه)، وحّد مقاييس الـ features أولًا. والـ pipeline يُبقي الـ scaler والنموذج معًا.
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
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"])
model = make_pipeline(StandardScaler(), LogisticRegression()).fit(X_train, y_train)
print("test accuracy:", model.score(X_test, y_test))
print(model.predict_proba(X_test)[:4].round(2))
print(model.predict(X_test)[:4])تُعيد predict_proba عمودين، واحدًا لكل فئة بترتيب classes_: احتمال البقاء، واحتمال الانقطاع. ومجموعهما 1. أما predict فاختصار يصنّف الصف بـ 1 حين يكون احتمال الانقطاع 0.5 على الأقل. وهذه الـ 0.5 قيمة افتراضية، لا قانون، وآخر درس في القسم 3 يدور حول اختيارها عن قصد.
الـ accuracy تبلغ 0.72، أي بمستوى قاعدة الـ 80 يومًا. لا تتوقف عن القراءة هنا: فالاحتمالات تحمل معلومات ترميها الـ accuracy.
قراءة المعاملات
مع features موحّدة المقاييس، يقول كل معامل كم يحرّك انحرافٌ معياري واحد من ذلك الـ feature الدرجةَ z (أي الـ log-odds للانقطاع). وهذا يجعلها قابلة للمقارنة بين الـ features.
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
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"])
model = make_pipeline(StandardScaler(), LogisticRegression()).fit(X_train, y_train)
coefs = pd.Series(model[-1].coef_[0], index=features).sort_values()
print(coefs.round(2))
ranked = X_test.assign(churn_prob=model.predict_proba(X_test)[:, 1], churned=y_test)
top10 = ranked.sort_values("churn_prob", ascending=False).head(10)
print(top10[["days_since_last_order", "orders", "churn_prob", "churned"]].round(2))
print("share of the top 10 who really churned:", top10["churned"].mean())حداثة آخر طلب (days_since_last_order، +0.93) هي المهيمنة، وهذا يطابق ما أخبرتك به قاعدة خط الأساس. ومدة العضوية الأطول تدفع أيضًا نحو الانقطاع، بينما تدفع الطلبات الأكثر والإنفاق الأكبر واستخدام القسائم، بل وتذاكر الدعم الأكثر، بعيدًا عنه. فالعملاء الذين يتواصلون مع الدعم عملاء متفاعلون؛ والصامتون هم من يرحلون. هذا هو نوع الاستنتاجات الذي يستحق أن تعود به إلى أصحاب القرار في الشركة، مع التنبيه إلى أنه ارتباط وليس سببية.
ثم تأتي الثمرة: من بين العشرة الذين يصنّفهم النموذج الأكثر خطرًا، انقطع تسعة فعلًا. قاعدة نعم/لا لا تستطيع إنتاج هذه القائمة؛ أما الاحتمال فيستطيع.
العقوبة التي لم تطلبها
LogisticRegression منظَّم افتراضيًا بعقوبة L2، وهي الفكرة نفسها في Ridge. تُحدَّد قوّتها بـ C، وهو مقلوب alpha في Ridge: قيمة C الصغيرة تعني عقوبة قوية، والكبيرة تعني عقوبة ضعيفة. والقيمة الافتراضية C=1.0 بداية معقولة. على هذه البيانات، تقع القيم من 0.01 إلى 100 كلها في حدود نقطتين من بعضها، وهذه علامة على أن ثمانية features حسنة السلوك لا تمنح النموذج مجالًا كبيرًا للـ overfitting. أما مع مئات الـ features، فتصبح C مهمة جدًا، وستضبطها بالأدوات التي في القسم 4.
يرسم الانحدار اللوجستي حدًّا مستقيمًا واحدًا عبر فضاء الـ features. أما نموذج الدرس القادم فلا يفترض شيئًا كهذا: إنه يطرح سلسلة من أسئلة نعم/لا ويستطيع تقطيع الفضاء إلى صناديق.
أهم النقاط
- يحسب الانحدار اللوجستي درجة خطية ثم يضغطها عبر دالة الـ sigmoid لتصبح احتمالًا بين 0 و1.
- تُعيد
predict_probaاحتمالًا لكل فئة؛ وتطبّقpredictعليه حدًّا فاصلًا عند 0.5. - على features موحّدة المقاييس، كل معامل هو التغيّر في الـ log-odds لكل انحراف معياري، فتصبح إشارته وحجمه قابلين للمقارنة بين الـ features.
LogisticRegressionمنظَّم افتراضيًا؛ وCهو مقلوب قوة العقوبة، فقيمةCالأصغر تعني عقوبة أقوى.- ترتيب العملاء بحسب الاحتمال أنفع غالبًا من label نعم/لا، لأنه يتيح للشركة أن تختار عدد العملاء الذين ستتعامل معهم.