سلسلة فهم لتعلم الآلة – الجزء الثاني | Classification

الثلاثاء 26 جمادى الأولى 1444ھ الثلاثاء 20 ديسمبر 2022م
فيسبوك
تويتر
واتساب
تيليجرام
لينكدإن
المحتوى
توقع ترك العملاء
Customer Churn Prediction

مقدمة

أهلا بكم في الجزء الثاني من سلسلة فهم لتعلم الآلة. اليوم سوف نتحدث عن النوع الثاني من أنواع التعلم الخاضع للإشراف ألا وهو التصنيف والمعروف بالـ Classification، إن الأمثلة على تطبيقات التصنيف متعددة، على سبيل المثال لا الحصر

وتكمن أهمية خوارزميات التصنيف في أمرين أساسيين، أولا تصنيف الأشياء و ثانيا تحديد العوامل التي أدت إلى هذا التصنيف. وفي درس اليوم، سوف نتعلم كيفية استخدام خوارزميات التصنيف لتوقع أي من عملاء شركة الاتصال سيترك الشركة وأي منهم سيستمر في الاشتراك بخدماتها.

ماذا نريد أن نفعل؟

في هذا المشروع، أنت عالم بيانات لشركة اتصالات تقدم خدمات الاتصال و الإنترنت للمواطنين. وبما إن المنافسة بين شركات الاتصال عالية، طُلب منك عمل نموذج تعلم آلة يستطيع توقع مَن مِن العملاء قد يستغني عن خدمات الشركة ويذهب إلى شركة أخرى بناء على الذي حصل في الماضي.

ما المقصود بالماضي؟

حسنا، سبق وأن تحدثنا أن تعلم الآلة مبني على التعلم من البيانات المجمعة (أي الخبرات الماضية)، حيث أن المرحلة الأولى في سير عمل نماذج تعلم الآلة هو (التذكر)

ومن أجل ذلك، تقوم شركات الإتصال بالعادة بتسجيل بيانات العملاء مثل (العمر، عدد أفراد العائلة، متزوج أم لا، ذكر أم أنثى) بالإضافة إلى تسجيل الخدمات المشتركين فيها مثل (نوع الإنترنت، عدد الخطوط المستعملة، قيمة الاشتراك، مدة العقد) ثم يقومون بملاحظة من ترك الشركة ومن استمر فيها. ومن خلال هذه الملاحظات، سوف نقارن بيانات العملاء الحالين ببيانات العملاء الذين تركوا الشركة، فإن كان هناك تشابه في تصرفاتهم وبياناتهم، فبالغالب سوف يتركون الشركة، ومن أجل حل هذه المشكلة، نقوم بتوجيه عروض مخصصة لهم من أجل المحافظة عليهم.

نموذج البيانات

Data Model

من أجل بناء نموذج تعلم الآلة لابد أولا من بناء نموذج البيانات (جدول البيانات) المناسب للتدريب. حيث أن جودة البيانات هي العامل الأساسي في جودة ودقة نماذج تعلم الآلة. إذًا كيف نبني نموذج البيانات المناسب؟

إنه يوجد في كل شركة قاعدة بيانات تحتوي على العديد من الجداول ، ومهمتنا الأولى هي استخراج البيانات المناسبة من هذه الجداول لبناء النموذج وجمعها في جدول واحد عن طريق لغة الـــ SQL. يمكنك زيارة الدرس التالي إن كنت مهتم في كيفية استخراج البيانات من قواعد البيانات.

إدارة البيانات عن طريق قاعدة بيانات SQLite العلائقية – تطبيق عملي على بيانات الغابات

اختيار الأعمدة المناسبة لنموذج البيانات

