الوحدة 4 — NumPy: المصفوفات والبثّ والحساب المتّجه
NumPy أساس المنظومة كلّها: pandas وscikit-learn وحتى موتّرات PyTorch تستعير مفاهيمه. كائنه الوحيد — المصفوفة المتجانسة ndarray — ومبدؤه الوحيد — وجِّه بدل أن تكرّر — يكفيان لتسريع الحسابات من 10 إلى 100 مرّة.
المصفوفة ndarray: كتلة متجانسة منمّطة
بخلاف قائمة بايثون (مراجع إلى كائنات مبعثرة)، مصفوفة NumPy كتلة ذاكرة متّصلة من عناصر من النوع نفسه. هذا التجانس هو ما يشتري السرعة: تنزل العمليات إلى C المُجمَّعة بدل تفسير كلّ عنصر.
import numpy as np
a = np.array([1.5, 2.0, 3.5])
m = np.zeros((3, 4)) # مصفوفة 3×4 من الأصفار
x = np.arange(0, 10, 0.5) # 0, 0.5, 1.0, …, 9.5
g = np.random.default_rng(42).normal(size=(1000, 3)) # عشوائية قابلة للتكرار
a.shape # (3,) — الأبعاد
a.dtype # float64 — نوع العناصر الموحّد
m.ndim # 2 — عدد المحاور
shape وdtype هما أول ما يُفحَص أمام أيّ سلوك غريب: نصف أخطاء NumPy أشكالٌ غير متوقّعة.
التوجيه: العملية تنطبق على المصفوفة كلّها
# أسلوب بايثون الخالص — بطيء
results = []
for price in price_list:
results.append(price * 1.15)
# أسلوب NumPy — أسرع 10 إلى 100 مرّة، وأوضح
results = prices * 1.15
كلّ العمليات الحسابية والدوالّ الشاملة (np.log وnp.exp وnp.sqrt…) تنطبق عنصراً عنصراً على المصفوفة كاملة. اشتمال القائمة من الوحدة 2 يصبح تعبيراً بلا حلقة:
standardized = (x - x.mean()) / x.std() # التقييس في سطر واحد
القاعدة المهنية: إن وجدت نفسك تكتب حلقة for على مصفوفة NumPy فتوقّف — توجد على الأرجح صياغة موجَّهة، أسرع وأقرب إلى الرياضيات.
البثّ (broadcasting): العمل بين شكلين مختلفين
يمدّد NumPy تلقائياً المصفوفات ذات الأشكال المتوافقة:
m = np.array([[1., 2., 3.],
[4., 5., 6.]]) # شكل (2, 3)
m * 10 # عدد مفرد يُبثّ في كلّ مكان
m - m.mean(axis=0) # يطرح متوسّط كلّ عمود — شكل (3,) يُبثّ على (2, 3)
القاعدة الرسمية: بُعدان متوافقان إذا كانا متساويين أو أحدهما يساوي 1، بمحاذاة الأشكال من اليمين. عملياً، الحالة المهمّة هي أعلاه: تمركز الأعمدة أو تحجيمها بلا حلقة. وهذه بالضبط خطوة التقييس التي تسبق معظم النماذج.
طرح مصفوفة شكلها (n,) من مصفوفة شكلها (n, 1) ينتج مصفوفة (n, n) — بلا أيّ خطأ. إن أعاد حسابٌ شكلاً عبثياً فابحث عن بثّ غير مقصود؛ x.reshape(-1, 1) وx.ravel() يصحّحان الأشكال.
الأقنعة المنطقية: الترشيح بشرط
أكثر تراكيب NumPy استخداماً — والآلية الحرفية وراء مرشّحات pandas في الوحدة التالية:
ages = np.array([22, 35, 58, 41, 17, 63])
mask = ages >= 40 # array([False, False, True, True, False, True])
ages[mask] # array([58, 41, 63]) — انتقاء
(ages >= 40).mean() # 0.5 — النسبة (True تُحسَب 1)
# شروط مركّبة: & (و)، | (أو)، والأقواس إلزامية
active_seniors = ages[(ages >= 40) & (ages < 65)]
# استبدال شرطي
capped = np.where(ages > 60, 60, ages)
الأقواس حول كلّ شرط ليست اختيارية: أولوية & و| أعلى من المقارنات، ونسيانها ينتج خطأً غامضاً.
التجميعات والمحاور: التلخيص في الاتجاه الصحيح
grades = np.array([[12, 15, 9],
[14, 11, 16]]) # طالبان × 3 موادّ
grades.mean() # 12.83 — المتوسّط العامّ
grades.mean(axis=0) # [13. 13. 12.5] — لكلّ مادّة (تنهار الصفوف)
grades.mean(axis=1) # [12. 13.67] — لكلّ طالب (تنهار الأعمدة)
القاعدة الذهنية الراسخة: axis يسمّي المحور الذي يختفي. axis=0 يطوي الصفوف فتبقى قيمة لكلّ عمود. التجميعات نفسها في كلّ مكان: sum وmin وmax وstd وargmax (مؤشّر الأقصى — الذي يعطي الفئة المتنبَّأ بها في شبكة عصبية).
دقيقتان من العالم الحقيقي: القيم الناقصة تنتشر (np.nan يلوّث أيّ مجموع — استخدم np.nanmean وعائلتها)، وتقطيعات NumPy عروض (views) على الذاكرة نفسها لا نسخ (.copy() للفصل).
الخلاصة
- المصفوفة
ndarrayمتجانسة منمّطة؛shapeوdtypeأول عادات التشخيص. - التوجيه يستبدل الحلقات: عمليات عنصراً بعنصر، أسرع 10 إلى 100 مرّة، وأوضح.
- البثّ يتيح العمل بين أشكال متوافقة — تمركز الأعمدة في سطر — لكنه قد يصنع أشكالاً عبثية في صمت.
- الأقنعة المنطقية: ترشيح وعدّ واستبدال بشرط؛ الأقواس إلزامية مع
&و|. axis= المحور الذي يختفي؛np.nanmeanأمام النواقص؛ التقطيعات عروض.
الوحدة التالية: pandas، التي تضع تسميات — أسماء أعمدة وفهرساً — على هذ ه المصفوفات وتصبح أداة العمل اليومية على البيانات الجدولية.