استخدام الرسوم البيانية السببية للإجابة على الأسئلة السببية | بواسطة ريان أوسوليفان
الذكاء الاصطناعي السببي، يستكشف دمج التفكير السببي في التعلم الآلي
تقدم هذه المقالة مقدمة عملية لإمكانات الرسوم البيانية السببية.
وهو موجه إلى أي شخص يريد أن يفهم المزيد عن:
- ما هي الرسوم البيانية السببية وكيف تعمل
- دراسة حالة عملية في بايثون توضح كيفية بناء الرسوم البيانية السببية
- كيف يقارنون بـ ML
- التحديات الرئيسية والاعتبارات المستقبلية
المفكرة الكاملة تجدها هنا:
تساعدنا الرسوم البيانية السببية على فصل الأسباب عن الارتباطات. إنها جزء أساسي من الاستدلال السببي/التعلم السببي/الذكاء الاصطناعي السببي ويمكن استخدامها للإجابة على الأسئلة السببية.
غالبًا ما يشار إليه باسم DAG (الرسم البياني الحلقي الموجه)، ويحتوي الرسم البياني السببي على العقد والحواف – عقد ربط الحواف المرتبطة سببيًا.
هناك طريقتان لتحديد الرسم البياني السببي:
- معرفة مجال الخبراء
- خوارزميات الاكتشاف السببي
في الوقت الحالي، سنفترض أن لدينا معرفة متخصصة في المجال لتحديد الرسم البياني السببي (سنغطي خوارزميات الاكتشاف السببي في المستقبل).
الهدف من ML هو التصنيف أو التنبؤ بأكبر قدر ممكن من الدقة في ضوء بعض بيانات التدريب. لا يوجد حافز لخوارزمية تعلم الآلة لضمان أن الميزات التي تستخدمها مرتبطة بشكل سببي بالهدف. ليس هناك ما يضمن أن الاتجاه (التأثير الإيجابي/السلبي) وقوة كل ميزة سوف يتماشى مع عملية توليد البيانات الحقيقية. لن يأخذ ML في الاعتبار المواقف التالية:
- الارتباطات الزائفة – هناك متغيران لهما علاقة زائفة عندما يكون لهما سبب مشترك، على سبيل المثال ارتفاع درجات الحرارة مما يزيد من عدد مبيعات الآيس كريم وهجمات أسماك القرش.
- الإرباك – يؤثر المتغير على علاجك ونتيجتك، على سبيل المثال، يؤثر الطلب على المبلغ الذي ننفقه على التسويق وعدد العملاء الجدد الذين يسجلون.
- Colliders – متغير يتأثر بمتغيرين مستقلين، على سبيل المثال جودة خدمة العملاء -> رضا المستخدم <- حجم الشركة
- الوسطاء – يتم ربط متغيرين (بشكل غير مباشر) من خلال وسيط، على سبيل المثال التمرين المنتظم -> لياقة القلب والأوعية الدموية (الوسيط) -> الصحة العامة
وبسبب هذه التعقيدات وطبيعة الصندوق الأسود لتعلم الآلة، لا يمكننا أن نكون واثقين من قدرتها على الإجابة على الأسئلة السببية.
بالنظر إلى الرسم البياني السببي المعروف والبيانات المرصودة، يمكننا تدريب النموذج السببي الهيكلي (SCM). يمكن اعتبار SCM بمثابة سلسلة من النماذج السببية، واحد لكل عقدة. يستخدم كل نموذج عقدة واحدة كهدف، والأصل المباشر لها كميزات. إذا كانت العلاقات في البيانات المرصودة لدينا خطية، فسيكون SCM عبارة عن سلسلة من المعادلات الخطية. ويمكن نمذجة ذلك من خلال سلسلة من نماذج الانحدار الخطي. إذا كانت العلاقات في البيانات المرصودة لدينا غير خطية، فيمكن تصميم ذلك باستخدام سلسلة من الأشجار المعززة.
يتمثل الاختلاف الرئيسي عن التعلم الآلي التقليدي في أن نموذج SCM يمثل العلاقات السببية ويفسر الارتباطات الزائفة والإرباك والمصادمات والوسطاء.
من الشائع استخدام نموذج الضوضاء المضافة (ANM) لكل عقدة غير جذرية (بمعنى أنها تحتوي على أصل واحد على الأقل). يتيح لنا ذلك استخدام مجموعة من خوارزميات التعلم الآلي (بالإضافة إلى مصطلح الضوضاء) لتقدير كل عقدة غير جذرية.
ص := و(X) + ن
يمكن تصميم العقد الجذرية باستخدام نموذج عشوائي لوصف التوزيع.
يمكن النظر إلى SCM كنموذج توليدي لتوليد عينات جديدة من البيانات، وهذا يمكّنه من الإجابة على مجموعة من الأسئلة السببية. يقوم بإنشاء بيانات جديدة عن طريق أخذ عينات من العقد الجذرية ثم نشر البيانات من خلال الرسم البياني.
تكمن قيمة SCM في أنها تسمح لنا بالإجابة على الأسئلة السببية عن طريق حساب الحقائق المضادة ومحاكاة التدخلات:
- الحقائق المضادة: استخدام البيانات التي تمت ملاحظتها تاريخيًا لحساب ما كان سيحدث لـ y إذا قمنا بتغيير xeg. ما الذي كان سيحدث لعدد العملاء المتخلفين إذا قمنا بتقليل وقت انتظار المكالمات بنسبة 20% الشهر الماضي؟
- التدخلات: مشابهة جدًا للواقع المخالف (وغالبًا ما تستخدم بالتبادل) ولكن التدخلات تحاكي ما سيحدث في المستقبل، على سبيل المثال، ماذا سيحدث لعدد العملاء المضطربين إذا قمنا بتقليل وقت انتظار المكالمات بنسبة 20% في العام المقبل؟
هناك العديد من مؤشرات الأداء الرئيسية التي يراقبها فريق خدمة العملاء. واحدة من هذه هي أوقات انتظار المكالمات. ستؤدي زيادة عدد موظفي مركز الاتصال إلى تقليل أوقات انتظار المكالمات.
ولكن كيف سيؤثر تقليل وقت انتظار المكالمات على مستويات تراجع العملاء؟ وهل سيعوض هذا تكلفة موظفي مركز الاتصال الإضافيين؟
يُطلب من فريق علوم البيانات بناء حالة العمل وتقييمها.
السكان موضع الاهتمام هم العملاء الذين يقومون بإجراء مكالمة واردة. يتم جمع بيانات السلاسل الزمنية التالية يوميًا:
في هذا المثال، نستخدم بيانات السلاسل الزمنية ولكن الرسوم البيانية السببية يمكن أن تعمل أيضًا مع البيانات على مستوى العميل.
في هذا المثال، نستخدم معرفة مجال الخبراء لتحديد الرسم البياني السببي.
# Create node lookup for channels
node_lookup = {0: 'Demand',
1: 'Call waiting time',
2: 'Call abandoned',
3: 'Reported problems',
4: 'Discount sent',
5: 'Churn'
}total_nodes = len(node_lookup)
# Create adjacency matrix - this is the base for our graph
graph_actual = np.zeros((total_nodes, total_nodes))
# Create graph using expert domain knowledge
graph_actual[0, 1] = 1.0 # Demand -> Call waiting time
graph_actual[0, 2] = 1.0 # Demand -> Call abandoned
graph_actual[0, 3] = 1.0 # Demand -> Reported problems
graph_actual[1, 2] = 1.0 # Call waiting time -> Call abandoned
graph_actual[1, 5] = 1.0 # Call waiting time -> Churn
graph_actual[2, 3] = 1.0 # Call abandoned -> Reported problems
graph_actual[2, 5] = 1.0 # Call abandoned -> Churn
graph_actual[3, 4] = 1.0 # Reported problems -> Discount sent
graph_actual[3, 5] = 1.0 # Reported problems -> Churn
graph_actual[4, 5] = 1.0 # Discount sent -> Churn
بعد ذلك، نحتاج إلى إنشاء بيانات لدراسة الحالة الخاصة بنا.
نريد إنشاء بعض البيانات التي ستسمح لنا بمقارنة حساب الحقائق المضادة باستخدام الرسوم البيانية السببية مقابل تعلم الآلة (لتبسيط الأمور، انحدار التلال).
وكما حددنا الرسم البياني السببي في القسم الأخير، يمكننا استخدام هذه المعرفة لإنشاء عملية توليد البيانات.
def data_generator(max_call_waiting, inbound_calls, call_reduction):
'''
A data generating function that has the flexibility to reduce the value of node 0 (Call waiting time) - this enables us to calculate ground truth counterfactualsArgs:
max_call_waiting (int): Maximum call waiting time in seconds
inbound_calls (int): Total number of inbound calls (observations in data)
call_reduction (float): Reduction to apply to call waiting time
Returns:
DataFrame: Generated data
'''
df = pd.DataFrame(columns=node_lookup.values())
df[node_lookup[0]] = np.random.randint(low=10, high=max_call_waiting, size=(inbound_calls)) # Demand
df[node_lookup[1]] = (df[node_lookup[0]] * 0.5) * (call_reduction) + np.random.normal(loc=0, scale=40, size=inbound_calls) # Call waiting time
df[node_lookup[2]] = (df[node_lookup[1]] * 0.5) + (df[node_lookup[0]] * 0.2) + np.random.normal(loc=0, scale=30, size=inbound_calls) # Call abandoned
df[node_lookup[3]] = (df[node_lookup[2]] * 0.6) + (df[node_lookup[0]] * 0.3) + np.random.normal(loc=0, scale=20, size=inbound_calls) # Reported problems
df[node_lookup[4]] = (df[node_lookup[3]] * 0.7) + np.random.normal(loc=0, scale=10, size=inbound_calls) # Discount sent
df[node_lookup[5]] = (0.10 * df[node_lookup[1]] ) + (0.30 * df[node_lookup[2]]) + (0.15 * df[node_lookup[3]]) + (-0.20 * df[node_lookup[4]]) # Churn
return df
# Generate data
np.random.seed(999)
df = data_generator(max_call_waiting=600, inbound_calls=10000, call_reduction=1.00)sns.pairplot(df)
لدينا الآن مصفوفة مجاورة تمثل الرسم البياني السببي وبعض البيانات. نحن نستخدم وحدة gcm من حزمة dohy Python لتدريب SCM.
من المهم التفكير في الآلية السببية التي يجب استخدامها للعقد الجذرية وغير الجذرية. إذا نظرت إلى وظيفة مولد البيانات لدينا، سترى أن جميع العلاقات خطية. ولذلك فإن اختيار انحدار التلال ينبغي أن يكون كافيا.
# Setup graph
graph = nx.from_numpy_array(graph_actual, create_using=nx.DiGraph)
graph = nx.relabel_nodes(graph, node_lookup)# Create SCM
causal_model = gcm.InvertibleStructuralCausalModel(graph)
causal_model.set_causal_mechanism('Demand', gcm.EmpiricalDistribution()) # Root node
causal_model.set_causal_mechanism('Call waiting time', gcm.AdditiveNoiseModel(gcm.ml.create_ridge_regressor())) # Non-root node
causal_model.set_causal_mechanism('Call abandoned', gcm.AdditiveNoiseModel(gcm.ml.create_ridge_regressor())) # Non-root node
causal_model.set_causal_mechanism('Reported problems', gcm.AdditiveNoiseModel(gcm.ml.create_ridge_regressor())) # Non-root node
causal_model.set_causal_mechanism('Discount sent', gcm.AdditiveNoiseModel(gcm.ml.create_ridge_regressor())) # Non-root
causal_model.set_causal_mechanism('Churn', gcm.AdditiveNoiseModel(gcm.ml.create_ridge_regressor())) # Non-root
gcm.fit(causal_model, df)
يمكنك أيضًا استخدام وظيفة التعيين التلقائي لتعيين الآليات السببية تلقائيًا بدلاً من تعيينها يدويًا.
لمزيد من المعلومات حول حزمة gcm راجع المستندات:
نحن نستخدم أيضًا انحدار التلال للمساعدة في إنشاء مقارنة أساسية. يمكننا أن ننظر إلى مولد البيانات ونرى أنه يقدر بشكل صحيح معاملات كل متغير. ومع ذلك، بالإضافة إلى التأثير المباشر على عدم الاتصال، يؤثر وقت انتظار المكالمات بشكل غير مباشر على عدم الاتصال من خلال المكالمات المهجورة والمشكلات المبلغ عنها والخصومات المرسلة.
عندما يتعلق الأمر بتقدير الحقائق المضادة، سيكون من المثير للاهتمام أن نرى كيف يمكن مقارنة SCM بانحدار التلال.
# Ridge regression
y = df['Churn'].copy()
X = df.iloc[:, 1:-1].copy()
model = RidgeCV()
model = model.fit(X, y)
y_pred = model.predict(X)print(f'Intercept: {model.intercept_}')
print(f'Coefficient: {model.coef_}')
# Ground truth[0.10 0.30 0.15 -0.20]
قبل أن ننتقل إلى حساب الحقائق المغايرة باستخدام الرسوم البيانية السببية وانحدار التلال، نحتاج إلى معيار الحقيقة الأرضية. يمكننا استخدام منشئ البيانات الخاص بنا لإنشاء عينات مطابقة للواقع بعد أن قمنا بتقليل وقت انتظار المكالمات بنسبة 20%.
لم نتمكن من القيام بذلك مع مشاكل العالم الحقيقي ولكن هذه الطريقة تسمح لنا بتقييم مدى فعالية الرسم البياني السببي وانحدار التلال.
# Set call reduction to 20%
reduce = 0.20
call_reduction = 1 - reduce# Generate counterfactual data
np.random.seed(999)
df_cf = data_generator(max_call_waiting=600, inbound_calls=10000, call_reduction=call_reduction)
يمكننا الآن تقدير ما كان سيحدث لو قمنا بتقليل وقت انتظار المكالمات بنسبة 20% باستخدام طرقنا الثلاث:
- الحقيقة الأرضية (من مولد البيانات)
- ريدج الانحدار
- الرسم البياني السببي
نحن نرى أن انحدار التلال يقلل من التأثير على الاضطراب بشكل كبير في حين أن الرسم البياني السببي قريب جدًا من الحقيقة على الأرض.
# Ground truth counterfactual
ground_truth = round((df['Churn'].sum() - df_cf['Churn'].sum()) / df['Churn'].sum(), 2)# Causal graph counterfactual
df_counterfactual = gcm.counterfactual_samples(causal_model, {'Call waiting time': lambda x: x*call_reduction}, observed_data=df)
causal_graph = round((df['Churn'].sum() - df_counterfactual['Churn'].sum()) / (df['Churn'].sum()), 3)
# Ridge regression counterfactual
ridge_regression = round((df['Call waiting time'].sum() * 1.0 * model.coef_[0] - (df['Call waiting time'].sum() * call_reduction * model.coef_[0])) / (df['Churn'].sum()), 3)
كان هذا مثالًا بسيطًا لبدء التفكير في قوة الرسوم البيانية السببية.
بالنسبة للمواقف الأكثر تعقيدًا، هناك العديد من التحديات التي قد تحتاج إلى بعض الاعتبار:
- ما هي الافتراضات التي تم وضعها وما هو تأثير انتهاكها؟
- ماذا لو لم يكن لدينا المعرفة المتخصصة في المجال لتحديد الرسم البياني السببي؟
- ماذا لو كانت هناك علاقات غير خطية؟
- ما مدى ضرر الخطية المتداخلة المتعددة؟
- ماذا لو كانت بعض المتغيرات لها تأثيرات متأخرة؟
- كيف يمكننا التعامل مع مجموعات البيانات عالية الأبعاد (الكثير من المتغيرات)؟
سيتم تغطية كل هذه النقاط في المدونات المستقبلية.
إذا كنت مهتمًا بمعرفة المزيد عن الذكاء الاصطناعي السببي، فإنني أوصي بشدة بالموارد التالية:
“تعرف على رايان، وهو عالم بيانات رئيسي متمرس مع تركيز متخصص على استخدام التقنيات السببية في سياقات الأعمال، والتي تشمل التسويق والعمليات وخدمة العملاء. وتكمن كفاءته في كشف تعقيدات العلاقات بين السبب والنتيجة لدفع عملية صنع القرار المستنيرة والتحسينات الاستراتيجية عبر الوظائف التنظيمية المتنوعة.