المقصود بالأعمدة هي الصفات مثل جنس العميل، مدة اشتراكه، إلخ. حيث أن هناك صفات تأثر أكثر من الأخرى على مدى استمرارية العميل. حسنا، كيف أختار الأعمدة التي تساهم فعلا في توقع مَن مِن العملاء سوف يترك الشركة؟ إن الإجابة على هذا السؤال تطلب العديد من التجارب والخبرات، حيث أن الخبرة في المجال (Business Knowledge) الذي يعمل فيه عالم البيانات أمر مهم. ولتسريع عملية البحث، تستطيع الاجتماع مع الخبراء في الشركة لمساعدتك في تحديد الأعمدة التي تساهم في التوقع بشكل صحيح.

نموذج البيانات المستخدم (البيانات المستخدمة)

إن نموذج البيانات المستخدم في هذا الدرس جاهز. وهو موجود على موقع Kaggle.

هنا نجد المصدر الأصلي للبيانات

ولقد قمنا ببعض التعديلات الطفيفة على البيانات لتتناسب مع موضوع اليوم. ولذلك نرجو تحميل البيانات من هنا لتتبع خطوات الدرس بشكل صحيح.

الخطوة الأولى: استكشاف البيانات المستخدمة

Step One: Explore Data

علينا الآن استكشاف نموذج البيانات المستخدم، ومعرفة ماهي الأعمدة (الصفات) التي سوف تستخدم في توقع من من العملاء سوف يترك الشركة

				
					import pandas as pd
				
			
				
					df = pd.read_csv('https://github.com/KAFSALAH/Fihm_Lessons/raw/master/ML_Series2_Classification/customer_churn.csv')

# General info about the data 
print('——————————————————————————')
print('First 3 rows')
display(df.head(3))
				
			
customerIDgenderSeniorCitizenMarriedDependentstenurePhoneServiceMultipleLinesInternetServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportContractPaperlessBillingPaymentMethodMonthlyChargesTotalChargesChurn
0
7590-VHVEG
Female
No
Yes
No
1
No
No phone service
DSL
No
Yes
No
No
Month-to-month
Yes
Electronic check
29.85
29.85
No
1
5575-GNVDE
Male
No
No
No
34
Yes
No
DSL
Yes
No
Yes
No
One year
No
Mailed check
56.95
1889.5
No
2
3668-QPYBK
Male
No
No
No
2
Yes
No
DSL
Yes
Yes
No
No
Month-to-month
Yes
Mailed check
53.85
108.15
Yes

الآن، وبعد الاطلاع على الصفات المستخدمة، فلنقم بتلخيص تعريف كل صفة كالتالي

Customer_ID

رقم مميز لكل عميل

gender

جنس العميل

SeniorCitizen

هل العميل كبير بالسن؟

Married

هل العميل متزوج؟

Dependents

هل هناك تابعين؟

tenure

مدة اشتراك العميل بالأشهر

PhoneService

هل العميل مشترك بخدمة الاتصال؟

MultipleLines

هل العميل يستخدم أكثر من خط اتصال؟

InterntService

نوع خدمة الإنترنت

OnlineSecurity

هل لدى العميل خدمات حماية أون لاين؟

OnlineBackup

هل لدى العميل نسخة احتياطية أون لاين؟

DeviceProtection

هل لدى العميل ضمان؟

TechSupport

هل لدى العميل خدمة دعم فني؟

Customer_ID

رقم مميز لكل عميل

Contract

نوع عقد العميل

PaperlessBilling

هل الفواتير إلكترونية؟

PaymentMethod

طريقة سداد الفواتير

MonthlyCharges

قيمة الفواتير الشهرية

TotalCharges

مجموع قيمة فواتير العميل

الخطوة الثانية: معالجة البيانات

Step Two: Preprocess Data

أ- التحقق من القيم الناقصة أو المتكررة

في مرحلة معالجة البيانات، دعونا نتحقق أولا من عدم وجود قيم ناقصة أو صفوف متكررة (وجود صف متكرر يعني أن هناك عميل تكررت بياناته).

				
					print("Number of duplicated values is ", df.duplicated().sum())
print("Number of missing values is", df.isnull().values.sum())
				
			

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

				
					df.drop('customerID', axis = 1, inplace = True) # 'Inplace' implies that data is modified in place
                                                # Axis = 1 because we are dropping a column (0 in case we are dropping a row)
				
			

