NumPy: الشروع في العمل مع NumPy

NumPy هو أساس الحوسبة العلمية في بايثون. سواء كنت تعمل في التعلم الآلي، تحليل البيانات، أو المحاكاة الهندسية، فإن كل مكتبة رقمية تقريبًا تُبنى على NumPy. يبدأ هذا الفصل من نقاط الضعف في أداء قوائم بايثون ويكشف كيف يحقق NumPy تسريعًا بمقدار 160 ضعفًا — خطوتك الأولى في الحوسبة الرقمية.

⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة بايثون محلية.

1. ما ستتعلمه



2. رحلة التسريع مع بيانات بملايين السجلات

(1) المشكلة: حلقة Alice مع القائمة

Alice محللة بيانات، تحتاج إلى تربيع مليون رقم عشوائي. تكتب كود بايثون الأكثر "طبيعية" — حلقة for تعالج عناصر القائمة واحدًا تلو الآخر.

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

: تربيع قائمة (الصعوبة ⭐)

PYTHON
import time
import random

size = 1_000_000  # 1 million numbers
data = [random.random() for _ in range(size)]

start = time.time()
result = [x * x for x in data]
elapsed = time.time() - start

print(f"List comprehension: {elapsed:.4f} seconds")
# Typical output: List comprehension: 0.8000 seconds
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

كود Alice يستغرق حوالي 0.8 ثانية. لا يبدو ذلك سيئًا — حتى تحتاج إلى إجراء نفس العملية على مئات الملايين من نقاط البيانات، حيث يصبح الانتظار لا يطاق.

(2) الحل: التوجيه المتجهي لـ Bob مع NumPy

Bob يغير سطرين فقط: استبدال القائمة بـ np.array والحلقة بعملية ضرب متجهية واحدة.

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

: تربيع NumPy (الصعوبة ⭐⭐)

PYTHON
import time
import numpy as np

size = 1_000_000  # 1 million numbers
data = np.random.random(size)

start = time.time()
result = data * data  # vectorized operation
elapsed = time.time() - start

print(f"NumPy vectorized: {elapsed:.4f} seconds")
---
## 3. Typical output: NumPy vectorized: 0.0050 seconds
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

نفس المليون رقم تستغرق فقط حوالي 5 ملي ثانية مع NumPy — أسرع بحوالي 160 ضعفًا.

(3) النتيجة: ما الذي يجعلها أسرع 160 ضعفًا

سرعة NumPy ليست بسبب "بايثون أصبح أسرع" — بل بسبب تحويل العمليات الحسابية إلى لغة C واستخدام الذاكرة المتجاورة:

هذه هي فلسفة NumPy الأساسية — سهولة بايثون مع سرعة C.



4. لماذا تعاني قوائم بايثون مع الأرقام

(1) الحمل الزائد للحلقة: التنفيذ المفسر

بايثون لغة ديناميكية الأنماط. كل تكرار للحلقة يمر بـ: التحقق من النوع ← البحث عن الدالة → تنفيذ العملية → تغليف النتيجة. بالنسبة للعمل الرقمي، هذه الخطوات الإضافية هي هدر محض.

PYTHON
---
## 5. Each iteration: type check + method lookup + boxing
result = []
for x in data:          # Python loop overhead per iteration
    result.append(x * x)  # type check, method dispatch, result boxing
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

مقارنة بكود C المترجم، يمكن أن يكون الحمل الزائد لتكرار حلقة بايثون الواحدة عشرات المرات أكثر تكلفة من عملية الضرب الفعلية.

(2) الحمل الزائد للنوع: كل عنصر هو كائن كامل

قائمة بايثون لا تخزن أرقامًا أولية — إنها تخزن مؤشرات PyObject. العدد الصحيح 42 يأخذ 28 بايت في بايثون، ولكن 4 بايت فقط في C.



6. المزايا الأساسية لـ NumPy

(1) ما هو ndarray

ndarray (مصفوفة متعددة الأبعاد) هي بنية البيانات الأساسية لـ NumPy. إنها:

(2) ndarray مقابل قائمة بايثون

الخاصية قائمة بايثون ndarray في NumPy
نوع العنصر أي خليط متجانس (نمط dtype واحد)
تخطيط الذاكرة مصفوفة مؤشرات، عناصر متناثرة كتلة ذاكرة متجاورة
ذاكرة عدد صحيح واحد 28 بايت (PyObject) 8 بايت (int64)
العمليات الجماعية فهم القائمة / حلقة for متجهية، تعليمة واحدة
البث غير مدعوم توسيع الأبعاد تلقائيًا
عرض الشريحة يعيد نسخة يعيد عرضًا افتراضيًا (بدون نسخ)
متعدد الأبعاد قوائم متداخلة (غير منتظمة) أبعاد N أصلية، خاصية shape
تحت الغطاء مفسر CPython كود C / Fortran مُجمّع

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

: مقارنة الذاكرة (الصعوبة ⭐)

PYTHON
import sys
import numpy as np

size = 1_000_000  # 1 million integers

---
## 7. Python list
py_list = list(range(size))
list_bytes = sys.getsizeof(py_list) + sum(sys.getsizeof(x) for x in py_list[:1000]) * size // 1000
print(f"Python list: ~{list_bytes / 1024 / 1024:.1f} MB")

