سلسلة فهم لتعلم الآلة – الجزء الأول | Linear Regression

الأثنين 04 جمادى الأولى 1444ھ الأثنين 28 نوفمبر 2022م
فيسبوك
تويتر
واتساب
تيليجرام
لينكدإن
المحتوى
توقع أسعار المركبات
Vehicle Price Prediction

مقدمة

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

هل الذكاء الاصطناعي هو تعلم الآلة؟

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

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

إذًا ما هو تعلم الآلة؟

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

ماهي أنواع تعلم الآلة؟

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

التعريف
في هذا النوع من نماذج تعلم الآلة، يكون لدينا عمود محدد نعلم قيمهُ السابقة ونريد توقع القيم المستقبلية فيه.

مثال
أسعار السيارات والعقار حيث أننا نعلم أسعار السيارات الموجودة حاليا، وسوف نستخدم هذه المعرفة في توقع أسعار السيارات الجديدة.

التعريف
في هذا النوع من تعلم الآلة، لا يوجد لدينا عمود محدد نستطيع بناء التوقعات عليه.

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

التعريف
هي الأنواع التي تكون إما خليط من النوعين الأولين أو أنها تعتمد على طرق أخرى.

مثال
إيجاد الفيديوهات المتشابهة مثل توصيات اليوتيوب.

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

ما نوع البيانات المستخدم في تعلم الآلة؟

عند بناء نماذج تعلم الآلة نقوم باستخدام البيانات المنظمة ثنائية الأبعاد والمعروفة بالجداول. حيث أن جداول البيانات تحتوي على أعمدة وصفوف تستخدم في تدريب (بناء خبرة) النماذج.

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

ماهي مصطلحات تعلم الآلة؟

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

1- صف: Instance

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

2- صفة، عمود، ميزة: Feature, Column, Attribute

الأعمدة أو الصفات أو الميزات هي مصطلحات تصف نفس الشيء، ألا وهو الأعمدة في جدول البيانات، وفي العادة هناك نوعين من الأعمدة، أعمدة مستقلة وأعمدة مستهدفة.

3- العمود المستهدف: Target column

هو العمود الذي نريد توقع قيمته وهو يعتمد على قيمة الأعمدة الأخرى.

4- أعمدة مستقلة: Independent columns

هذه هي الأعمدة الي تستخدم لتوقع قيمة العمود المستهدف.

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

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

تستطيع تنزيل البيانات من هنا

أو عبر الرابط الأصلي لمصدر البيانات

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

Step One: Explore Data
				
					import pandas as pd
df = pd.read_csv('https://github.com/KAFSALAH/Fihm_Lessons/raw/master/ML_Series1_Regression/CarPrices.csv')

# General info about the data - معلومات عامة عن البيانات
print('——————————————————————————')
print('أول ثلاثة صفوف في الجدول هي')
display(df.head(3))
print('——————————————————————————')
print('آخر ثلاثة صفوف في الجدول هي')
display(df.tail(3))
print('——————————————————————————')
print('عدد الصفوف والأعمدة في الجدول هي')
display(df.shape)
print('——————————————————————————')
print('أنواع الأعمدة المستخدمة هي')
display(df.info())
print('——————————————————————————')
print('توزيع البيانات بالنسبة للأعمدة التي تحتوي على قيم أرقام')
display(df.describe())
				
			

أول ثلاثة صفوف في الجدول هي

car_IDsymbolingCarNamefueltypeaspirationdoornumbercarbodydrivewheelenginelocationwheelbase...enginesizefuelsystemboreratiostrokecompressionratiohorsepowerpeakrpmcitympghighwaympgprice
0
1
3
alfa-romero giulia
gas
std
two
convertible
rwd
front
88.6
...
130
mpfi
3.47
2.68
9
111
5000
21
27
13495
1
2
3
alfa-romero stelvio
gas
std
two
convertible
rwd
front
88.6
...
130
mpfi
3.47
2.68
9
111
5000
21
27
16500
2
3
1
alfa-romero Quadrifoglio
gas
std
two
hatchback
rwd
front
94.5
...
152
mpfi
2.68
3.47
9
154
5000
19
26
16500