ب- ترميز الأعمدة الكتابية

فلنقم أيضا من التحقق من الأعمدة التي تحتوي على كتابات وتحويلها إلى أرقام من أجل بناء النموذج

				
					# To identify object columns
print('Object columns are as follows')
object_cols = df.loc[:,df.dtypes==object].columns.tolist()
object_cols
				
			

نلاحظ أمرا غريبا. إن عمود TotalCharges مصنف على أنه عمود كتابي لا رقمي. وهذا أمر خاطئ حيث عند التحقق نجد أن العمود يحتوي على أرقام.

				
					df.TotalCharges
				
			
0         29.85
1        1889.5
2        108.15
3       1840.75
4        151.65
         ...   
7038     1990.5
7039     7362.9
7040     346.45
7041      306.6
7042     6844.5
Name: TotalCharges, Length: 7043, dtype: object

هذه الأخطاء تحصل بالعادة عند عملية إدخال البيانات في قاعدة البيانات أو حين القراءة منها. نستطيع استخدام الكود الذي بالأسفل لتحويله إلى عمود رقمي.

				
					df['TotalCharges'] = pd.to_numeric(df['TotalCharges'], errors='coerce')
				
			
				
					# Check again if 'TotalCharges' is still considered as an object or not
print('Object columns are as follows')
object_cols = df.loc[:,df.dtypes==object].columns.tolist()
object_cols
				
			

قمنا بتحويل نوع عمود TotalCharges من كتابي إلى رقمي بنجاح، ولكن هذه الخطوة قد ينتج بسببها بعض القيم المفقودة. حيث أن البرنامج سوف يقوم بترجمة الكتابة إلى رقم، فإن لم يستطع، سوف يترك الخلية فارغة. للتحقق من عدد الخلايا الفارغة التي نتجت نستطيع استخدام الكود التالي

				
					df['TotalCharges'].isna().sum()
				
			

يوجد لدينا ١١ خلية فارغة. أي أننا خسرنا بيانات ١١ عميل في صفة التكلفة الإجمالية TotalCharges نستطيع تحديد ماهي الصفوف التي تحتوي على خلية فارغة في التكلفة الإجمالية وتعبئتها يدويا بناء على البيانات الموجودة قبل التحويل. ولكن لحفظ الوقت، نستطيع ملء الخلايا الفارغة بقيمة الوسيط لعمود التكلفة الإجمالية كحلٍ وسط يجمع ما بين الدقة والسرعة

				
					# Replace missing values with the median
df.TotalCharges.fillna(df.TotalCharges.median(), inplace = True)

# Check again for missing values
df['TotalCharges'].isna().sum()
				
			

الآن، لترميز البيانات، سوف نقوم باستكشاف العناصر المميزة في كل عمود كتابي. وتذكر أن هناك نوعين في الأعمدة الكتابية

Object columns
Type 1 - Nominal object: الترتيب غير مهم مثل جنس العميل
Type 2 - Ordinal object: الترتيب مهم مثل نوع اشتراك العميل
				
					# Identify the number of unique elements in each object columns
for i in object_cols:
    print('Number of unique elements in' , i, 'is', len(df.loc[:,i].unique()))
    print(df.loc[:,i].unique())
				
			
Number of unique elements in gender is 2
['Female' 'Male']
Number of unique elements in SeniorCitizen is 2
['No' 'Yes']
Number of unique elements in Married is 2
['Yes' 'No']
Number of unique elements in Dependents is 2
['No' 'Yes']
Number of unique elements in PhoneService is 2
['No' 'Yes']
Number of unique elements in MultipleLines is 3
['No phone service' 'No' 'Yes']
Number of unique elements in InternetService is 3
['DSL' 'Fiber optic' 'No']
Number of unique elements in OnlineSecurity is 3
['No' 'Yes' 'No internet service']
Number of unique elements in OnlineBackup is 3
['Yes' 'No' 'No internet service']
Number of unique elements in DeviceProtection is 3
['No' 'Yes' 'No internet service']
Number of unique elements in TechSupport is 3
['No' 'Yes' 'No internet service']
Number of unique elements in Contract is 3
['Month-to-month' 'One year' 'Two year']
Number of unique elements in PaperlessBilling is 2
['Yes' 'No']
Number of unique elements in PaymentMethod is 4
['Electronic check' 'Mailed check' 'Bank transfer (automatic)'
 'Credit card (automatic)']
