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

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

ماهي مصطلحات تعلم الآلة؟
خلال رحلتنا في هذه السلسلة، سوف نقوم بتقديم مصطلحات جديدة تستخدم عند بناء نماذج تعلم الآلة. وسوف نقوم بذكرها باللغة الإنجليزية وترجمتها باللغة العربية. في هذا المشروع سوف نستخدم المصطلحات التالية:
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_ID | symboling | CarName | fueltype | aspiration | doornumber | carbody | drivewheel | enginelocation | wheelbase | ... | enginesize | fuelsystem | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |
3 rows × 26 columns
آخر ثلاثة صفوف في الجدول هي
| car_ID | symboling | CarName | fueltype | aspiration | doornumber | carbody | drivewheel | enginelocation | wheelbase | ... | enginesize | fuelsystem | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |
3 rows × 26 columns
عدد الصفوف والأعمدة في الجدول هي (26 ,205)
أنواع الأعمدة المستخدمة هي
RangeIndex: 205 entries, 0 to 204 Data columns (total 26 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 car_ID 205 non-null int64 1 symboling 205 non-null int64 2 CarName 205 non-null object 3 fueltype 205 non-null object 4 aspiration 205 non-null object 5 doornumber 205 non-null object 6 carbody 205 non-null object 7 drivewheel 205 non-null object 8 enginelocation 205 non-null object 9 wheelbase 205 non-null float64 10 carlength 205 non-null float64 11 carwidth 205 non-null float64 12 carheight 205 non-null float64 13 curbweight 205 non-null int64 14 enginetype 205 non-null object 15 cylindernumber 205 non-null object 16 enginesize 205 non-null int64 17 fuelsystem 205 non-null object 18 boreratio 205 non-null float64 19 stroke 205 non-null float64 20 compressionratio 205 non-null float64 21 horsepower 205 non-null int64 22 peakrpm 205 non-null int64 23 citympg 205 non-null int64 24 highwaympg 205 non-null int64 25 price 205 non-null float64 dtypes: float64(8), int64(8), object(10) memory usage: 41.8+ KB
None
توزيع البيانات بالنسبة للأعمدة التي تحتوي على قيم أرقام
| car_ID | symboling | wheelbase | carlength | carwidth | carheight | curbweight | enginesize | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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()
car_ID 0 symboling 0 CarName 0 fueltype 0 aspiration 0 doornumber 0 carbody 0 drivewheel 0 enginelocation 0 wheelbase 0 carlength 0 carwidth 0 carheight 0 curbweight 0 enginetype 0 cylindernumber 0 enginesize 0 fuelsystem 0 boreratio 0 stroke 0 compressionratio 0 horsepower 0 peakrpm 0 citympg 0 highwaympg 0 price 0 dtype: int64
لقد تحققنا وبالفعل لا يوجد لدينا أي عمود يحتوي على معلومات ناقصة. الآن سوف نقوم بالتحقق من أنواع الأعمدة المستخدمة كالتالي
df.dtypes
car_ID int64 symboling int64 CarName object fueltype object aspiration object doornumber object carbody object drivewheel object enginelocation object wheelbase float64 carlength float64 carwidth float64 carheight float64 curbweight int64 enginetype object cylindernumber object enginesize int64 fuelsystem object boreratio float64 stroke float64 compressionratio float64 horsepower int64 peakrpm int64 citympg int64 highwaympg int64 price float64 dtype: object
لاحظ كيف أن كل عمود لابد أن يحتوي على نوع واحد فقط، ونلاحظ أنه يوجد لدنيا ثلاثة أنواع من البيانات:
- أرقام صحيحة مثل عمود عدد الأحصنة int64: integers
- أرقام تحتوي على فواصل مثل عمود السعر float64: decimal
- كتابة مثل نوع السيارة أو نوع المحرك object: nominal
وفي العموم نستطيع أن نقول أن هناك أربعة أنواع من البيانات
- Numerical data [integer]
- Numerical data [float]
- Object data [nominal]
- Object data [ordinal]
إن النوع الأول هو الأعداد الصحيحة وهي الأعداد التي لا تحتوي على فواصل. أما النوع الثاني فهو أيضا أعداد ولكنها تحتوي على فواصل. إن النوع الأول والثاني نستطيع استخدامهم في تعلم الآلة دون مشاكل. أما النوع الثالث فهو بيانات تكون مكتوبة باستخدام الحروف ولكن لا يوجد ترتيب فيها مثل جنس العميل (ذكر أو أنثى). والنوع الآخير هو البيانات التي تكون أيضا مكتوبة باستخدام الحروف ولكن الترتيب مهم فيها مثل (تقييم أربع نجوم و ثلاث نجوم) حيث أننا نريد أن نعطي قيمة أكبر للأربع نجوم مقارنة بالثلاثة نجوم. وعلى العموم إن لكل نوع طريقة معينة للتعامل معه.
تذكر أن نماذج تعلم الآلة ماهي إلا معادلات رياضية تستخدم لتوقع نتيجة معينة. ولإدخال البيانات في نموذج تعلم الآلة لابد أن تكون جميع الأعمدة مكونة عن أرقام. ولذلك سنقوم بأخذ الأعمدة التي تحتوي على حروف وتحويلها إلى أعمدة تحتوي على أرقام مع الحفاظ على البيانات دون فقدانها كما في المثال التالي
# 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_id | customer_age | customer_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_id | customer_age | customer_gender_F | customer_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_id | Type |
---|---|---|
0 | 1 | BMW |
1 | 2 | Mercedes |
2 | 3 | Toyota |
3 | 4 | Mercedes |
بعد التحويل تصبح كالتالي
| car_id | Type_BMW | Type_Mercedes | Type_Toyota |
---|---|---|---|---|
0 | 1 | 1 | 0 | 0 |
1 | 2 | 0 | 1 | 0 |
2 | 3 | 0 | 0 | 1 |
3 | 4 | 0 | 1 | 0 |
وما نكتشفه أن عمود نوع السيارة تم حذفه وفصله إلى ثلاثة أعمدة، لأن العمود الأصلي يحتوي على ثلاثة قيم مميزة، ونستنتج من هذا أننا نقوم بفصل العمود الذي يحتوي على كتابة إلى أعمدة متعددة بحيث يحتوي كل عمود على 0 أو 1 من أجل تمثيل نوع واحد فقط وبذلك يكون عدد الأعمدة الناتج مساوي لعدد الأنواع التي كانت في العمود سابقا
إذًا، عدد الأعمدة الناتجة من عملية الترميز يساوي ( عدد القيم المميزة - ١ ) لأننا سوف نحذف العمود الأصلي
للتنويه
إن هناك طرق أخرى للترميز وذات جودة أفضل وسوف نتطرق لها في المشاريع اللاحقة
والآن فلنقم بالتحقق من القيم المميزة في كل عمود كتابي (Object) من أجل التحقق من كمية الأعمدة التي سوف تنتج بعد عملية الترميز
# To identify object columns - لتحديد أسماء الأعمدة التي تحتوي على كتابات
print('Object columns are as follows')
df.loc[:,df.dtypes==object].columns
Object columns are as follows
Index(['CarName', 'fueltype', 'aspiration', 'doornumber', 'carbody', 'drivewheel', 'enginelocation', 'enginetype', 'cylindernumber', 'fuelsystem'], dtype='object')
# 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_ID | symboling | companyname | fueltype | aspiration | doornumber | carbody | drivewheel | enginelocation | wheelbase | ... | enginesize | fuelsystem | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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الآن وقبل أن نبني نموذج تعلم الآلة، سوف نستخدم الرسم لاستكشاف البيانات ومعرفة ماذا تمثل وما هو الاستخدام الأمثل لها؟
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]))