آخر ثلاثة صفوف في الجدول هي

car_IDsymbolingCarNamefueltypeaspirationdoornumbercarbodydrivewheelenginelocationwheelbase...enginesizefuelsystemboreratiostrokecompressionratiohorsepowerpeakrpmcitympghighwaympgprice
202
203
-1
volvo 244dl
gas
std
four
sedan
rwd
front
109.1
...
173
mpfi
3.58
2.87
8.8
134
5500
18
23
21485.0
203
204
-1
volvo 246
diesel
turbo
four
sedan
rwd
front
109.1
...
145
idi
3.01
3.40
23.0
106
4800
26
27
22470.0
204
205
-1
volvo 264gl
gas
turbo
four
sedan
rwd
front
109.1
...
141
mpfi
3.78
3.15
9.5
114
5400
19
25
22625.0

عدد الصفوف والأعمدة في الجدول هي (26 ,205)

أنواع الأعمدة المستخدمة هي

توزيع البيانات بالنسبة للأعمدة التي تحتوي على قيم أرقام

car_IDsymbolingwheelbasecarlengthcarwidthcarheightcurbweightenginesizeboreratiostrokecompressionratiohorsepowerpeakrpmcitympghighwaympgprice
count
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
205.000000
mean
103.000000
0.834146
98.756585
174.049268
65.907805
53.724878
2555.565854
126.907317
3.329756
3.255415
10.142537
104.117073
5125.121951
25.219512
30.751220
13276.710571
std
59.322565
1.245307
6.021776
12.337289
2.145204
2.443522
520.680204
41.642693
0.270844
0.313597
3.972040
39.544167
476.985643
6.542142
6.886443
7988.852332
min
1.000000
-2.000000
86.600000
141.100000
60.300000
47.800000
1488.000000
61.000000
2.540000
2.070000
7.000000
48.000000
4150.000000
13.000000
16.000000
5118.000000
25%
52.000000
0.000000
94.500000
166.300000
64.100000
52.000000
2145.000000
97.000000
3.150000
3.110000
8.600000
70.000000
4800.000000
19.000000
25.000000
7788.000000
50%
103.000000
1.000000
97.000000
173.200000
65.500000
54.100000
2414.000000
120.000000
3.310000
3.290000
9.000000
95.000000
5200.000000
24.000000
30.000000
10295.000000
75%
154.000000
2.000000
102.400000
183.100000
66.900000
55.500000
2935.000000
141.000000
3.580000
3.410000
9.400000
116.000000
5500.000000
30.000000
34.000000
16503.000000
max
205.000000
3.000000
120.900000
208.100000
72.300000
59.800000
4066.000000
326.000000
3.940000
4.170000
23.000000
288.000000
6600.000000
49.000000
54.000000
45400.000000

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

Step Two: Preprocess Data

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

				
					df.isnull().sum()
				
			

لقد تحققنا وبالفعل لا يوجد لدينا أي عمود يحتوي على معلومات ناقصة. الآن سوف نقوم بالتحقق من أنواع الأعمدة المستخدمة كالتالي

				
					df.dtypes
				
			

لاحظ كيف أن كل عمود لابد أن يحتوي على نوع واحد فقط، ونلاحظ أنه يوجد لدنيا ثلاثة أنواع من البيانات:

وفي العموم نستطيع أن نقول أن هناك أربعة أنواع من البيانات

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

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

				
					# Create a table with 5 customers' info about their age and gender
#  انظر إلى الجدول الافتراضي أدناه سوف تلاحظ بيانات العمر والجنس لخمسة عملاء
Customers = {
    'customer_id' : [1,2,3,4,5],
    'customer_age' : [20, 44, 27,32,29],
    'customer_gender' : ['M','F','F','M','F']
            }