Number of unique elements in Churn is 2
['No' 'Yes']

والآن سوف نقوم بالترميز عن طريق ثلاثة طرق

ترميز الأعمدة المرتبة

“Mapping” for ordinal columns

ترميز الأعمدة المرتبة يبدأ بصفر لأقل قيمة. ثم يرتفع، على سبيل المثال عمود مشتركي خدمة الإنترنت. إن لم يكن مشترك نعطيه قيمة 0. إن كان مشترك في خدمة (الدي إس إل) نعطيه 1. وإن كان مشترك في الألياف البصرية نعطيه 2.

“LabelEncoder” for binary nominal columns

ترميز الأعمدة الثنائية يكون عن طريق الـ 0، 1. الأعمدة الثنائية مثل جنس العميل وهل متزوج أم لا، لا يوجد فيها أهمية كبيرة للترتيب أيهم يأخذ قيمة ال0 وأيهم ال1.

“get_dummies” for non-binary nominal columns

ترميز الأعمدة الغير المرتبة الغير ثناية عن طريق صناعة عمود خاص لكل عنصر سوف نقوم باستخدام هذه الطريقة لترميز عمود PaymentMethod حيث أنه عمود غير ثنائي ولا يحتوي على ترتيب أيضا.
				
					# Firstly, we map ordinal columns

df.Churn = df.Churn.map({'No':0, 'Yes':1}) # We will annotate churned customers with 1

#---
df.InternetService = df.InternetService.map({'No':0, 'DSL':1, 'Fiber optic':2})
df.MultipleLines = df.MultipleLines.map({'No phone service':0, 'No':1, 'Yes':2})
df.Contract = df.Contract.map({'Month-to-month':0,'One year':1,'Two year':2})
#---

## For similar ordinal columns, we can map them using a for loop
similar_ordinal_cols = ['OnlineSecurity','OnlineBackup','DeviceProtection','TechSupport']
for i in similar_ordinal_cols:
    df[i] = df[i].map({'No internet service':0, 'No' :1, 'Yes': 2})
				
			

الآن، فلنقم بالتحقق من الأعمدة المتبقية والتي تمثل الأعمدة الكتابية الغير مرتبة

				
					print('Object columns are as follows')
object_cols = df.loc[:,df.dtypes==object].columns.tolist()
object_cols
				
			

جميع هذه الصفات هي صفات ثنائية (نعم أو لا) ما عدا PaymentMethod لذلك سوف نقوم بترميز PaymentMethod عن طريق get_dummies والأعمدة الثنائية عن طريق LabelEncoder

ترميز الأعمدة الثنائية

				
					# Now, we LabelEncode binary nominal columns

object_cols.remove('PaymentMethod') # Remove it to later encode it using get_dummies
from sklearn.preprocessing import LabelEncoder
labelencoder = LabelEncoder()
for i in object_cols:
    df[i] = labelencoder.fit_transform(df[i])
				
			

ترميز الأعمدة الغير مرتبة الغير ثنائية

				
					# Lastly, we encode 'PaymentMethod' column using get_dummies
encoded_df = pd.get_dummies(df, drop_first = True) # drop_first to avoid data redundancy 
				
			

فلنتحقق الآن من شكل البيانات الحالي بعد عملية الترميز

				
					encoded_df.head()
				
			
