Machine Learning: دورة مكثفة في NumPy

آخر تحديث: 2026-08-26

NumPy هو حجر الأساس لعلوم البيانات في Python — كل مكتبة ML رئيسية (Pandas, Scikit-learn, PyTorch) مبنية فوق مصفوفات NumPy.

1. ما ستتعلمه


2. قصة حقيقية من مهندس بيانات

(1) المشكلة: قوائم Python بطيئة جدًا لملايين الصفوف

كان Bob بحاجة إلى حساب إحصائيات المبيعات الشهرية عبر 12 شهرًا و 5 فئات منتجات — 60 ألف سجل. استخدام حلقات Python الأصلية لحساب المتوسط والانحراف المعياري استغرق أكثر من 30 ثانية، ومجموعة بيانات Alice الأمريكية المكونة من 500 ألف سجل تجمدت تمامًا. حلقات Python الأصلية هي عنق الزجاجة في معالجة بيانات ML.

(2) حل NumPy

يستخدم ndarray في NumPy كتل ذاكرة متجاورة وعمليات منخفضة المستوى بلغة C، مما يجعل الحسابات المتجهة أسرع بـ 50-100 مرة من حلقات Python.

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) إنشاء المصفوفات

PYTHON
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

PYTHON
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:

TEXT 📖 للعرض فقط
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

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

(3) آلية البث (Broadcasting)

تسمح آلية البث للمصفوفات ذات الأشكال المختلفة بالتوسع تلقائيًا أثناء العمليات الحسابية، مما يلغي الحاجة إلى نسخ البيانات يدويًا.

100%
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)"]

▶ مثال: البث عمليًا

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

4. فهرسة المصفوفات وتقطيعها

(1) الفهرسة والتقطيع الأساسيان

PYTHON
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)

▶ مثال: تصفية فئات المبيعات المرتفعة

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

(3) الفهرسة المتقدمة (Fancy Indexing)

▶ مثال: اختيار أشهر وفئات محددة

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully
طريقة الفهرسة الصيغة الأبعاد المُعادة حالة الاستخدام
الفهرسة الأساسية arr[2] تقليل البُعد الوصول إلى عنصر واحد
التقطيع arr[1:5] نفس البُعد الوصول إلى نطاق متجاور
Boolean indexing arr[mask] 1D تصفية شرطية
Fancy indexing arr[[1,3,5]] نفس البُعد الوصول إلى مواقع غير متجاورة

5. الحوسبة العددية والإحصاء

(1) العمليات المتجهة

العمليات المتجهة في NumPy تحل محل حلقات Python وهي جوهر ميزة الأداء في NumPy.

▶ مثال: مقارنة أداء التوجيه المتجه مقابل الحلقة

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

(2) الدوال الإحصائية

▶ مثال: إحصائيات مبيعات SalesPredict

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

(3) عمليات المصفوفات

▶ مثال: حساب مصفوفة عائد الإنفاق الإعلاني

PYTHON
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:

TEXT 📖 للعرض فقط
# Executed successfully

6. الأرقام العشوائية والجبر الخطي

(1) توليد الأرقام العشوائية

PYTHON
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) الجبر الخطي

▶ مثال: المعادلة الطبيعية للانحدار الخطي

PYTHON
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:

TEXT 📖 للعرض فقط
# 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)

❓ أسئلة شائعة

س ما الفرق الجوهري بين ndarray وقائمة Python؟
ج يحتوي ndarray على أنواع عناصر موحدة، وذاكرة متجاورة، ويدعم العمليات المتجهة؛ أما القائمة فتحتوي على أنواع مختلطة، وذاكرة متفرقة، ولا يمكن معالجتها إلا بالحلقات. ndarrays أسرع بـ 50-100 مرة في الحوسبة العددية.
س هل تنسخ reshape البيانات؟
ج لا. reshape يُرجع عرضًا (view) للبيانات الأصلية دون نسخ الذاكرة. ومع ذلك، إذا كانت الأشكال غير متوافقة (مثل الذاكرة غير المتجاورة)، فسيُنشئ نسخة تلقائيًا. استخدم السمة .base للتحقق مما إذا كان الشيء عرضًا.
س ما هي قواعد البث (broadcasting)؟
ج تتم محاذاة الأبعاد من المحور الأيمن. أي بُعد قيمته 1 أو مفقود يتم توسيعه تلقائيًا. يجب أن يكون البُعدان إما متساويين أو أن يكون أحدهما 1؛ وإلا، يتم رفع خطأ.
س متى أستخدم np.random.seed مقابل np.random.default_rng؟
ج استخدم default_rng (الواجهة الأحدث) — seed تنتمي إلى الواجهة القديمة. يستخدم default_rng خوارزمية PCG64، التي تتمتع بجودة إحصائية أفضل ولا تؤثر على الحالة العامة.
س كيف أعرف إذا كانت مصفوفتان تشاركان الذاكرة؟
ج استخدم np.shares_memory(a, b) للتحقق. أو تحقق مما إذا كان a.base is b أو b.base is a. عند مشاركة الذاكرة، فإن تعديل مصفوفة واحدة سيؤثر على الأخرى.
س لماذا تُعتبر NumPy أساس ML؟
ج Pandas مبنية فوق مصفوفات NumPy في الأسفل، ومخرجات ومدخلات Scikit-learn كلها ndarray، وTensors في PyTorch متوافقة للغاية مع NumPy. إتقان NumPy يعني إتقان لغة البيانات في ML.

📖 ملخص

📝 تمارين

  1. أساسي (الصعوبة ⭐): أنشئ مصفوفة 5x5 بقيم من 1 إلى 25، ثم استخدم التقطيع لاستخراج عناصر القطر. تلميح: عناصر القطر لها نفس مؤشر الصف والعمود، أو استخدم np.diag().
  2. متوسط (الصعوبة ⭐⭐): ولّد 1000 نقطة بيانات مبيعات عشوائية من توزيع طبيعي N(100, 15)، واستخدم boolean indexing لتصفية القيم فوق 130، واحسب نسبتها. تلميح: استخدم rng.normal() و boolean indexing.
  3. تحدي (الصعوبة ⭐⭐⭐): نفّذ انحدارًا خطيًا متعددًا باستخدام المعادلة الطبيعية في NumPy. افترض sales = 20 + 3ad_spend + 1.5traffic + noise. ولّد بيانات محاكاة، وحل المعاملات، وقارنها بالمعاملات الحقيقية. تلميح: أضف عمود انحياز عند بناء مصفوفة X، واستخدم np.linalg.inv مع ضرب المصفوفات.

← الدرس السابق: مقدمة في تعلم الآلة | الدرس التالي: معالجة البيانات باستخدام Pandas →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%