Customers_df = pd.DataFrame(Customers)
Customers_df
				
			
customer_idcustomer_agecustomer_gender
0
1
20
M
1
2
44
F
2
3
27
F
3
4
32
M
4
5
29
F

بما أن ميزة العمر (عمود العمر) عبارة عن أرقام، نستطيع استخدامها في نموذج تعلم الآلة ولكن من الناحية الأخرى لا نستطيع استخدام جنس العميل لأنه ليس ممثل عن طريق الأرقام بل عن طريق الحروف. ولتمثيله عن طريق الأرقام نقوم باستخدام وظيفة في مكتبة البانداز معروفة بـ get_dummies لتقوم بعملية ترميز الأعمدة الكتابية والمعروفة بعملية الـ Encoding.

				
					# We will use get_dummies to encode object-nominal values into numerical
# سوف نقوم بترميز الأعمدة التي تحتوي على كتابات باستخدام الكود التالي
Customers_df = pd.get_dummies(Customers_df)
Customers_df
				
			
customer_idcustomer_agecustomer_gender_Fcustomer_gender_M
0
1
20
0
1
1
2
44
1
0
2
3
27
1
0
3
4
32
0
1
4
5
29
1
0

الذي قمنا بعمله هو تحويل العمود الذي يحتوي على كتابة (عمود الجنس) إلى عمودين

1- customer_gender_F

إذا كانت القيمة 1 في هذا العمود فهذا يعني أن العميل أنثى.

2- customer_gender_M

إذا كانت القيمة 1 في هذا العمود فهذا يعني أن العميل ذكر.

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

				
					cars = {
    'car_id': [1,2,3,4],
    'Type': ['BMW','Mercedes','Toyota','Mercedes']
}

cars_df = pd.DataFrame(cars)
display(cars_df)

print('بعد التحويل تصبح كالتالي')
display(pd.get_dummies(cars_df))
				
			
car_idType
0
1
BMW
1
2
Mercedes
2
3
Toyota
3
4
Mercedes

بعد التحويل تصبح كالتالي

car_idType_BMWType_MercedesType_Toyota
0
1
1
0
0
1
2
0
1
0
2
3
0
0
1
3
4
0
1
0

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

إذًا، عدد الأعمدة الناتجة من عملية الترميز يساوي ( عدد القيم المميزة - ١ ) لأننا سوف نحذف العمود الأصلي

Number of generated columns = Number of unique entities in the column - 1

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

والآن فلنقم بالتحقق من القيم المميزة في كل عمود كتابي (Object) من أجل التحقق من كمية الأعمدة التي سوف تنتج بعد عملية الترميز

				
					# To identify object columns - لتحديد أسماء الأعمدة التي تحتوي على كتابات
print('Object columns are as follows')
df.loc[:,df.dtypes==object].columns
				
			
				
					# Store them in a list - حفظها في قائمة
object_columns = df.loc[:,df.dtypes==object].columns.tolist()
# Identify number of unique elements in each object-nominal columns
# سنقوم بتحديد عدد العناصر المميزة في كل عمود كتابي
for i in object_columns:
    print('Number of unique elements in' , i, 'is', len(df.loc[:,i].unique()))
				
			
Number of unique elements in CarName is 147
Number of unique elements in fueltype is 2
Number of unique elements in aspiration is 2
Number of unique elements in doornumber is 2
Number of unique elements in carbody is 5
Number of unique elements in drivewheel is 3
Number of unique elements in enginelocation is 2
Number of unique elements in enginetype is 7
Number of unique elements in cylindernumber is 7
Number of unique elements in fuelsystem is 8

