البيانات في تعلّم الآلة: الميزات والتسميات والتنظيف
في الدرس الأول عرفت أن البيانات هي وقود تعلّم الآلة. وفي الواقع، علماء البيانات يقضون أغلب وقتهم، أحياناً أكثر من نصفه، في تجهيز البيانات وليس في بناء النماذج! لأن أذكى خوارزمية في العالم ستعطيك نتائج سيئة إذا تدربت على بيانات سيئة. في هذا الدرس ستتعلم كيف تفهم البيانات وتجهزها، باستخدام مكتبة pandas الشهيرة في Python.
المصطلحات: الميزات والتسميات
Section titled “المصطلحات: الميزات والتسميات”لنفترض أننا نريد نموذجاً يتوقع: هل سينجح الطالب في الامتحان؟ نجمع بيانات طلاب سابقين:
| ساعات المذاكرة | ساعات النوم | المدينة | نجح؟ |
|---|---|---|---|
| 1 | 5 | القاهرة | لا |
| 2 | 6 | طنطا | لا |
| 3 | 8 | القاهرة | نعم |
| 4 | 7 | أسيوط | نعم |
- الميزات (Features): المعلومات التي يعتمد عليها النموذج في التوقع: ساعات المذاكرة، والنوم، والمدينة. تُسمى عادة
X. - التسمية (Label) أو الهدف (Target): الإجابة التي نريد توقعها: نجح أم لا. تُسمى عادة
y. - العينة (Sample): صف واحد، أي طالب واحد.
تخيّل طبيباً يشخّص مرضاً: الأعراض والتحاليل هي الميزات، والتشخيص هو التسمية. والطبيب تعلّم من آلاف الحالات السابقة التي عُرف تشخيصها.
تحميل البيانات بـ pandas
Section titled “تحميل البيانات بـ pandas”مكتبة 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 passed0 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').
استكشاف البيانات
Section titled “استكشاف البيانات”قبل أي شيء، افهم بياناتك:
print(df.shape)print(df['hours'].describe().round(2))(8, 4)count 7.00mean 3.29std 1.80min 1.0025% 2.0050% 3.0075% 4.50max 6.00Name: hours, dtype: float64shape: 8 صفوف و 4 أعمدة.describe(): ملخص إحصائي للعمود: العدد، والمتوسط (mean)، والانحراف المعياري (std) أي مدى تشتت القيم، وأقل وأكبر قيمة، والوسيط (50%).
لاحظ أن count تساوي 7 وليس 8! فهناك قيمة ناقصة.
القيم الناقصة
Section titled “القيم الناقصة”print(df.isna().sum())hours 1sleep 0city 0passed 0dtype: int64isna().sum() تعدّ القيم الناقصة في كل عمود. وأغلب النماذج لا تقبل القيم الناقصة، فلدينا خياران:
- الحذف:
df.dropna()تحذف الصفوف الناقصة. مناسب إذا كانت قليلة. - التعويض: نملأها بقيمة معقولة، مثل المتوسط:
df['hours'] = df['hours'].fillna(df['hours'].mean())أصبحت ساعات الطالب الأخير 3.29، أي متوسط الباقين.
تحويل النصوص إلى أرقام
Section titled “تحويل النصوص إلى أرقام”النماذج تفهم الأرقام فقط. فكيف نتعامل مع «نعم» و«لا» و«القاهرة»؟
قيمتان فقط: نحوّلهما إلى 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 01 0 0 12 0 1 0الطالب الأول من القاهرة، فعمود القاهرة عنده 1 والباقي 0.
فصل الميزات عن التسمية
Section titled “فصل الميزات عن التسمية”X = df[['hours', 'sleep']]y = df['passed_num']print(X.shape, y.shape)(8, 2) (8,)X جدول بعمودين (الميزات)، و y عمود واحد (التسمية).
التدريب والاختبار
Section titled “التدريب والاختبار”هذه أهم فكرة في الدرس: لا تختبر النموذج على نفس البيانات التي تدرب عليها! تخيّل طالباً حفظ إجابات أسئلة الكتاب حرفياً، ثم جاء الامتحان بنفس الأسئلة: سيحصل على الدرجة النهائية دون أن يفهم شيئاً. الامتحان الحقيقي يكون بأسئلة جديدة.
لذلك نقسم البيانات:
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، التي ستستخدمها كثيراً في الدرسين القادمين.)
جرّب بنفسك
Section titled “جرّب بنفسك”ثبّت pandas، ثم:
- أنشئ
DataFrameلـ 8 منتجات فيه: السعر، والتصنيف (نص)، والتقييم، مع ترك قيمة تقييم ناقصة. - اعرض الشكل بـ
shapeوملخص السعر بـdescribe(). - اكتشف القيم الناقصة، وعوّضها بمتوسط العمود.
- حوّل التصنيف بالترميز الأحادي.
- قسّم البيانات 75% للتدريب و 25% للاختبار.
أخطاء شائعة
Section titled “أخطاء شائعة”- تجاهل استكشاف البيانات: بناء نموذج قبل فهم البيانات يخفي مشاكل مثل القيم الناقصة والأخطاء.
- ترقيم الفئات بأرقام متتالية: يخلق ترتيباً وهمياً. استخدم الترميز الأحادي للفئات غير المرتبة.
- الاختبار على بيانات التدريب: يعطي نتيجة مبالغاً فيها لا تعكس الأداء الحقيقي.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
في نموذج يتوقع سعر الشقة من مساحتها وعدد غرفها، ما هي التسمية (Label)؟
التسمية هي ما نريد توقعه، وهو السعر. أما المساحة وعدد الغرف فميزات.
سؤال
لماذا نقسم البيانات إلى تدريب واختبار؟
الاختبار على بيانات لم يرها النموذج يكشف هل فهم الأنماط فعلاً أم حفظ الأمثلة فقط.
الخلاصة
Section titled “الخلاصة”- الميزات
Xهي المعلومات المدخلة، والتسميةyهي ما نريد توقعه. - pandas تحمّل البيانات وتستكشفها:
headوshapeوdescribe. - القيم الناقصة تُكتشف بـ
isna()، وتُحذف بـdropnaأو تُعوَّض بـfillna. - النصوص تتحول لأرقام:
mapللقيمتين، والترميز الأحاديget_dummiesللفئات. train_test_splitيفصل بيانات التدريب عن الاختبار، والبيانات الجيدة أساس النموذج الجيد.