بايثون لعلوم البيانات: الخطوات التسع الرئيسية للانتقال من الصفر إلى التشغيل
بايثون لعلوم البيانات: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات ملموسة، مقتطفات من دورة مكونة من 36 درسًا.
يمكن للجميع تعلم Python Data Science — بشرط اتباع الخطوات بالترتيب الصحيح. لقد لخصنا دورة كاملة من 36 درسًا في مسار واضح، مع أكثر مقتطفات الكود فائدة.
- مقدمة وتثبيت
- NumPy الأساسي
- Pandas Series و DataFrames
- قراءة وكتابة البيانات
- تنظيف البيانات
التكرارات والتناقضات
الأهداف التعليمية
لماذا التكرارات خطيرة
التكرار هو نفس الواقع محسوب مرتين. النتائج: إيرادات مبالغ فيها، متوسطات متحيزة، نماذج مفرطة التدريب. قد يأتي التكرار من استيراد مكرر، أو ربط سيئ، أو نموذج تم إرساله مرتين…
اكتشاف التكرارات
import pandas as pd df = pd.DataFrame({ "id": [1, 2, 3, 2, 4, 1], "nom": ["Alice", "Bob", "Chloe", "Bob", "David", "Alice"], "ville": ["Paris", "Lyon", "Nice", "Lyon", "Lille", "Paris"] }) # قناع منطقي: True إذا كان الصف مكررًا df.duplicated() # كم عدد التكرارات الإجمالي؟ df.duplicated().sum() # عرض التكرارات فقط df[df.duplicated()] # التكرارات بناءً على أعمدة معينة فقط df.duplicated(subset=["id"]) df.duplicated(subset=["nom", "ville"])
duplicated() يضع علامة True بدءًا من الثانية مرة. يُعتبر النسخة الأولى هي الأصلية.حذف التكرارات
# الاحتفاظ بالظهور الأول (افتراضي) df.drop_duplicates() # الاحتفاظ بالظهور الأخير df.drop_duplicates(keep="last") # حذف جميع التكرارات df.drop_duplicates(keep=False) # على أعمدة معينة فقط (مفيد إذا كان أحد الأعمدة طابعًا زمنيًا) df.drop_duplicates(subset=["id"]) # Inplace لتعديل DataFrame مباشرة df.drop_duplicates(inplace=True)
keep — "first" للاحتفاظ بالسجل الأقدم، "last" للأحدث (غالبًا الخيار الجيد إذا تم تحديث البيانات)، False لحذف الكل والتحقيق.فخ التكرارات التقريبية
« Paris » و « paris » مختلفان بالنسبة لـ Pandas، حتى لو كانا نفس المدينة بالنسبة لك. قبل البحث عن التكرارات، طبّع.
df = pd.DataFrame({
"email": ["Alice@MAIL.com", " alice@mail.com ", "bob@mail.com"],
"ville": ["Paris", "PARIS", "Lyon"]
})
# تطبيع الإيميلات (مسافات + أحرف صغيرة)
df["email"] = df["email"].str.strip().str.lower()
df["ville"] = df["ville"].str.strip().str.title()
# الآن يمكن اكتشاف التكرارات الحقيقية
df.duplicated(subset=["email"])
print(df)صندوق أدوات .str
يمنحك الوصول .str جميع طرق سلاسل Python، موجهة:
s = pd.Series([" Alice DUPONT ", "bob martin", "CHLOE.LEROY"]) s.str.strip() # إزالة المسافات s.str.lower() # أحرف صغيرة s.str.upper() # أحرف كبيرة s.str.title() # كل كلمة تبدأ بحرف كبير s.str.replace(".", " ") # استبدال s.str.contains("alice", case=False) # تصفية s.str.startswith("A") s.str.len() # عدد الأحرف s.str.split(" ", expand=True) # فصل إلى أعمدة
unicodedata أو مكتبة unidecode : df["ville"].apply(unidecode).التناقضات الفئوية
غالبًا ما تُدخل نفس الفئة بطرق مختلفة: « H »، « Homme »، « M »، « Masculin »… يراها Pandas كـ 4 فئات مختلفة.
df = pd.DataFrame({
"sexe": ["H", "Homme", "M", "Masculin", "F", "Femme", "f"]
})
# قبل: عرض القيم الفريدة
print(df["sexe"].value_counts())
# الاستراتيجية: قاموس تعيين
mapping = {
"H": "Homme", "M": "Homme", "Masculin": "Homme",
"F": "Femme", "f": "Femme", "Femme": "Femme"
}
df["sexe"] = df["sexe"].map(mapping)
print(df["sexe"].value_counts())df["col"].value_counts(). ستظهر التناقضات فورًا.مشروع مصغر: تنظيف قاعدة موظفين
import pandas as pd df = pd.DataFrame({ "id": [1, 2, 3, 2, 4, 5], "nom": ["Alice", " Bob ", "Chloe", "BOB", "David", "emma"], "poste": ["Dev", "DEV", "PM", "dev", "Pm", "Designer"], "ville": ["Paris", "paris", "Lyon", "PARIS", "Lille", "Lyon"] }) # 1. تطبيع السلاسل for col in ["nom", "poste", "ville"]: df[col] = df[col].str.strip().str.title() # 2. اكتشاف التكرارات على id print("التكرارات :", df.duplicated(subset=["id"]).sum()) # 3. الاحتفاظ بالسجل الأخير (الأحدث) df = df.drop_duplicates(subset=["id"], keep="last") # 4. التحقق print(df) print(df["poste"].value_counts())
القيم المفقودة (NaN)
الأهداف التعليمية
ما هو NaN؟
NaN = « Not a Number ». هذه هي الطريقة التي يمثل بها Pandas (الموروث من NumPy) قيمة مفقودة في عمود رقمي. للتواريخ، يكون NaT؛ وللكائنات العامة، None. يعالجها Pandas الثلاثة بشكل موحد عبر isnull().
import pandas as pd import numpy as np df = pd.DataFrame({ "nom": ["Alice", "Bob", None, "David"], "age": [30, np.nan, 25, 35], "date": pd.to_datetime(["2025-01-01", None, "2025-01-03", "2025-01-04"]) }) print(df)
NaN != NaN في Python النقي (وهذا مقصود). لذا x == np.nan يكون خطأ دائمًا. استخدم دائمًا isnull() أو isna() للاختبار.اكتشاف القيم المفقودة
# قناع منطقي خلية بخلية df.isnull() # True إذا كان NaN df.notna() # العكس # العد حسب العمود df.isnull().sum() # نسبة NaN لكل عمود (df.isnull().sum() / len(df) * 100).round(2) # الإجمالي في كل DataFrame df.isnull().sum().sum() # الصفوف التي تحتوي على NaN واحد على الأقل df[df.isnull().any(axis=1)]
df.isnull().sum(). هذا في ثانيتين لوحة تحكم جودة بياناتك.الاستراتيجية 1 — الحذف (dropna)
عندما تكون NaN نادرة أو يتطلب التحليل بيانات كاملة:
# حذف أي صف يحتوي على NaN واحد على الأقل df.dropna() # حذف فقط إذا كانت كل القيم NaN df.dropna(how="all") # حذف إذا كان NaN في عمود محدد df.dropna(subset=["age"]) # الاحتفاظ بصف إذا كان لديه 3 قيم غير NaN على الأقل df.dropna(thresh=3) # حذف عمود كامل غير مكتمل جدًا df.dropna(axis=1, thresh=100) # الأعمدة < 100 قيمة محذوفة
df.dropna().shape vs df.shape.الاستراتيجية 2 — الملء (fillna)
بقيمة ثابتة
df["age"].fillna(0) df["ville"].fillna("Inconnu") # على كل DataFrame بقاموس لكل عمود df.fillna({"age": 0, "ville": "Inconnu", "salaire": 2000})
بإحصائية من العمود
df["age"].fillna(df["age"].mean()) # المتوسط df["age"].fillna(df["age"].median()) # الوسيط (قوي) df["ville"].fillna(df["ville"].mode()[0]) # القيمة الأكثر تكرارًا
بالانتشار (مفيد للسلاسل الزمنية)
# الملء بالقيمة السابقة (forward fill) df["prix"].ffill() # بالقيمة التالية (backward fill) df["prix"].bfill() # تحديد عدد الملءات المتتالية df["prix"].ffill(limit=3)
أنواع البيانات والتحويل
الأهداف التعليمية
dtypes، والتحويل إلى رقم/تاريخ/فئة، واستخدام errors="coerce" للقيم غير النظيفة، وتقليل بصمة الذاكرة لـ DataFrame بتحويل object → category.لماذا يهم النوع
الـ « 42 » المخزن كنص (object) لا يمكن جمعه، ولا مقارنته رقميًا. التاريخ المخزن كنص لا يسمح بـ .dt.year. نوع سيء = أخطاء صامتة أو فقدان وظائف.
import pandas as pd df = pd.DataFrame({ "prix": ["12.50", "8.99", "15.00"], "date": ["2025-01-01", "2025-02-15", "2025-03-10"] }) print(df.dtypes) # prix object <-- نص! # date object <-- نص! df["prix"].sum() # يربط « 12.508.9915.00 » !
object = « أي شيء »، غالبًا نص. إذا رأيت object على عمود من المفترض أن يكون رقميًا، فهناك مشكلة يجب حلها قبل أي تحليل.أنواع Pandas باختصار
| Dtype | الاستخدام | مثال |
|---|---|---|
int64 | عدد صحيح | الأعمار، الكميات |
float64 | عدد حقيقي | الأسعار، درجات الحرارة |
bool | صح/خطأ | نشط، مدفوع |
object | عام (غالبًا str) | الأسماء، الإيميلات |
datetime64[ns] | تاريخ/وقت | الطلب، الميلاد |
timedelta64 | مدة | الفرق بين تاريخين |
category | فئات مكررة | الجنس، المدينة، الحالة |
التحويل بـ astype
# تحويل بسيط، يفشل إذا لم تناسب قيمة df["age"] = df["age"].astype(int) df["prix"] = df["prix"].astype(float) df["actif"] = df["actif"].astype(bool) df["sexe"] = df["sexe"].astype("category") # على عدة أعمدة في وقت واحد df = df.astype({"age": int, "prix": float, "ville": "category"})
astype(int) يتعطل فورًا إذا لم تتحول قيمة (مثل: "12 EUR"). للتعامل مع هذه الحالات، استخدم pd.to_numeric.pd.to_numeric — المتسامح
s = pd.Series(["12.5", "8.99", "oops", "15"]) # الوضع الصارم: يتعطل إذا كانت قيمة غير رقمية pd.to_numeric(s) # ValueError # الوضع المتسامح: القيم غير النظيفة -> NaN pd.to_numeric(s, errors="coerce") # 0 12.50 # 1 8.99 # 2 NaN <-- "oops" يصبح NaN # 3 15.00 # اختيار النوع الفرعي لتوفير الذاكرة pd.to_numeric(s, errors="coerce", downcast="float") pd.to_numeric(s, errors="coerce", downcast="integer")
errors="coerce" → عد NaN الناتجة → قرر ما تفعل (تعويض، حذف، إبلاغ).pd.to_datetime — كل التواريخ
# يتعرف على معظم التنسيقات تلقائيًا pd.to_datetime(["2025-01-15", "15/01/2025", "Jan 15, 2025"]) # تنسيق صريح (أسرع وأأمن) pd.to_datetime(df["date"], format="%%d/%%m/%%Y") # متسامح مع القيم غير النظيفة pd.to_datetime(df["date"], errors="coerce") # بمجرد أن يصبح datetime، يمكن الوصول إلى المكونات df["date"] = pd.to_datetime(df["date"]) df["annee"] = df["date"].dt.year df["mois"] = df["date"].dt.month df["jour_sem"] = df["date"].dt.day_name()
format= قد يضاعف السرعة 100 مرة. لم يعد Pandas بحاجة للتخمين.النوع category : سحر الذاكرة
لعمود « ville » مكرر مليون مرة، تخزين كل سلسلة يهدر المساحة. category يخزن كل قيمة فريدة مرة واحدة، ويشير إلى فهرس عدد صحيح.
import pandas as pd df = pd.DataFrame({ "ville": ["Paris", "Lyon", "Paris"] * 1_000_000 }) print(df.memory_usage(deep=True).sum() / 1e6, "Mo") # حوالي 200 Mo df["ville"] = df["ville"].astype("category") print(df.memory_usage(deep=True).sum() / 1e6, "Mo") # حوالي 8 Mo -- توفير x25 !
category؟ — عندما يكون عدد القيم الفريدة صغيرًا مقارنة بعدد الصفوف الإجمالي (عادة < 5 %%). وإلا، فائدة قليلة.مشروع مصغر: تنظيف تصدير محاسبي
import pandas as pd df = pd.DataFrame({ "montant": ["125,50", "99,00", "N/D", "42,75"], "date": ["01/03/2025", "02/03/2025", "oops", "04/03/2025"], "categorie": ["Achat", "Vente", "Achat", "Vente"], "paye": ["Oui", "Non", "Oui", "Oui"] }) # 1. المبلغ: فاصلة -> نقطة، ثم رقمي df["montant"] = df["montant"].str.replace(","span>, ".") df["montant"] = pd.to_numeric(df["montant"], errors="coerce") # 2. التاريخ بتنسيق يوم/شهر/سنة df["date"] = pd.to_datetime(df["date"], format="%%d/%%m/%%Y", errors="coerce") # 3. الفئة -> نوع category df["categorie"] = df["categorie"].astype("category") # 4. Oui/Non -> bool df["paye"] = df["paye"].map({"Oui": True, "Non": False}) print(df.dtypes) print(df)
يغطي هذا المقال المقتطفات الأكثر فائدة — الدورة الكاملة Python Data Science (11 فصول، 36 درسًا، تمارين مصححة ومشروع نهائي) تأخذك إلى النهاية.
./acceder-au-cours-complet cours gratuit : Maîtriser Claude Codeالأسئلة الشائعة
كم من الوقت لتعلم Python Data Science؟
هل هناك متطلبات مسبقة؟
من أين أبدأ عمليًا؟
📬 Tu veux recevoir ce type de guide chaque semaine ? Abonne-toi gratuitement — code réel, zéro blabla.