حسنًا، لقد استطعنا تحديد عدد القيم المميزة في كل عمود كتابي، ونلاحظ أن في عمود (اسم السيارة) يوجد لدينا 147 قيمة مميزة، مما يعني أنه سوف يكون لدينا 146 عمود جديد إضافي فقط من هذا العمود بعد عملية الترميز. ونحن نريد تجنب هذا العدد الكبير من الأعمدة لأنه يتطلب قوة حسابية عالية بل ربما يضر في دقة النموذج. ومن أجل حل هذه المشكلة، سوف نقوم باستخدام اسم الشركة فقط بدلا من اسم كل سيارة من أجل تقليل عدد الأعمدة الذي سوف ينتج من الترميز.

				
					# Split compnay name and store it in a new column 
# فصل اسم الشركة عن اسم السيارة وحفظه في عمود جديد
companyname = df['CarName'].apply(lambda x : x.split(' ')[0])

# Store the 'companename' column in the dataset 
# تخزين العمود الجديد 'اسم السيارة' في قاعدة البيانات
df.insert(3,"companyname",companyname)

# Drop the 'CarName' column 
# التخلص من عمود اسم السيارة
df.drop(['CarName'], axis=1, inplace=True)
df.head(3)
				
			
car_IDsymbolingcompanynamefueltypeaspirationdoornumbercarbodydrivewheelenginelocationwheelbase...enginesizefuelsystemboreratiostrokecompressionratiohorsepowerpeakrpmcitympghighwaympgprice
0
1
3
alfa-romero
gas
std
two
convertible
rwd
front
88.6
...
130
mpfi
3.47
2.68
9.0
111
5000
21
27
13495.0
1
2
3
alfa-romero
gas
std
two
convertible
rwd
front
88.6
...
130
mpfi
3.47
2.68
9.0
111
5000
21
27
16500.0
2
3
1
alfa-romero
gas
std
two
hatchback
rwd
front
94.5
...
152
mpfi
2.68
3.47
9.0
154
5000
19
26
16500.0
				
					# To check companies names in the column - للتحقق من أسماء الشركات الموجودة
print(df.companyname.unique())
				
			
['alfa-romero' 'audi' 'bmw' 'chevrolet' 'dodge' 'honda' 'isuzu' 'jaguar'
 'maxda' 'mazda' 'buick' 'mercury' 'mitsubishi' 'Nissan' 'nissan'
 'peugeot' 'plymouth' 'porsche' 'porcshce' 'renault' 'saab' 'subaru'
 'toyota' 'toyouta' 'vokswagen' 'volkswagen' 'vw' 'volvo']

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

				
					df.companyname = df.companyname.str.lower() # Make all letters in smallcase -  جعل جميع الحروف بالكتابة الصغيرة

# Define a function to replace names  - تعريف وظيفة لإعادة تسمية بعض الشركات 
def replace_name(a,b):
    df.companyname.replace(a,b,inplace=True)

# Rename unique elements - إعادة تسمية العناصر المميزة 
replace_name('alfa-romero','alfa-romeo')
replace_name('maxda','mazda')
replace_name('porcshce','porsche')
replace_name('toyouta','toyota')
replace_name('vokswagen','volkswagen')
replace_name('vw','volkswagen')
				
			
				
					# Now we will calculate the total number of unique elements per object-column
# الآن سوف نقوم بالتحقق من عدد العناصر في كل عمود من نوع كتابي
object_columns = df.loc[:,df.dtypes==object].columns.tolist()
total_generated_columns = 0
for i in object_columns:
    print('Number of unique elements in' , i, 'is', len(df.loc[:,i].unique()))
    total_generated_columns = total_generated_columns + len(df.loc[:,i].unique()) - 1 
    

print('get_dummies will generate:',total_generated_columns)

				
			
Number of unique elements in companyname is 22
Number of unique elements in fueltype is 2
Number of unique elements in aspiration is 2
Number of unique elements in doornumber is 2
Number of unique elements in carbody is 5
Number of unique elements in drivewheel is 3
Number of unique elements in enginelocation is 2
Number of unique elements in enginetype is 7
Number of unique elements in cylindernumber is 7
Number of unique elements in fuelsystem is 8
get_dummies will generate: 50