genderSeniorCitizenMarriedDependentstenurePhoneServiceMultipleLinesInternetServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportContractPaperlessBillingMonthlyChargesTotalChargesChurnPaymentMethod_Credit card (automatic)PaymentMethod_Electronic checkPaymentMethod_Mailed check
0
0
0
1
0
1
0
0
1
1
2
1
1
0
1
29.85
29.85
0
0
1
0
1
1
0
0
0
34
1
1
1
2
1
2
1
1
0
56.95
1889.5
0
0
0
1
2
1
0
0
0
2
1
1
1
2
2
1
1
0
1
53.85
108.15
1
0
0
1
3
1
0
0
0
45
0
0
1
2
1
2
2
1
0
42.3
1840.75
0
0
0
0
4
0
0
0
0
2
1
1
2
1
1
1
1
0
1
70.7
151.65
1
0
1
0

نلاحظ أن العمود المستهدف Churn أصبح في منتصف الجدول، فلنقم بتحريكه إلى أقصى يمين العمود من أجل المحافظة على شكل الجدول بشكل مناسب حيث أن العرف أن العمود المستهدف يكون في أقصى اليمين

				
					last_column = encoded_df.pop('Churn')
encoded_df.insert(df.shape[1]+1, 'Churn', last_column)
encoded_df.head(3)
				
			
genderSeniorCitizenMarriedDependentstenurePhoneServiceMultipleLinesInternetServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportContractPaperlessBillingMonthlyChargesTotalChargesPaymentMethod_Credit card (automatic)PaymentMethod_Electronic checkPaymentMethod_Mailed checkChurn
0
0
0
1
0
1
0
0
1
1
2
1
1
0
1
29.85
29.85
0
1
0
0
1
1
0
0
0
34
1
1
1
2
1
2
1
1
0
56.95
1889.5
0
0
1
0
2
1
0
0
0
2
1
1
1
2
2
1
1
0
1
53.85
108.15
0
0
1
1

الخطوة الثالثة: تحضير البيانات من أجل تدريب النماذج

Step Three: Prepare Data for Machine Learning Training

أ- فصل البيانات

كما أشرنا سابقا في الجزء الأول، نحن نقوم بفصل البيانات إلى جزئين من أجل اختبار دقة النموذج. فلننظر إلى كيفية توزيع العملاء في عمود الـ Churn كما يلي

				
					print('Customer Churn distribution')
display(encoded_df.Churn.value_counts())
encoded_df.Churn.value_counts(normalize = False).plot(kind= 'bar', color = 'darkblue');
				
			
				
					print('Customer Churn Percentages')
display(encoded_df.Churn.value_counts(normalize = True))
				
			

نلاحظ أنه يوجد 5,174 عميل ما زال مستمرا مع الشركة، ومن الناحية الأخرى يوجد لدينا معلومات 1,869 عميل قد قام بترك الشركة. وحين النظر إلى النسب، نجد أن نسبة الذين تركوا الشركة هي 26.5%. ومن أجل اختبار دقة النموذج بشكل فعال، نقوم بالمحافظة على هذه النسب في كلا الجدولين (جدول التدريب وجدول الاختبار) ومن أجل القيام بذلك نقوم باستخدام وظيفة StratifiedShuffleSplit والتي تقوم بالحفاظ على نسبة توزيع العمود بالمستهدف

				
					feature_cols = encoded_df.columns[:-1] # select feature columns (Independent columns)

from sklearn.model_selection import StratifiedShuffleSplit

# Get the split indexes
strat_shuf_split = StratifiedShuffleSplit(n_splits=1, 
                                          test_size=0.25, 
                                          random_state=123) # Taking 25% of the dataset as the test set 

# We use 'next' to get the arrays from the generator object.
train_idx, test_idx = next(strat_shuf_split.split(encoded_df[feature_cols], encoded_df.Churn))

# Create the splits
X_train = encoded_df.loc[train_idx, feature_cols] # loc[index,column]
y_train = encoded_df.loc[train_idx, 'Churn']
X_test  = encoded_df.loc[test_idx, feature_cols]
y_test  = encoded_df.loc[test_idx, 'Churn']
				
			