count 205.000000 mean 13276.710571 std 7988.852332 min 5118.000000 25% 7788.000000 50% 10295.000000 75% 16503.000000 85% 18500.000000 90% 22563.000000 100% 45400.000000 max 45400.000000 Name: price, dtype: float64
نلاحظ أن لدينا سعر 205 سيارة. وعلى الرغم من أسعار السيارات المتوسط هو 13,276 إلا أن الانحراف المعياري std.
عالي القيمة مما يعني أن هناك تباين كبير في القيم، وهو ما يمكن ملاحظته حين النظر إلى الطرف اليمين من الرسمة سوف نلاحظ وجود سيارات سعرها أعلى من 40,000.
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()

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')
The new df is
| symboling | wheelbase | carlength | carwidth | carheight | curbweight | enginesize | boreratio | stroke | compressionratio | ... | cylindernumber_twelve | cylindernumber_two | fuelsystem_1bbl | fuelsystem_2bbl | fuelsystem_4bbl | fuelsystem_idi | fuelsystem_mfi | fuelsystem_mpfi | fuelsystem_spdi | fuelsystem_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 |
The size of the dataframe is We have 205 rows, and 75 columns
الآن، سوف نقوم بفصل البيانات على مرتين: الفصل الأول سنقوم بفصل العمود المستهدف (السعر) عن باقي الأعمدة (المتغيرات المستقلة) عن طريق التالي
# Create X & y - فصل البيانات إلى مجموعة س و ص
# X represetns the independet variables - س يمثل المتغيرات المستقلة التي تستخدم لتوقع السعر
X = ecnoded_df.drop('price', axis = 1)
# Targer variable - المتغير الذي نريد توقعه وهو السعر
y = ecnoded_df['price']
والسبب وراء هذا الفصل هو أننا نريد استخدام الأعمدة المستقلة (مثل نوع الوقود، واسم الشركة) لتوقع قيمة العمود المستهدف (عمود السعر).
الآن الفصل الثاني هو فصل (التدريب/الاختبار) والذي نقوم به في هذا الفصل هو أخذ نسبة من البيانات وفصلها عن طريق عدم وضعها في مرحلة تدريب النموذج. والسبب في قيام ذلك هو أننا نريد اختبار دقة عمل النموذج في الحياة الواقعية وإذا اختبرنا النموذج على نفس البيانات التي دربناه عليها سوف يحرز نتائج عالية بسهولة. ومن أجل ذلك نحن نبقي جزء من البيانات من غير تدريب لإجراء الاختبارات عليه بحيادية.
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 متغيرات ووصفهم كالتالي
- X_train: هي الصفوف (السيارات) التي سوف نستخدمها في تدريب النموذج.
- y_train: هي أسعار الصفوف التي سوف ندرب النموذج عليها (أسعار صفوف التدريب).
- X_test: هي الصفوف التي نريد توقعها من أجل اختبار دقة النموذج
- y_test: هي أسعار الصفوف الحقيقة والتي سوف نقارن توقعات النموذج بها
الآن سوف نقوم بخطوة أخيرة قبل التدريب: ألا وهي توحيد المقاييس 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]
highwaympg -0.697599 citympg -0.685751 drivewheel_fwd -0.601950 fuelsystem_2bbl -0.501374 enginetype_ohc -0.344270 Name: price, dtype: float64
نصيحة فهم للتعلم
إن كنت متمرس في تعلم الآلة سوف تجد أن هذا الموضوع يساعدك في مراجعة أساسيات تعلم الآلة. وفي حالة كنت جديدًا في هذا المجال، ستجد أن هناك الكثير لتعلمه وربما الآن تشعر بالحيرة والقلق بسبب كثرة الخطوات. ونصيحتنا هي ألا تقلق أبدًا، فكلنا بدأنا من الصفر وتعلم الذكاء الاصطناعي ممتع ولكنه يستغرق بعض الوقت. كلما تدربت على مشاريع تعلم آلة، كلما أصبحت خبرتك ومهارتك أحسن. ونحن في فهم سنسعى لتقديم مشاريع متنوعة تستطيع التدرب عليها. وأيضا تستطيع زيارة موقع kaggle، وهو موقع متخصص لعلماء البيانات تستطيع من خلاله الوصول إلى المئات من مشاريع تعلم الآلة والذكاء الاصطناعي والتعلم من خبرات الآخرين. فإذا انتهيت من هذا المشروع، تستطيع زيارة موقع كاجل والتدرب على المشاريع المتنوعة في الانحدار الخطي بناء على الحلول المزودة هناك.
ماذا تعلمنا؟
- تعلم الآلة هو جزء من الذكاء الاصطناعي ولها تطبيقات كثيرة ومتعددة
- تعلم الآلة هو استخدام البيانات كمدخلات من أجل إيجاد مخرجات عن طريق الرياضيات
- مخرجات تعلم الآلة كثيرة، وهي تعتمد على نوع التطبيق مثل توقع المستقبل أو تصنيف نوع العميل
- من تطبيقات تعلم الآلة هو توقع الأسعار، وحين توقع الأسعار نستطيع استخدام نماذج الانحدار الخطي
- إن صناعة النماذج الجيدة تعتمد بشكل مباشر على معالجة البيانات وهي الخطوة التي تأخذ معظم الوقت
- معالجة البيانات تتضمن التحقق من سلامة البيانات من أية بيانات محذوفة، أو خاطئة، أو متكررة
- معالجة البيانات تتضمن أيضا ترميز الأعمدة التي تحتوي على أعمدة مكتوبة بالحروف وتحويلها إلى أرقام
- معالجة البيانات تتضمن أيضا توحيد القياسات بين الأعمدة من أجل المساواة بين أثر الأعمدة
شكرا جزيلا – شرح جميل
الشرح جميل وممتاز وجزاك الله خير
لكن في تحديد صنف الجنس بالشرح أشرت الى 1 أنثى وأيضاً 1 ذكر