في المشهد الحديث للبيانات، أثبتت لغة بايثون مكانتها كلغة مشتركة لعلوم البيانات. في قلب هذا النظام البيئي تكمن مكتبتان قويتان: NumPy و Pandas. رغم استخدامهما أحياناً بالتبادل من قبل المبتدئين، إلا أنهما يخدمان أغراضاً متميزة ومتكاملة. يوفر NumPy العمليات الأساسية منخفضة المستوى للمصفوفات، بينما يبني Pandas عليها ليوفر هياكل بيانات عالية المستوى وبديهية للتعامل مع البيانات المهيكلة. يغوص هذا المنشور بعمق في كيفية الاستفادة الفعالة من هذه الأدوات للمطورين من المستوى المتوسط إلى المتقدم.
فهم البنية الأساسية
قبل كتابة سطر واحد من كود التحليل، من الضروري فهم ما يحدث خلف الكواليس. يركز NumPy (بايثون العددية) بشكل أساسي على إجراء حسابات سريعة وفعالة على المصفوفات متعددة الأبعاد والمصفوفات الرياضية الكبيرة. وهو يقدم كائن ndarray، الذي يخزن عناصر من نفس النوع في كتلة متصلة من الذاكرة، مما يتيح عمليات متجهة (Vectorized operations) أسرع بكثير من الحلقات البرمجية القياسية في بايثون.
من ناحية أخرى، صُمم Pandas للتعامل مع البيانات وتنظيفها. وهو يقدم بنيتين بيانات رئيسيتين: Series (بعد واحد) و DataFrame (بعدين). يعد DataFrame هيكلاً يشبه جداول البيانات، حيث يمكن أن تحتوي الأعمدة على أنواع بيانات مختلفة. تم بناء Pandas فوق NumPy، مما يعني أنه تحت السطح، العديد من عمليات Pandas هي مجرد استدعاءات لـ NumPy محسّنة. فهم هذه العلاقة يسمح للمطورين بكتابة كود أكثر كفاءة من خلال معرفة متى يستخدمون السرعة الخام لـ NumPy مقابل راحة استخدام Pandas.
تقنيات أساسية للتعامل مع البيانات
بالنسبة للمطورين من المستوى المتوسط، تكمن القيمة ليس فقط في تحميل البيانات، بل في تحويلها بكفاءة. تشمل المهام الشائعة التصفية، والتجميع، والتعامل مع البيانات المفقودة. دعونا نلقي نظرة على مثال عملي يتضمن مجموعة بيانات مبيعات محاكاة.
أولاً، نقوم بتوليد مجموعة بيانات باستخدام NumPy للشدة العددية، ثم نهيكلها باستخدام Pandas:
import pandas as pd
import numpy as np
# محاكاة مجموعة بيانات بأرقام مبيعات عشوائية
np.random.seed(42)
data = {
'product': ['A', 'B', 'C', 'A', 'B', 'C'],
'region': ['North', 'South', 'North', 'South', 'North', 'South'],
'sales': np.random.randint(100, 1000, size=6),
'date': pd.date_range('2023-01-01', periods=6, freq='D')
}
df = pd.DataFrame(data)
print("Original DataFrame:")
print(df)
بمجرد تحميل البيانات، تصبح عملية التصفية بسيطة. للعثور على جميع المبيعات في منطقة 'الشمال' التي تتجاوز 500 وحدة، يمكننا استخدام الفهرسة المنطقية (Boolean indexing):
# تصفية البيانات
filtered_df = df[(df['region'] == 'North') & (df['sales'] > 500)]
print("\nFiltered Data:")
print(filtered_df)
تظهر قوة Pandas حقاً في عمليات التجميع. لنفترض أننا نريد حساب متوسط المبيعات لكل منتج. باستخدام طريقة groupby، يمكننا تحقيق ذلك في سطر واحد:
# التجميع
summary = df.groupby('product')['sales'].mean()
print("\nAverage Sales per Product:")
print(summary)
تحسين الأداء باستخدام العمليات المتجهة
من الأخطاء الشائعة للمطورين الذين ينتقلون من بايثون القياسية هو استخدام الحلقات الصريحة لتحويل البيانات. هذا النهج بطيء ولا يتبع أفضل ممارسات بايثون. بدلاً من ذلك، استغل دائماً العمليات المتجهة المقدمة من كل من NumPy و Pandas.
فكر في سيناريو تحتاج فيه إلى تطبيق دالة رياضية معقدة على عمود. تجنب استخدام apply() مع دالة بايثون مخصصة إلا إذا كان ذلك ضرورياً للغاية، لأنها تعود إلى استخدام حلقة بايثون. بدلاً من ذلك، استخدم دوال NumPy المدمجة التي تم تنفيذها بلغة C:
# غير كفء: استخدام apply مع دالة لامدا
# df['sales_normalized'] = df['sales'].apply(lambda x: np.log1p(x))
# كفء: عملية متجهة من NumPy
df['sales_normalized'] = np.log1p(df['sales'])
من خلال دفع الحساب إلى مستوى مصفوفات C، يمكنك رؤية تحسنات في وقت التنفيذ بمقدار رتبة كاملة، خاصة مع مجموعات البيانات التي تحتوي على ملايين الصفوف.
التعامل مع البيانات المفقودة وتحويل الأنواع
بيانات العالم الحقيقي نادراً ما تكون نظيفة. يوفر Pandas طرقاً قوية للتعامل مع قيم NaN (ليس رقماً). يجب أن يكون المطورون على دراية بـ dropna() لإزالة السجلات غير المكتملة و fillna() لتعويض القيم المفقودة باستخدام المتوسط، أو الوسيط، أو طرق التعبئة للأمام.
علاوة على ذلك، يعد ضمان صحة أنواع البيانات أمراً حاسماً للكفاءة في استخدام الذاكرة. يسمح لك استخدام df.info() بفحص استهلاك الذاكرة. يمكن أن يؤدي تحويل السلاسل النصية الفئوية إلى نوع البيانات category أو استخدام الأعداد الصحيحة القابلة للفقدان Int64 بدلاً من الكسور العشرية القياسية إلى تقليل البصمة الذاكرة لمصفوفات البيانات (DataFrames) بشكل كبير.
الخاتمة
إتقان Pandas و NumPy هو رحلة من تحميل البيانات الأساسي إلى خطوط الأنابيب المعقدة والمُحسّنة للبيانات. من خلال فهم البنية الأساسية لإسقاط مصفوفات NumPy ومحاذاة الفهرس في Pandas، يمكن للمطورين كتابة كود ليس فقط قابلاً للقراءة، بل أيضاً عالي الأداء. بينما تستمر في رحلتك في علوم البيانات، قم دائماً بمراقبة أداء الكود الخاص بك، وفضل العمليات المتجهة على الحلقات، واستغل النظام البيئي الغني من الامتدادات التي تبني على هذه المكتبات الأساسية.