كما في الدرس الماضي، أصبح لدنيا أربعة متغيرات كالتالي

للتحقق من أن توزيع العمود المستهدف في كلا من مجموعتي التدريب والاختبار متساوي

				
					y_train.value_counts(normalize=True)
				
			
0    0.73457
1    0.26543
Name: Churn, dtype: float64
				
					y_test.value_counts(normalize=True)
				
			
0    0.73481
1    0.26519
Name: Churn, dtype: float64

ب- إعادة وزن قيم الأعمدة

الآن سوف نقوم بالخطوة الأخيرة قبل تدريب النماذج وهي إعادة وزن الأعمدة. وذلك مثل ما ذكرنا في الجزء الأول من أجل جعل الأعمدة ذات أثر متساوي في بناء النموذج

				
					from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
				
			

الخطوة الرابعة: تدريب النماذج وتقييم أداؤها

Step Four: Train and Evaluate the ML Models

سوف نقوم بتدريب ثلاثة نماذج وتقييم أداؤها، هذه النماذج سوف تكون باستخدام الخوارزميات التالية

K-Nearest Neighbor (KNN)

خوارزمية تتوقع التصنيف بناء على تصنيف العملاء القريبين (الجيران)

Support Vector Machine (SVM)

خوارزمية تتوقع التصنيف بناء على فصل المجموعات

Logistic Regression (LR)

خوارزمية تتوقع احتمالية التصنيف

أيضا، كما أنه هنالك معاير لتقييم أداء نماذج الانحدار الخطي Linear Regression، هناك أيضا معاير لتقييم الأداء في نماذج التصنيف Classification، والمعاير المستخدمة في هذا المشروع هي Accuracy Precision Recall f1-score.

ونحن ننصح بالاطلاع على معنى كل معيار والغرض منه من خلال زيارة هذا الثريد المميز الذي قام به أحد أعضاء فريق فهم "محمد عثمان".

A- K Nearest Neighbor
				
					from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=7) # We will use 7 neighbors, feel free to try other values 
knn.fit(X_train, y_train)
y_preds = knn.predict(X_test)
				
			
				
					from sklearn.metrics import accuracy_score, classification_report
print(classification_report(y_test, y_preds))
print('-------------')
print('Accuracy score: ', round(accuracy_score(y_test, y_preds), 2))
				
			
B - Support Vector Machine
				
					from sklearn.svm import SVC
SVM_Model = SVC(kernel='rbf',gamma=1)
SVM_Model.fit(X_train, y_train)
y_preds = SVM_Model.predict(X_test)
				
			
				
					print(classification_report(y_test, y_preds))
print('-------------')
print('Accuracy score: ', round(accuracy_score(y_test, y_preds), 2))
				
			
C - Logistic Regression

للتنويه
على الرغم من تشابه اسم Logistic Regression مع Linear Regression إلا أن الـ Logistic Regression يُستعمل فقط في التصنيف وليس في توقع القيم المتصلة على غرار الانحدار الخطي.

				
					from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(solver='liblinear')
lr.fit(X_train, y_train)
lr_preds = lr.predict(X_test)
lr_prob = lr.predict_proba(X_test).max(axis=1)


Logistic_Results = (pd.DataFrame([lr_preds,lr_prob])
                    .T.rename(columns={0:'Prediction',1:'Probability'}))
Logistic_Results.head(10)
				
			
PredictionProbability
0
1
0.743765
1
0
0.958825
2
0
0.996193
3
0
0.834216
4
0
0.953707
5
1
0.506502
6
0
0.77516
7
0
0.692961
8
0
0.722585
9
0
0.993586
				
					print(classification_report(y_test, lr_preds))
print('-------------')
print('Accuracy score: ', round(accuracy_score(y_test, lr_preds), 2))
				
			
              precision    recall  f1-score   support

           0       0.84      0.90      0.87      1294
           1       0.65      0.52      0.58       467

    accuracy                           0.80      1761
   macro avg       0.75      0.71      0.72      1761