سوف نقوم بالتحقق أيضا إذا ماكان هناك صفوف متكررة كالتالي

				
					# To check if there is any duplicated rows - للتحقق إن كانت هناك سيارة سجلت مرتين
df.loc[df.duplicated()]
				
			
car_ID
symboling
companyname
fueltype
aspiration
doornumber
carbody
drivewheel
enginelocation
wheelbase
...
enginesize
fuelsystem
boreratio
stroke
compressionratio
horsepower
peakrpm
citympg
highwaympg
price
0 rows × 26 columns

الخطوة الثالثة: استكشاف البيانات

Step Three: EDA

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

Plot 1 - Prices Distribution
				
					import matplotlib.pyplot as plt  # For plotting 1 - المكتبة الأولى للرسم
import seaborn as sns            # For plotting 2 - المكتبة الثانية للرسم
plt.figure(figsize=(16,8))
plt.title('Prices Distribution')
sns.histplot(df.price)
plt.show()
print(df.price.describe(percentiles = [0.25,0.50,0.75,0.85,0.90,1]))
				
			

نلاحظ أن لدينا سعر 205 سيارة. وعلى الرغم من أسعار السيارات المتوسط هو 13,276 إلا أن الانحراف المعياري std.

عالي القيمة مما يعني أن هناك تباين كبير في القيم، وهو ما يمكن ملاحظته حين النظر إلى الطرف اليمين من الرسمة سوف نلاحظ وجود سيارات سعرها أعلى من 40,000.

Plot 2 - Cars Companies and Types
				
					plt.figure(figsize=(16, 6))
plt.subplot(1,2,1)
df.companyname.value_counts().plot(kind  = 'bar', color = 'darkblue')
plt.title('Companies')
plt.xlabel('Car company')
plt.ylabel('Count')
plt.subplot(1,2,2)
df.carbody.value_counts().plot(kind = 'bar', color = 'purple')
plt.title('Cars types')
plt.xlabel('Car type')
plt.ylabel('Count')
plt.show()
				
			
Plot 3 - Used Fuel
				
					plt.figure(figsize=(8, 4))
df.fueltype.value_counts().plot(kind = 'bar', color = 'darkred')
plt.title('Fuel Types')
plt.xlabel('Fuel')
plt.ylabel('Count')
plt.show()
				
			

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

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

Step Four: Prepare Data for Machine Learning Training

الآن تأتي الخطوات الأخيرة قبل بناء النموذج وهي تحضير البيانات بالشكل المناسب وسوف نقوم بذلك عن طريق التالي

أولا سوف نقوم بإزالة عمود car_ID؛ لأن هذا العمود لا يعطي أية معلومات حقيقة تأثر على سعر السيارة.

				
					df.drop('car_ID',axis = 1, inplace = True)
				
			

ثم كما تناقشنا سابقا، سوف نقوم بترميز الأعمدة الكتابة وتحويلها إلى أرقام (Encoding Nominal Values).

				
					ecnoded_df = pd.get_dummies(df)
print('The new df is')
display(ecnoded_df.head(3))
print('The size of the dataframe is')
print(' We have', ecnoded_df.shape[0], 'rows, and', ecnoded_df.shape[1], 'columns')
				
			
symbolingwheelbasecarlengthcarwidthcarheightcurbweightenginesizeboreratiostrokecompressionratio...cylindernumber_twelvecylindernumber_twofuelsystem_1bblfuelsystem_2bblfuelsystem_4bblfuelsystem_idifuelsystem_mfifuelsystem_mpfifuelsystem_spdifuelsystem_spfi
0
3
88.6
168.8
64.1
48.8
2548
130
3.47
2.68
9.0
...
0
0
0
0
0
0
0
1
0
0
1
3
88.6
168.8
64.1
48.8
2548
130
3.47
2.68
9.0
...
0
0
0
0
0
0
0
1
0
0
2
1
94.5
171.2
65.5
52.4
2823
152
2.68
3.47
9.0
...
0
0
0
0
0
0
0
1
0
0

الآن، سوف نقوم بفصل البيانات على مرتين: الفصل الأول سنقوم بفصل العمود المستهدف (السعر) عن باقي الأعمدة (المتغيرات المستقلة) عن طريق التالي

				
					# Create X & y - فصل البيانات إلى مجموعة س و ص
# X represetns the independet variables - س يمثل المتغيرات المستقلة التي تستخدم لتوقع السعر
X = ecnoded_df.drop('price', axis = 1) 

# Targer variable - المتغير الذي نريد توقعه وهو السعر
y = ecnoded_df['price']
				
			

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

X(Columns) * (Parameters) >> leads to Y(Predictions)

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

				
					from sklearn.model_selection import train_test_split # for splitting the data - الكود المستخدم لفصل البيانات

# We will make the test size = 30% - سنقوم بعمل حجم الاختبار مساوي لـ30 بالمئة
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=1204)
				
			

نلاحظ أن عملية الفصل انتجت لنا 4 متغيرات ووصفهم كالتالي

الآن سوف نقوم بخطوة أخيرة قبل التدريب: ألا وهي توحيد المقاييس Scaling.

لماذا نقوم بتوحيد المقاييس؟ حسنا انظر إلى الجدول الذي بالأسفل

سوف تلاحظ أن لدينا عمودين لتوقع سعر السيارة: أحدهم حجم المحرك ويقاس بوحدة الـ CC

والعمود الثاني هو عدد الإسطوانات والتي تكون قيمتها 4,6,8. نحن نعلم أن كلا من حجم المحرك وعدد الإسطوانات هي معايير مهمة في تحديد سعر السيارة. ولكن إن لم نقم بتوحيد المقاييس سوف يكون أثر حجم المحرك أكبر بكثير من عدد الإسطوانات لأن قيم حجم المحرك بالآلاف أما قيمة عدد الإسطوانات بالآحاد . ولحل هذه المشكلة نقوم بتوحيد المقاييس كالتالي

والذي سوف ينتج قيم جديدة للأعمدة تتراوح ما بين الصفر والواحد. حيث أن صفر تمثل أقل قيمة وواحد تمثل أعلى قيمة. وبذلك، نحن نجعل أثر كل عمود في توقع السعر متساوي مع الأعمدة الأخرى لأن كل قيم الأعمدة تتراوح ما بين 0-1.

				
					from sklearn.preprocessing import MinMaxScaler # To scale columns - لتوحيد المقاييس

s = MinMaxScaler()
X_train_s = s.fit_transform(X_train)
X_test_s = s.transform(X_test)
				
			

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

Step Five: Train and Evaluate the ML Models

حسنا! لقد وصلنا إلى الخطوة الأهم ألا وهي اختيار النموذج المناسب لهدفنا. إن هدفنا في هذا المشروع هو توقع أسعار السيارات، ولو نظرنا إلى نوع هذا العمود، لوجدنا أن نوعه هو عبارة عن عمود رقمي متصل أي يحتوي على أرقام. وإحدى النماذج التي تستخدم لتوقع القيم المتصلة الرقمية هو الانحدار الخطي والمعروف بـ Regression.

وفي هذا المشروع، سوف نستخدم نوعين من الانحدار الخطي، ألا وهم Lasso and Ridge وسوف نختار الذي سوف يحرز نتيجة أعلى في اختبار تقييم الأداء، تقييم أداء الانحدار الخطي في هذا المشروع سيكون عن طريق معيارين وهم

R2: قيمة تتراوح بين 0-1 كلما اقتربنا من 1 كل ما كان توقعنا قريب من القيمة الحقيقية.