---
## 8. NumPy ndarray
np_array = np.arange(size, dtype=np.int64)
array_bytes = np_array.nbytes
print(f"NumPy ndarray: {array_bytes / 1024 / 1024:.1f} MB")

print(f"Ratio: {list_bytes / array_bytes:.1f}x more memory for list")
---
## 9. Typical output:
---
## 10. Python list: ~44.7 MB
---
## 11. NumPy ndarray: 7.6 MB
---
## 12. Ratio: 5.9x more memory for list
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

مصفوفة ndarray بسيطة من النوع int64 تستخدم ذاكرة أقل بحوالي 6 مرات من قائمة بايثون بنفس الحجم — لأن ndarray تخزن القيم الأولية، وليس كائنات بايثون كاملة.

(3) نظرة أولى على البث (Broadcasting)

"البث" يسمح للمصفوفات ذات الأشكال المختلفة بالعمل معًا مباشرة، دون الحاجة إلى توسيع الأبعاد يدويًا.

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

: عمليات المصفوفة مقابل فهم القائمة (الصعوبة ⭐⭐)

PYTHON
import numpy as np

---
## 13. Task: add 100 to every element and multiply by 2
data = [1, 2, 3, 4, 5]

---
## 14. --- Python list ---
result_list = [(x + 100) * 2 for x in data]
print(result_list)
---
## 15. [202, 204, 206, 208, 210]

---
## 16. --- NumPy ndarray ---
arr = np.array(data)
result_np = (arr + 100) * 2  # broadcasting + vectorization
print(result_np)
---
## 17. [202 204 206 208 210]

---
## 18. With a 2D array and 1D array
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
---
## 19. [[11 22 33]
---
##  20. [14 25 36]]
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة بايثون المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

فهم القائمة يحتاج إلى كتابة منطق الحلقة، بينما NumPy يحتاج فقط إلى تعبير رياضي واحد — الكود هو الصيغة.



❓ أسئلة شائعة

س ما العلاقة بين NumPy وبايثون؟
ج NumPy هي مكتبة طرف ثالث، وليست جزءًا من المكتبة القياسية لبايثون. محرك الحوسبة الأساسي مكتوب بلغة C ويتم استدعاؤه عبر واجهة بايثون، مما يمنحك سرعة قريبة من C من بايثون.
س لماذا NumPy أسرع بكثير من القوائم؟
ج ثلاثة أسباب — ① تنفيذ على مستوى C يتجاوز حمل مفسر بايثون؛ ② تخطيط الذاكرة المتجاورة يزيد من كفاءة ذاكرة التخزين المؤقت لوحدة المعالجة المركزية؛ ③ العمليات المتجهية تعالج المصفوفة بأكملها بتعليمة واحدة، بدون حلقة عنصر بعنصر.
س هل أحتاج إلى تعلم C لاستخدام NumPy؟
ج لا. هدف تصميم NumPy هو تمكين مستخدمي بايثون من الاستمتاع بسرعة C باستخدام صيغة بايثون. تحتاج C فقط إذا كنت تريد المساهمة في الكود الأساسي أو كتابة إضافات C مخصصة لـ NumPy.
س هل يمكن لـ NumPy استبدال Excel؟
ج للحوسبة الرقمية والمعالجة الجماعية، NumPy أقوى وأكثر كفاءة من Excel. لكن NumPy لا يوفر واجهة جداول بيانات أو رسوم بيانية بالسحب والإفلات — ستحتاج عادةً إلى إقرانه مع Pandas (البيانات الجدولية) و Matplotlib (التصور).
س ما الفرق بين NumPy 2.x و 1.x؟
ج NumPy 2.0 (الذي صدر في 2024) حسّن بشكل أساسي استقرار واجهة C API، وأضاف بعض واجهات برمجة تطبيقات معالجة السلاسل، وطور نظام dtype. لمستخدمي بايثون اليوميين، تغييرات واجهة API طفيفة — معظم كود 1.x ينتقل بسلاسة. المشاريع الجديدة يجب أن تستخدم 2.x.
س ما الفرق بين ndarray ووحدة مصفوفة في بايثون؟
ج وحدة array المضمنة في بايثون تدعم فقط مصفوفات أحادية البعد متجانسة بدون بث أو جبر خطي أو تحويل فورييه. ndarray في NumPy يدعم بيانات متعددة الأبعاد، البث، ومجموعة غنية من الدوال الرياضية — هما في مستويين مختلفين تمامًا.

📖 ملخص


📝 تمارين

  1. مبتدئ (الصعوبة ⭐): قم بتثبيت NumPy وشغّل import numpy as np; print(np.__version__). تأكد من أن الإصدار ≥ 1.24. سجل المخرجات.

  2. متوسط (الصعوبة ⭐⭐): أنشئ قائمة ومصفوفة ndarray، كل منهما يحتوي على 5 ملايين رقم عشوائي. استخدم فهم القائمة وتوجيه NumPy المتجهي لحساب مربع كل رقم زائد 10. قم بقياس الوقت لكل منهما باستخدام time.time() وقارن. سجل نسبة السرعة.

  3. متقدم (الصعوبة ⭐⭐⭐): شغّل np.show_config() وحدد خلفية BLAS التي يستخدمها NumPy الخاص بك (OpenBLAS / MKL / غير ذلك). ابحث كيف تؤثر هذه الخلفية على أداء عمليات المصفوفات واكتب شرحًا موجزًا.

Web-Tutorial.com

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

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

100%