weighted avg       0.79      0.80      0.79      1761

-------------
Accuracy score:  0.8

نلاحظ أن أحد مزايا خوارزمية Logistic Regression هي القدرة على إعطاء التوقع مع احتمالية حصوله. فمثلا، لقد توقع النموذج أن العميل الأول في مجموعة الاختبار سوف يترك الشركة واحتمالية حصول هذا الأمر هي 0.74

خطوة إضافية: تحسين معدل الاسترجاع

Bonus Step: Improve Recall Score

نلاحظ أن نموذج الـ Logistic Regression قد أحرز أعلى نتيجة Accuracy = 80%. إلا أن نماذجنا الحالية ما زالت تعاني عند توقع الـ Churn بشكل دقيق بسبب أن الـ Recall منخفض وللتوضيح أكثر، إن معيار recall يساوي 0.52 عند توقع الـ1، أي حين توقع مَن مِن العملاء سوف يترك الشركة [Churn Prediction] مما يعني أن هناك 52% من الذين تركوا الشركة توقعناهم بشكل صحيح أنهم تركوا الشركة. وهناك 48% من الذين تركوا الشركة لم نستطع توقع تركهم. إحد أسباب هذه المشكلة هي وجود صفوف قليلة لمن ترك الشركة مقارنة بصفوف الموجودين حيث أن نسبة صفوف الذين تركوا الشركة هي 26.5% فقط. وهذه مشكلة معروفة بـ Imbalanced target feature.

إحدى حلول هذه المشكلة هي توليد صفوف صناعية تكون مشابهة لصفوف العملاء الذين تركوا الشركة وذلك من أجل موازنة توزيع قيم العمود المستهدف كالتالي

				
					from imblearn.over_sampling import SMOTE
Smote = SMOTE(random_state=123)
X_Smote, y_Smote = Smote.fit_resample(X_train, y_train)
				
			
				
					lr = LogisticRegression(solver='liblinear')
lr.fit(X_Smote, y_Smote)
lr_preds = lr.predict(X_test)
				
			
				
					print(classification_report(y_test, lr_preds))
print('-------------')
print('Accuracy score: ', round(accuracy_score(y_test, lr_preds), 2))
				
			
              precision    recall  f1-score   support

           0       0.91      0.75      0.82      1294
           1       0.53      0.78      0.63       467

    accuracy                           0.76      1761
   macro avg       0.72      0.77      0.72      1761
weighted avg       0.81      0.76      0.77      1761

-------------
Accuracy score:  0.76

نلاحظ أن دقة النموذج الكلية قد انخفضت إلى 76% ولكن دقة الـ Recall قد ارتفعت إلى 78% وهو مؤشر جيد؛ لأن حين توقع مَن مِن العملاء سوف يترك الشركة، معيار الـ Recall يعتبر هو ذو الأهمية الكبرى.

نصيحة فهم للتعلم

في هذا الدرس تحدثنا عن النوع الثاني من أنواع تعلم الآلة الخاضع للإشراف ألا وهو التصنيف. نصيحة فهم هي التعرف على نقاط القوة والضعف للخوارزميات المستعملة في هذا الدرس. بالإضافة إلى التعرف إلى معايير تقييم جودة نماذج التصنيف مثل الدقة والاسترجاع. يمكنكم أيضا زيارة موقع Kaggle لتجربة حلول مشاريع أخرى باستخدام خوارزميات التصنيف لتثبيت ما تم تعلمه.

ماذا تعلمنا؟

نشرة فهم البريدية
لتبقى على اطلاع دائم على كل ما هو جديد مما تقدمه منصة فهم، انضم لنشرتنا البريدية.
طالب ماجستير في علم البيانات، جامعة مالايا - كوالا لامبور ماليزيا. بكالوريوس في الهندسة الكهربائية من الجامعة الإسلامية - المدينة المنورة السعودية. باحث في مجال تطوير أنظمة الطاقة المتجددة باستخدام علم البيانات وإنترنت الأشياء.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *