Machine Learning: دورة مكثفة في NumPy
آخر تحديث: 2026-08-26
NumPy هو حجر الأساس لعلوم البيانات في Python — كل مكتبة ML رئيسية (Pandas, Scikit-learn, PyTorch) مبنية فوق مصفوفات NumPy.
1. ما ستتعلمه
- إنشاء ndarray ومعالجة الأشكال: reshape، transpose، وآلية البث
- فهرسة المصفوفات وتقطيعها: Boolean indexing، fancy indexing، والتقطيع متعدد الأبعاد
- الحوسبة العددية: العمليات المتجهة، ضرب المصفوفات، والدوال الإحصائية
- توليد الأرقام العشوائية وأساسيات الجبر الخطي: np.random و np.linalg
- العمل على مصفوفة بيانات مبيعات SalesPredict لـ Bob باستخدام NumPy
2. قصة حقيقية من مهندس بيانات
(1) المشكلة: قوائم Python بطيئة جدًا لملايين الصفوف
كان Bob بحاجة إلى حساب إحصائيات المبيعات الشهرية عبر 12 شهرًا و 5 فئات منتجات — 60 ألف سجل. استخدام حلقات Python الأصلية لحساب المتوسط والانحراف المعياري استغرق أكثر من 30 ثانية، ومجموعة بيانات Alice الأمريكية المكونة من 500 ألف سجل تجمدت تمامًا. حلقات Python الأصلية هي عنق الزجاجة في معالجة بيانات ML.
(2) حل NumPy
يستخدم ndarray في NumPy كتل ذاكرة متجاورة وعمليات منخفضة المستوى بلغة C، مما يجعل الحسابات المتجهة أسرع بـ 50-100 مرة من حلقات Python.
import numpy as np
# حلقة Python مقابل التوجيه المتجه في NumPy
sales_list = list(range(1, 60001)) # 60,000 سجل
sales_arr = np.array(sales_list)
# NumPy متجه: أسرع بـ 100 مرة
mean_val = sales_arr.mean()
std_val = sales_arr.std()
print(f"Mean: {mean_val:.2f}, Std: {std_val:.2f}")
(3) النتيجة: انخفض وقت الحساب من 30 ثانية إلى 0.3 ثانية
بعد أن نقل Bob معالجة البيانات من حلقات Python إلى التوجيه المتجه في NumPy، انخفضت الحسابات الإحصائية على 60 ألف سجل من 30 ثانية إلى 0.3 ثانية. وحتى سجلات Alice البالغة 500 ألف سجل تكتمل في أقل من ثانية.
3. إنشاء ndarray ومعالجة الأشكال
ndarray هو بنية البيانات الأساسية في NumPy — مصفوفة متعددة الأبعاد من عناصر من نفس النوع مخزنة في ذاكرة متجاورة.
(1) إنشاء المصفوفات
import numpy as np
# من قائمة Python
a = np.array([1, 2, 3, 4, 5])
# دوال البناء المدمجة
zeros = np.zeros((3, 4)) # مصفوفة أصفار 3x4
ones = np.ones((2, 3)) # مصفوفة آحاد 2x3
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]
print(f"arange: {range_arr}")
print(f"linspace: {linspace}")
▶ مثال: إنشاء مصفوفة مبيعات SalesPredict
import numpy as np
# المبيعات الشهرية لـ 5 فئات على مدار 12 شهرًا (بالألف دولار)
sales = np.array([
[120, 135, 150, 142, 160, 175, 180, 190, 195, 200, 220, 250], # Electronics
[80, 85, 90, 88, 95, 100, 105, 108, 110, 115, 130, 145], # Clothing
[50, 48, 55, 60, 58, 62, 65, 68, 70, 72, 80, 90], # Food
[30, 35, 40, 38, 42, 45, 48, 50, 52, 55, 60, 70], # Books
[200, 210, 225, 220, 240, 260, 270, 280, 290, 300, 350, 400], # Home
])
print(f"Shape: {sales.shape}")
print(f"Total annual revenue: {sales.sum() / 1000:.1f} million USD")
print(f"Q4 revenue: {sales[:, 9:].sum() / 1000:.1f} million USD")
Output:
Shape: (5, 12)
Total annual revenue: 6.3 million USD
Q4 revenue: 2.3 million USD
(2) عمليات الشكل
| العملية | الطريقة | الوصف |
|---|---|---|
| Reshape | reshape() |
تغيير العرض دون تعديل البيانات |
| Transpose | T أو transpose() |
تبديل الصفوف والأعمدة |
| Flatten | flatten() / ravel() |
متعدد الأبعاد → أحادي |
| إضافة بُعد | np.newaxis / expand_dims |
إضافة محور جديد |
▶ مثال: reshape و transpose
import numpy as np
# Reshape: من 1D إلى 2D
data = np.arange(12)
matrix = data.reshape(3, 4)
print(f"Reshaped to 3x4:\n{matrix}")
# Transpose: تبديل الصفوف والأعمدة
transposed = matrix.T
print(f"Transposed to 4x3:\n{transposed}")
# -1 تعني الحساب التلقائي للبعد
auto_reshape = data.reshape(2, -1)
print(f"Auto reshape (2, -1): shape={auto_reshape.shape}")
Output:
# Executed successfully
(3) آلية البث (Broadcasting)
تسمح آلية البث للمصفوفات ذات الأشكال المختلفة بالتوسع تلقائيًا أثناء العمليات الحسابية، مما يلغي الحاجة إلى نسخ البيانات يدويًا.
graph TB
A[Scalar + Array] --> B["Scalar broadcast to array shape"]
C["1D + 2D Array"] --> D["1D broadcast along axis 0"]
E["Shape (3,1) + (1,4)"] --> F["Both broadcast to (3,4)"]
▶ مثال: البث عمليًا
import numpy as np
# Scalar + array: يتم بث Scalar
prices = np.array([100, 200, 300, 400])
discount = 0.9 # خصم 10%
print(f"Discounted prices: {prices * discount}")
# 1D + 2D: يتم بث الصف عبر الصفوف
monthly_sales = np.array([[100, 200], [110, 210], [120, 220]]) # 3 أشهر × 2 فئات
growth_rate = np.array([1.05, 1.10]) # نمو مختلف لكل فئة
print(f"Projected sales:\n{monthly_sales * growth_rate}")
# بث العمود + الصف
col = np.array([[1], [2], [3]]) # شكل (3, 1)
row = np.array([10, 20, 30, 40]) # شكل (4,)
print(f"Col + Row result shape: {(col + row).shape}")
Output:
# Executed successfully
4. فهرسة المصفوفات وتقطيعها
(1) الفهرسة والتقطيع الأساسيان
import numpy as np
arr = np.arange(10)
print(f"arr[3]: {arr[3]}") # عنصر واحد
print(f"arr[2:7]: {arr[2:7]}") # شريحة
print(f"arr[::2]: {arr[::2]}") # خطوة=2
# فهرسة 2D
matrix = np.arange(12).reshape(3, 4)
print(f"matrix[1, 2]: {matrix[1, 2]}") # صف 1، عمود 2
print(f"matrix[0, :]: {matrix[0, :]}") # الصف 0 بالكامل
print(f"matrix[:, 1]: {matrix[:, 1]}") # العمود 1 بالكامل
(2) الفهرسة المنطقية (Boolean Indexing)
▶ مثال: تصفية فئات المبيعات المرتفعة
import numpy as np
# مبيعات الفئات الشهرية (بالألف دولار)
sales = np.array([250, 145, 90, 70, 400])
categories = np.array(["Electronics", "Clothing", "Food", "Books", "Home"])
# Boolean indexing: البحث عن الفئات فوق 100k
high_sales = sales > 100
print(f"High sales mask: {high_sales}")
print(f"High sales categories: {categories[high_sales]}")
print(f"High sales values: {sales[high_sales]}")
# شروط مركبة
mid_range = (sales >= 80) & (sales <= 200)
print(f"Mid-range categories: {categories[mid_range]}")
Output:
# Executed successfully
(3) الفهرسة المتقدمة (Fancy Indexing)
▶ مثال: اختيار أشهر وفئات محددة
import numpy as np
sales = np.arange(60).reshape(5, 12) # 5 فئات × 12 شهرًا
# اختيار أشهر محددة: يناير، أبريل، يوليو، أكتوبر (المؤشرات 0,3,6,9)
quarterly = sales[:, [0, 3, 6, 9]]
print(f"Quarterly data shape: {quarterly.shape}")
# اختيار أعلى 3 فئات حسب إجمالي المبيعات
total = sales.sum(axis=1)
top3_idx = np.argsort(total)[-3:]
print(f"Top 3 category indices: {top3_idx}")
print(f"Top 3 total sales: {total[top3_idx]}")
Output:
# Executed successfully
| طريقة الفهرسة | الصيغة | الأبعاد المُعادة | حالة الاستخدام |
|---|---|---|---|
| الفهرسة الأساسية | arr[2] |
تقليل البُعد | الوصول إلى عنصر واحد |
| التقطيع | arr[1:5] |
نفس البُعد | الوصول إلى نطاق متجاور |
| Boolean indexing | arr[mask] |
1D | تصفية شرطية |
| Fancy indexing | arr[[1,3,5]] |
نفس البُعد | الوصول إلى مواقع غير متجاورة |
5. الحوسبة العددية والإحصاء
(1) العمليات المتجهة
العمليات المتجهة في NumPy تحل محل حلقات Python وهي جوهر ميزة الأداء في NumPy.
▶ مثال: مقارنة أداء التوجيه المتجه مقابل الحلقة
import numpy as np
import time
size = 1_000_000
a = np.random.rand(size)
b = np.random.rand(size)
# حساب متجه
start = time.time()
c = a + b
vec_time = time.time() - start
# حلقة Python (بطيئة!)
start = time.time()
c_list = [a[i] + b[i] for i in range(size)]
loop_time = time.time() - start
print(f"Vectorized: {vec_time:.4f}s")
print(f"Loop: {loop_time:.4f}s")
print(f"Speedup: {loop_time / vec_time:.0f}x")
Output:
# Executed successfully
(2) الدوال الإحصائية
▶ مثال: إحصائيات مبيعات SalesPredict
import numpy as np
# بيانات المبيعات اليومية لـ 30 يومًا (بالألف دولار)
daily_sales = np.array([
45, 52, 48, 61, 55, 72, 68, 50, 53, 49,
58, 63, 71, 66, 59, 54, 47, 70, 75, 62,
51, 57, 64, 69, 73, 60, 56, 67, 74, 78
])
print(f"Mean: {daily_sales.mean():.1f}k USD")
print(f"Median: {np.median(daily_sales):.1f}k USD")
print(f"Std: {daily_sales.std():.1f}k USD")
print(f"Min: {daily_sales.min()}k USD")
print(f"Max: {daily_sales.max()}k USD")
print(f"Total: {daily_sales.sum()}k USD")
# المجموع التراكمي للاتجاه
cum_sales = daily_sales.cumsum()
print(f"Day 30 cumulative: {cum_sales[-1]}k USD")
Output:
# Executed successfully
(3) عمليات المصفوفات
▶ مثال: حساب مصفوفة عائد الإنفاق الإعلاني
import numpy as np
# الإنفاق الإعلاني لكل قناة (3 قنوات) × 4 منتجات
ad_matrix = np.array([
[10, 15, 8, 12], # Google Ads (بالألف دولار)
[5, 20, 10, 8], # Facebook Ads
[3, 7, 15, 10], # Email Marketing
])
# مصفوفة معدل التحويل (قناة × منتج)
conv_rate = np.array([
[0.05, 0.03, 0.08, 0.04],
[0.03, 0.06, 0.04, 0.05],
[0.10, 0.08, 0.12, 0.09],
])
# العائد لكل تحويل (لكل منتج، بالألف دولار)
revenue_per_conv = np.array([50, 30, 80, 40])
# ضرب المصفوفات: التحويلات المتوقعة
expected_conv = ad_matrix * conv_rate # عنصر بعنصر
# إجمالي العائد لكل منتج
total_revenue = expected_conv.sum(axis=0) * revenue_per_conv
print(f"Revenue by product: {total_revenue} thousand USD")
print(f"Total ROI revenue: {total_revenue.sum():.1f} thousand USD")
Output:
# Executed successfully
6. الأرقام العشوائية والجبر الخطي
(1) توليد الأرقام العشوائية
import numpy as np
rng = np.random.default_rng(seed=42) # قابل للتكرار
# التوزيعات الشائعة
uniform = rng.uniform(0, 100, size=5) # منتظم [0, 100)
normal = rng.normal(50, 10, size=5) # طبيعي (متوسط=50، انحراف=10)
integers = rng.integers(1, 100, size=5) # أعداد صحيحة عشوائية [1, 100)
choice = rng.choice(["A", "B", "C"], size=5) # اختيار عشوائي
print(f"Uniform: {uniform}")
print(f"Normal: {normal}")
print(f"Integers: {integers}")
(2) الجبر الخطي
▶ مثال: المعادلة الطبيعية للانحدار الخطي
import numpy as np
# محاكاة: sales = 50 + 0.8 * ad_spend + noise
rng = np.random.default_rng(42)
n = 100
ad_spend = rng.uniform(10, 100, n)
noise = rng.normal(0, 5, n)
sales = 50 + 0.8 * ad_spend + noise
# الحل باستخدام المعادلة الطبيعية: w = (X^T X)^-1 X^T y
X = np.column_stack([np.ones(n), ad_spend]) # إضافة عمود الانحياز
w = np.linalg.inv(X.T @ X) @ (X.T @ sales)
print(f"Intercept: {w[0]:.2f}")
print(f"Coefficient: {w[1]:.2f}")
print(f"True values: intercept=50, coeff=0.8")
Output:
# Executed successfully
| الدالة | الغرض | الصيغة |
|---|---|---|
np.dot / @ |
ضرب المصفوفات | A @ B |
np.linalg.inv |
معكوس المصفوفة | inv(A) |
np.linalg.det |
المحدد | det(A) |
np.linalg.norm |
معيار المتجه/المصفوفة | norm(v) |
np.linalg.svd |
تحليل القيمة المفردة | U, S, Vt = svd(A) |
np.linalg.solve |
حل أنظمة خطية | solve(A, b) |
❓ أسئلة شائعة
.base للتحقق مما إذا كان الشيء عرضًا.np.shares_memory(a, b) للتحقق. أو تحقق مما إذا كان a.base is b أو b.base is a. عند مشاركة الذاكرة، فإن تعديل مصفوفة واحدة سيؤثر على الأخرى.📖 ملخص
- ndarray هو مصفوفة متعددة الأبعاد ذات أنواع موحدة وذاكرة متجاورة — بنية البيانات الأساسية في NumPy
- تسمح آلية البث للمصفوفات ذات الأشكال المختلفة بالتوسع تلقائيًا للحسابات، متجنبة النسخ اليدوي للبيانات
- العمليات المتجهة أسرع بـ 50-100 مرة من حلقات Python — جوهر ميزة الأداء في NumPy
- توفر Boolean indexing و fancy indexing طرقًا مرنة لتصفية البيانات
- يوفر np.linalg معكوس المصفوفة و SVD وعمليات الجبر الخطي الأخرى التي تشكّل الأساس الرياضي لخوارزميات ML
- استخدم default_rng(seed) لتوليد الأرقام العشوائية لضمان إمكانية التكرار
📝 تمارين
- أساسي (الصعوبة ⭐): أنشئ مصفوفة 5x5 بقيم من 1 إلى 25، ثم استخدم التقطيع لاستخراج عناصر القطر. تلميح: عناصر القطر لها نفس مؤشر الصف والعمود، أو استخدم
np.diag(). - متوسط (الصعوبة ⭐⭐): ولّد 1000 نقطة بيانات مبيعات عشوائية من توزيع طبيعي N(100, 15)، واستخدم boolean indexing لتصفية القيم فوق 130، واحسب نسبتها. تلميح: استخدم
rng.normal()و boolean indexing. - تحدي (الصعوبة ⭐⭐⭐): نفّذ انحدارًا خطيًا متعددًا باستخدام المعادلة الطبيعية في NumPy. افترض sales = 20 + 3ad_spend + 1.5traffic + noise. ولّد بيانات محاكاة، وحل المعاملات، وقارنها بالمعاملات الحقيقية. تلميح: أضف عمود انحياز عند بناء مصفوفة X، واستخدم
np.linalg.invمع ضرب المصفوفات.
← الدرس السابق: مقدمة في تعلم الآلة | الدرس التالي: معالجة البيانات باستخدام Pandas →