تخطَّ إلى المحتوى

البيانات في تعلّم الآلة: الميزات والتسميات والتنظيف

الدرس 2 من 8 · تعلّم الآلة

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

المصطلحات: الميزات والتسميات

Section titled “المصطلحات: الميزات والتسميات”

لنفترض أننا نريد نموذجاً يتوقع: هل سينجح الطالب في الامتحان؟ نجمع بيانات طلاب سابقين:

ساعات المذاكرة ساعات النوم المدينة نجح؟
1 5 القاهرة لا
2 6 طنطا لا
3 8 القاهرة نعم
4 7 أسيوط نعم
  • الميزات (Features): المعلومات التي يعتمد عليها النموذج في التوقع: ساعات المذاكرة، والنوم، والمدينة. تُسمى عادة X.
  • التسمية (Label) أو الهدف (Target): الإجابة التي نريد توقعها: نجح أم لا. تُسمى عادة y.
  • العينة (Sample): صف واحد، أي طالب واحد.

تخيّل طبيباً يشخّص مرضاً: الأعراض والتحاليل هي الميزات، والتشخيص هو التسمية. والطبيب تعلّم من آلاف الحالات السابقة التي عُرف تشخيصها.

مكتبة pandas هي الأداة الأساسية للتعامل مع البيانات الجدولية في Python. تثبّتها بالأمر pip install pandas:

import pandas as pd
data = {
'hours': [1, 2, 3, 4, 5, 6, 2, None],
'sleep': [5, 6, 8, 7, 8, 7, 4, 8],
'city': ['القاهرة', 'طنطا', 'القاهرة', 'أسيوط', 'طنطا', 'القاهرة', 'أسيوط', 'طنطا'],
'passed': ['لا', 'لا', 'نعم', 'نعم', 'نعم', 'نعم', 'لا', 'نعم'],
}
df = pd.DataFrame(data)
print(df.head(3))
الناتج
hours sleep city passed
0 1.0 5 القاهرة لا
1 2.0 6 طنطا لا
2 3.0 8 القاهرة نعم
  • DataFrame: جدول pandas، مثل ورقة Excel داخل Python. و df اختصار شائع لاسمه.
  • head(3): أول 3 صفوف، للاطلاع السريع على البيانات.
  • None: قيمة ناقصة: طالب لم نعرف عدد ساعات مذاكرته.

وفي الواقع، البيانات تأتي غالباً من ملف، فتقرؤها بسطر واحد: df = pd.read_csv('students.csv').

قبل أي شيء، افهم بياناتك:

print(df.shape)
print(df['hours'].describe().round(2))
الناتج
(8, 4)
count 7.00
mean 3.29
std 1.80
min 1.00
25% 2.00
50% 3.00
75% 4.50
max 6.00
Name: hours, dtype: float64
  • shape: 8 صفوف و 4 أعمدة.
  • describe(): ملخص إحصائي للعمود: العدد، والمتوسط (mean)، والانحراف المعياري (std) أي مدى تشتت القيم، وأقل وأكبر قيمة، والوسيط (50%).

لاحظ أن count تساوي 7 وليس 8! فهناك قيمة ناقصة.

print(df.isna().sum())
الناتج
hours 1
sleep 0
city 0
passed 0
dtype: int64

isna().sum() تعدّ القيم الناقصة في كل عمود. وأغلب النماذج لا تقبل القيم الناقصة، فلدينا خياران:

  1. الحذف: df.dropna() تحذف الصفوف الناقصة. مناسب إذا كانت قليلة.
  2. التعويض: نملأها بقيمة معقولة، مثل المتوسط:
df['hours'] = df['hours'].fillna(df['hours'].mean())

أصبحت ساعات الطالب الأخير 3.29، أي متوسط الباقين.

النماذج تفهم الأرقام فقط. فكيف نتعامل مع «نعم» و«لا» و«القاهرة»؟

قيمتان فقط: نحوّلهما إلى 0 و 1:

df['passed_num'] = df['passed'].map({'لا': 0, 'نعم': 1})

عدة فئات بلا ترتيب مثل المدن: لا يصح أن نقول القاهرة = 1 وطنطا = 2 وأسيوط = 3، لأن النموذج سيظن أن أسيوط «أكبر» من القاهرة! الحل: الترميز الأحادي (One-Hot Encoding)، عمود لكل مدينة:

print(pd.get_dummies(df['city'], dtype=int).head(3))
الناتج
أسيوط القاهرة طنطا
0 0 1 0
1 0 0 1
2 0 1 0

الطالب الأول من القاهرة، فعمود القاهرة عنده 1 والباقي 0.

X = df[['hours', 'sleep']]
y = df['passed_num']
print(X.shape, y.shape)
الناتج
(8, 2) (8,)

X جدول بعمودين (الميزات)، و y عمود واحد (التسمية).

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

لذلك نقسم البيانات:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
print(len(X_train), len(X_test))
الناتج
6 2
  • بيانات التدريب (75% هنا): يتعلم منها النموذج.
  • بيانات الاختبار (25%): يُقيَّم عليها، ولا يراها أثناء التدريب أبداً.
  • random_state=42: يجعل التقسيم العشوائي ثابتاً في كل تشغيل، فتحصل على نفس النتيجة.

(الدالة من مكتبة scikit-learn، التي ستستخدمها كثيراً في الدرسين القادمين.)

ثبّت pandas، ثم:

  1. أنشئ DataFrame لـ 8 منتجات فيه: السعر، والتصنيف (نص)، والتقييم، مع ترك قيمة تقييم ناقصة.
  2. اعرض الشكل بـ shape وملخص السعر بـ describe().
  3. اكتشف القيم الناقصة، وعوّضها بمتوسط العمود.
  4. حوّل التصنيف بالترميز الأحادي.
  5. قسّم البيانات 75% للتدريب و 25% للاختبار.
  • تجاهل استكشاف البيانات: بناء نموذج قبل فهم البيانات يخفي مشاكل مثل القيم الناقصة والأخطاء.
  • ترقيم الفئات بأرقام متتالية: يخلق ترتيباً وهمياً. استخدم الترميز الأحادي للفئات غير المرتبة.
  • الاختبار على بيانات التدريب: يعطي نتيجة مبالغاً فيها لا تعكس الأداء الحقيقي.

سؤال

في نموذج يتوقع سعر الشقة من مساحتها وعدد غرفها، ما هي التسمية (Label)؟

سؤال

لماذا نقسم البيانات إلى تدريب واختبار؟

  • الميزات X هي المعلومات المدخلة، والتسمية y هي ما نريد توقعه.
  • pandas تحمّل البيانات وتستكشفها: head و shape و describe.
  • القيم الناقصة تُكتشف بـ isna()، وتُحذف بـ dropna أو تُعوَّض بـ fillna.
  • النصوص تتحول لأرقام: map للقيمتين، والترميز الأحادي get_dummies للفئات.
  • train_test_split يفصل بيانات التدريب عن الاختبار، والبيانات الجيدة أساس النموذج الجيد.