RMSE: قيمة تمثل كمية الخطأ في توقعنا، كلما أخطأنا كلما ارتفعت.

				
					from sklearn.linear_model import  Lasso, Ridge # for regression - لتدريب نموذج الانحدار الخطي
from sklearn.metrics import r2_score, mean_squared_error # for evaluation - لتقييم الآداء
import numpy as np
				
			
				
					# Lasso regression model - نموذج لاسو
Lasso = Lasso() # initiate lasso object - نقوم أولا بتحضير النموذج
Lasso.fit(X_train_s, y_train) # Train the model using training data -  نقوم بتدريب النموذج باستخدام بيانات التدريب
Lasso_pred = Lasso.predict(X_test_s) # Predict the price of testing rows - الآن نقوم بتوقع أسعار السيارات في صفوف الاختبار   


#Evalaute Lasso model performance - تقييم أداء نموذج لاسو
print('R2 value is', r2_score(y_test, Lasso_pred))
print('RMSE value is', np.sqrt(mean_squared_error(y_test, Lasso_pred)))
				
			
R2 value is 0.8789021957699282
RMSE value is 2911.53212901985
				
					# Ridge regression model
Ridge = Ridge() # Initiate ridge object
Ridge.fit(X_train_s, y_train)
Ridge_pred = Ridge.predict(X_test_s)
print('R2 value is', r2_score(y_test, Ridge_pred))
print('RMSE value is', np.sqrt(mean_squared_error(y_test, Ridge_pred)))
				
			
R2 value is 0.9319482284094119
RMSE value is 2182.59507321917

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

				
					figure = plt.figure(figsize=(12,8))

ax = plt.axes()
ax.plot(y_test, Ridge_pred, 
         marker='o', ls='', ms=3.0,color='sienna')

lim = (0, y_test.max())

ax.set(xlabel='Actual Price', 
       ylabel='Predicted Price', 
       xlim=lim,
       ylim=lim)
plt.title('Ridge Regression Model Results', fontsize=14)
ax.xaxis.label.set_size(14);
ax.yaxis.label.set_size(14);
				
			

خطوة إضافية: إيجاد الصفات الأكثر توافقا مع السعر

Bonus Step: Highest Correlated Values with Price

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

				
					corr = ecnoded_df.corr()
plt.figure(figsize=(20,16))
plt.title('Correlation Map')
sns.heatmap(corr, annot=False, cmap="GnBu");
				
			

هذه الرسمة تمثل التوافق بين كل الأعمدة، الذي يهمنا هو صف (السعر). عند النظر إليه، نلاحظ أن قيم توافقه مع باقي الأعمدة تتراوح ما بين -1 و 1. إذا كانت القيمة قريبة من 1 فهذا يعني أن ارتفاع قيمة هذا العمود سيؤدي إلى ارتفاع السعر، والعكس صحيح.

نستطيع إيجاد ماهي أعلى القيم المتوافقة مع قيمة سعر السيارة إما إيجابيا أو سلبيا عن طريق التالي

				
					# Top 5 features that icnrease car price
# أكثر 5 قيم التي ترفع من قيمة سعر السيارة
corr.price.sort_values(ascending=False)[1:6]
				
			
enginesize    0.874145
curbweight    0.835305
horsepower    0.808139
carwidth      0.759325
carlength     0.682920
Name: price, dtype: float64
				
					# Top 5 features that decrease car price
# أكثر 5 القيم التي تنقص من قيمة السيارة
corr.price.sort_values(ascending=True)[1:6]
				
			

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

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

ماذا تعلمنا؟

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

    شكرا جزيلا – شرح جميل

  2. فهد عبدالرحمن فهد عبدالرحمن

    الشرح جميل وممتاز وجزاك الله خير
    لكن في تحديد صنف الجنس بالشرح أشرت الى 1 أنثى وأيضاً 1 ذكر

اترك تعليقاً

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