EduFlow

الوحدة 3 · التصنيف

الانحدار اللوجستي: التنبؤ بالاحتمالات

20 دقراءة 4 دتمرين Python

الدرس في لمحة

درّب نموذج انحدار لوجستي على بيانات الانقطاع، واقرأ احتمالاته ومعاملاته، واستخدم الاحتمالات لترتيب العملاء كي يتواصل فريق التسويق مع الأكثر خطرًا أولًا.

  1. 1من خط إلى احتمال
  2. 2تدريبه على بيانات الانقطاع
  3. 3قراءة المعاملات
  4. 4العقوبة التي لم تطلبها

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

أجابت الشجرة بعمق 3 من القسم 1 بـ “سينقطع” أو “سيبقى”. وفريق التسويق لا يريد ذلك حقًا. لديه ميزانية لبضع عشرات من مكالمات الاسترجاع أسبوعيًا، ويريد أن يعرف بمن يتصل أولًا. هذا يتطلّب درجة ترتّب العملاء بحسب الخطر، والنموذج الكلاسيكي لذلك هو الانحدار اللوجستي (logistic regression).

من خط إلى احتمال

يبدأ الانحدار اللوجستي كالانحدار الخطي: اضرب كل feature في معامل، واجمع النتائج، وأضف intercept. هذا يعطيك درجة z قد تكون أي رقم. ثم يضغط الدرجة عبر دالة الـ sigmoid، أي 1 / (1 + e^-z)، التي تحوّل أي رقم إلى قيمة بين 0 و1. الدرجات الموجبة الكبيرة تعطي احتمالات قرب 1، والسالبة الكبيرة قرب 0، والدرجة 0 بالضبط تعطي 0.5.

منحنى على شكل حرف S. المحور الأفقي هو الدرجة الخطية z من سالب 6 إلى موجب 6؛ والمحور العمودي هو الاحتمال من 0 إلى 1. يمرّ المنحنى بـ 0.5 عند z تساوي 0 ويتسطّح نحو 0 و1 عند الطرفين. 1.0 0.5 0.0 z = −6 0 +6 غالبًا سيبقى غالبًا سينقطع
الـ sigmoid تحوّل الدرجة إلى احتمال

أثناء التدريب، يعدّل النموذج المعاملات بحيث ينال المنقطعون احتمالات عالية وغير المنقطعين احتمالات منخفضة. ودالة الخسارة التي يصغّرها هي الـ log loss، التي تعاقب الإجابات الخاطئة الواثقة بشدة: التنبؤ بـ 0.99 لعميل بقي يكلّف أكثر بكثير من التنبؤ بـ 0.6. لا توجد معادلة دقيقة للقاع، فيجده scikit-learn بمُحسِّن تكراري، وهو قريب مهذَّب للـ gradient descent الذي كتبته في القسم السابق.

تدريبه على بيانات الانقطاع

لأن المُحسِّن تكراري وللنموذج عقوبة (المزيد عن ذلك أدناه)، وحّد مقاييس الـ features أولًا. والـ pipeline يُبقي الـ scaler والنموذج معًا.

Python
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.

Python
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 نعم/لا، لأنه يتيح للشركة أن تختار عدد العملاء الذين ستتعامل معهم.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

الدرجة الخطية لعميل داخل نموذج انحدار لوجستي تساوي 0. ما احتمال الانقطاع الذي يعطيه النموذج؟

السؤال 2 من 4

على features انقطاع موحّدة المقاييس، معامل days_since_last_order هو +0.93 ومعامل total_spent هو -0.26. ماذا يمكنك أن تقول؟

السؤال 3 من 4

درّبت LogisticRegression() على features الانقطاع الخام فظهر تحذير ConvergenceWarning. ما أفضل إصلاح أول؟

السؤال 4 من 4

يستطيع فريق التسويق الاتصال بـ 30 عميلًا هذا الأسبوع. ماذا يجب أن يعطيهم نموذجك؟

تدريب

تمرين Python

جهّز قائمة اتصالات يوم الاثنين

يستطيع فريق التسويق الاتصال بـ 20 عميلًا. أعطهم العشرين الصحيحين.

  1. model: pipeline يتكوّن من StandardScaler ثم LogisticRegression، مدرَّبًا على بيانات التدريب.
  2. churn_prob: احتمال الانقطاع (الفئة 1) لكل عميل في بيانات الاختبار.
  3. call_list: قيم customer_id لعملاء الاختبار العشرين أصحاب أعلى احتمال انقطاع.
  4. hit_rate: نسبة من انقطعوا فعلًا من هؤلاء العشرين.

ملفات البيانات: churn.csv

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"])

# 1. A pipeline: StandardScaler, then LogisticRegression; fit it on the training data
model = LogisticRegression().fit(X_train, y_train)

# 2. Churn probability (class 1) for every test customer
churn_prob = model.predict(X_test)

# 3. customer_id of the 20 test customers with the highest churn probability
call_list = []

# 4. Share of those 20 who really churned
hit_rate = None
جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

(لا مخرجات)

الفحوص

  • model هو StandardScaler ← LogisticRegression
  • يحتوي churn_prob على احتمالات الفئة 1
  • يحتوي call_list على معرّفات العملاء العشرين الأعلى خطرًا
  • hit_rate هي نسبة من انقطعوا من قائمة الاتصال