NumPy: أساسيات ndarray الأساسية

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

هيكل البيانات الأساسي في NumPy هو ndarray — المصفوفة متعددة الأبعاد. تبدو مثل قائمة Python، لكنها مختلفة تمامًا من الداخل: نوع ثابت، ذاكرة متجاورة، عمليات متجهة. فهم داخلية ndarray هو الخطوة الأولى لاستخدام NumPy بفعالية.

1. ما ستتعلمه




2. قصة حقيقية لمحلل بيانات

(1) المشكلة: Excel في Python، ارتباك

بوب لديه جدول Excel بثلاثة صفوف وأربعة أعمدة. يخزنه كقائمة من القوائم في Python — 3 قوائم فرعية متداخلة داخل قائمة خارجية. يريد جمع العمود الثاني، لذا يكتب حلقة for للتكرار عبر كل صف. لمليون صف، يستغرق ذلك 5 ثوان. والأسوأ، عندما يتسلل نص إلى أحد الصفوف، لا تفشل الحلقة حتى تصل إلى تلك الخلية.

(2) الحل باستخدام ndarray

يقترح تشارلي على بوب تحويل الجدول إلى ndarray باستخدام np.array. NumPy يفلطح البيانات إلى كتلة ذاكرة متجاورة وينفذ مجموع العمود في عملية واحدة متجهة على مستوى لغة C — نفس المليون صف تستغرق 5 ملي ثانية فقط. يتم فرض الأنواع في وقت الإنشاء، لذا يتم اكتشاف أي نص غريب فورًا، وليس في منتصف العملية الحسابية.

(3) النتيجة




3. جوهر ndarray

(1) أنواع البيانات المتجانسة

يجب أن تكون جميع عناصر ndarray من نفس النوع. هذا مختلف جوهريًا عن قوائم Python — يمكن للقوائم خلط الأعداد الصحيحة والنصوص وحتى الكائنات، بينما يسمح ndarray بنوع واحد فقط.

PYTHON
import numpy as np

a = np.array([1, 2, 3])
print(a.dtype)  # int64

b = np.array([1.0, 2.0, 3.0])
print(b.dtype)  # float64

c = np.array([1, 2.0, 3])
print(c.dtype)  # float64 (رفع تلقائي)
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.

(2) تخزين الذاكرة المتجاورة

قوائم Python تخزن مصفوفة من المؤشرات — كل مؤشر يشير إلى كائن PyObject منفصل موزع عبر ذاكرة الكومة. ndarray، من ناحية أخرى، يرتب كل البيانات في كتلة واحدة متجاورة من الذاكرة، بدون حمل إضافي للمؤشرات وكفاءة ممتازة لذاكرة التخزين المؤقت لوحدة المعالجة المركزية.

الميزة قائمة Python ndarray
نوع العنصر أي خليط نفس dtype
التخزين مصفوفة مؤشرات ← كائنات PyObject مبعثرة كتلة ذاكرة متجاورة
الحمل الإضافي لكل عنصر 28+ بايت (رأس PyObject) يعتمد على dtype (1/2/4/8 بايت)
ملائمة ذاكرة التخزين المؤقت ضعيفة (قفز بين المؤشرات) ممتازة (وصول تسلسلي)
أمان النوع لا يوجد (يُكتشف في وقت التشغيل) يُفرض في وقت الإنشاء

▶ مثال

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

: خصائص المصفوفات 0D/1D/2D/3D (الصعوبة ⭐)

PYTHON
import numpy as np

a0 = np.array(42)                   # 0D عددي
a1 = np.array([1, 2, 3])            # 1D
a2 = np.array([[1, 2], [3, 4]])     # 2D
a3 = np.array([[[1, 2], [3, 4]],
               [[5, 6], [7, 8]]])   # 3D

for name, arr in [("0D", a0), ("1D", a1), ("2D", a2), ("3D", a3)]:
    print(f"{name}: ndim={arr.ndim}, shape={arr.shape}, size={arr.size}")
# 0D: ndim=0, shape=(), size=1
---
## 4. 1D: ndim=1, shape=(3,), size=3
---
## 5. 2D: ndim=2, shape=(2,2), size=4
---
## 6. 3D: ndim=3, shape=(2,2,2), size=8
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.




7. الأبعاد، الشكل، والحجم

(1) ndim / shape / size

الخاصية المعنى مثال (shape=(3,4))
ndim عدد الأبعاد (المحاور) 2
shape طول كل محور، كمجموعة (3, 4)
size العدد الإجمالي للعناصر = حاصل ضرب أطوال المحاور 12
PYTHON
import numpy as np

a = np.zeros((3, 4))
print(a.ndim)    # 2
print(a.shape)   # (3, 4)
print(a.size)    # 12
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.

(2) الخطوات (Strides)

strides تخبرك بعدد البايتات التي يجب تخطيها في الذاكرة للتحرك خطوة واحدة على طول محور معين.

الخاصية المعنى shape=(3,4) dtype=int64
strides الخطوة لكل محور (بايت) (32, 8)
itemsize بايت لكل عنصر 8
PYTHON
import numpy as np

a = np.zeros((3, 4), dtype=np.int64)
print(a.strides)   # (32, 8)
---
## 8. المحور 0: تحرك صفًا واحدًا = 4 * 8 = 32 بايت
---
## 9. المحور 1: تحرك عمودًا واحدًا = 1 * 8 = 8 بايت
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.

▶ مثال

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

: تصور الخطوات (الصعوبة ⭐⭐)

PYTHON
import numpy as np

a = np.arange(12, dtype=np.int32).reshape(3, 4)
print(a)
---
## 10. [[ 0  1  2  3]
---
##  11. [ 4  5  6  7]
---
##  12. [ 8  9 10 11]]
print(f"shape:   {a.shape}")    # (3, 4)
print(f"strides: {a.strides}")  # (16, 4)
print(f"itemsize: {a.itemsize}")  # 4
---
## 13. خطوة المحور 0: 4 عناصر * 4 بايت = 16
---
## 14. خطوة المحور 1: 1 عنصر * 4 بايت = 4
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.




15. الحدس وراء المحاور

المحاور هي مفتاح فهم عمليات ndarray. axis=0 هو البعد الخارجي، axis=1 هو التالي، وهكذا.

المحور الموقع في shape الحدس 2D shape=(3,4) 3D shape=(2,3,4)
axis=0 0 الخارجي اتجاه الصفوف (عبر الصفوف) على طول محور "الطبقة"
axis=1 1 الثاني اتجاه الأعمدة (عبر الأعمدة) على طول محور "الصف"
axis=2 2 الأعمق على طول محور "العمود"

خدعة للذاكرة: axis=k يتوافق مع اتجاه shape[k]. القيام بـ sum/reduce على طول هذا المحور "يلغي" ذلك البعد.

PYTHON
import numpy as np

a = np.arange(24).reshape(2, 3, 4)
print(a.shape)         # (2, 3, 4)
print(a.sum(axis=0).shape)  # (3, 4) — المحور 0 أُلغي
print(a.sum(axis=1).shape)  # (2, 4) — المحور 1 أُلغي
print(a.sum(axis=2).shape)  # (2, 3) — المحور 2 أُلغي
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.




16. dtype واستخدام الذاكرة

(1) نظام أنواع dtype

dtype الوصف بايت النطاق
np.int8 عدد صحيح بإشارة 8 بت 1 -128 ~ 127
np.int32 عدد صحيح بإشارة 32 بت 4 -2^31 ~ 2^31-1
np.int64 عدد صحيح بإشارة 64 بت 8 -2^63 ~ 2^63-1
np.float32 عدد عائم 32 بت 4 ~±3.4e38، دقة 7 أرقام
np.float64 عدد عائم 64 بت 8 ~±1.8e308، دقة 15 رقمًا
np.bool_ منطقي 1 True/False
np.complex128 عدد مركب 128 بت 16 float64 مزدوج

(2) نموذج الذاكرة: ndarray ليس قائمة متداخلة

100%
graph TB
    A["كائن ndarray"] --> B["مؤشر البيانات<br/>كتلة ذاكرة خام"]
    A --> C["dtype<br/>نوع العنصر"]
    A --> D["shape<br/>(3, 4)"]
    A --> E["strides<br/>(32, 8)"]
    B --> F["0,0 | 0,1 | 0,2 | 0,3 | 1,0 | 1,1 | ... | 2,3"]
    style A fill:#4CAF50,color:#fff
    style B fill:#2196F3,color:#fff
    style F fill:#FF9800,color:#fff
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.

(3) جدول مرجعي للشكل والذاكرة

shape ndim size dtype=float64 nbytes strides
(10,) 1 10 80 (8,)
(3, 4) 2 12 96 (32, 8)
(2, 3, 4) 3 24 192 (96, 32, 8)
(5, 2, 3, 4) 4 120 960 (192, 96, 32, 8)

▶ مثال

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

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

PYTHON
import numpy as np

for dtype in [np.int8, np.int32, np.int64, np.float32, np.float64]:
    a = np.zeros(1000, dtype=dtype)
    print(f"{dtype.__name__:10s} itemsize={a.itemsize}  nbytes={a.nbytes}")
---
## 17. int8       itemsize=1  nbytes=1000
---
## 18. int32      itemsize=4  nbytes=4000
---
## 19. int64      itemsize=8  nbytes=8000
---
## 20. float32    itemsize=4  nbytes=4000
---
## 21. float64    itemsize=8  nbytes=8000
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.

▶ مثال

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

: التحقق من أن reshape لا ينسخ البيانات (الصعوبة ⭐⭐)

PYTHON
import numpy as np

a = np.arange(12, dtype=np.int64)
b = a.reshape(3, 4)

print(a.shape, b.shape)       # (12,) (3, 4)
print(a.strides, b.strides)   # (8,) (32, 8)
print(a.nbytes, b.nbytes)     # 96 96

b[0, 0] = 999
print(a[0])  # 999 — نفس الذاكرة!
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.




22. مثال شامل: تحليل متعمق لمصفوفة ثلاثية الأبعاد

▶ مثال

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

: تحليل كامل لخصائص مصفوفة 3×4×2 (الصعوبة ⭐⭐⭐)

PYTHON
import numpy as np

a = np.arange(24, dtype=np.int64).reshape(3, 4, 2)

print("=== المصفوفة الكاملة ===")
print(a)
---
## 23. [[[ 0  1]
---
##   24. [ 2  3]
---
##   25. [ 4  5]
---
##   26. [ 6  7]]
---
##  27. [[ 8  9]
---
##   28. [10 11]
---
##   29. [12 13]
---
##   30. [14 15]]
---
##  31. [[16 17]
---
##   32. [18 19]
---
##   33. [20 21]
---
##   34. [22 23]]]

print(f"ndim:    {a.ndim}")     # 3
print(f"shape:   {a.shape}")    # (3, 4, 2)
print(f"size:    {a.size}")     # 24
print(f"dtype:   {a.dtype}")    # int64
print(f"itemsize:{a.itemsize}") # 8
print(f"nbytes:  {a.nbytes}")   # 192  (24 * 8)
print(f"strides: {a.strides}")  # (64, 16, 8)
---
## 35. المحور 0: 4*2*8 = 64 بايت لكل خطوة
---
## 36. المحور 1: 2*8   = 16 بايت لكل خطوة
---
## 37. المحور 2: 1*8   = 8  بايت لكل خطوة

---
## 38. تحقق يدوي من الخطوات
expected_strides = (
    a.shape[1] * a.shape[2] * a.itemsize,  # 4*2*8 = 64
    a.shape[2] * a.itemsize,                # 2*8   = 16
    a.itemsize                               # 8
)
print(f"الخطوات اليدوية: {expected_strides}")  # (64, 16, 8)
print(f"تطابق: {a.strides == expected_strides}")  # True

---
## 39. تقليل المحاور
print(a.sum(axis=0).shape)  # (4, 2)
print(a.sum(axis=1).shape)  # (3, 2)
print(a.sum(axis=2).shape)  # (3, 4)
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل NumPy 2.x في بيئة Python المحلية لديك لرؤية مخرجات ndarray. خادم Piston لا يحتوي على NumPy مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install numpy`) وقارن. قد تختلف القيم الفعلية حسب إصدار NumPy والبذرة العشوائية.
⚠️ ملاحظة: الكود أدناه يحتاج إلى التشغيل في بيئة Python محلية.




❓ أسئلة شائعة

س هل يمكن لـ ndarray تخزين أنواع مختلفة؟
ج لا. ndarray متجانس — يجب أن تشترك جميع العناصر في نفس dtype. إذا حاولت خلط الأنواع، سيقوم NumPy بالرفع التلقائي (مثل int → float). الأنواع غير المتوافقة ستؤدي إلى خطأ.
س أي محور هو الصف — axis=0 أم axis=1؟
ج في مصفوفة ثنائية الأبعاد، axis=0 هو اتجاه الصفوف (عبر الصفوف)، و axis=1 هو اتجاه الأعمدة (عبر الأعمدة). الجمع على طول axis=0 "يضغط الصفوف في صف واحد"؛ الجمع على طول axis=1 "يضغط الأعمدة في عمود واحد."
س ما هي الخطوات (strides)؟
ج الخطوات هي مجموعة تشير إلى عدد البايتات التي يجب تخطيها في الذاكرة للتحرك خطوة واحدة على طول كل محور. هي المفتاح لكيفية قدرة ndarray على إعادة التشكيل/التحويل دون نسخ البيانات.
س ما الفرق بين float64 و float32؟
ج float64 يأخذ 8 بايت بدقة ~15 رقمًا عشريًا؛ float32 يأخذ 4 بايت بدقة ~7 أرقام. float32 يستخدم نصف الذاكرة لكن دقته أقل. التعلم العميق يستخدم عادة float32، بينما الحوسبة العلمية تستخدم عادة float64.
س لماذا يُسمى ndarray "متجانسًا"؟
ج لأن جميع العناصر معبأة بإحكام في الذاكرة، كل منها يأخذ نفس عدد البايتات ويُفسر بنفس الطريقة (يحددها dtype المشترك). هذا يسمح لوحدة المعالجة المركزية بمعالجة عناصر متعددة في وقت واحد بتعليمات متجهة — السبب الأساسي لأداء NumPy العالي.

📖 ملخص



📝 تمارين

  1. مبتدئ (الصعوبة ⭐): أنشئ أربع مصفوفات بطول 5000 بأنواع int8 و int32 و float32 و float64. اطبع nbytes لكل مصفوفة واشرح لماذا تستخدم الأنواع المختلفة كميات مختلفة من الذاكرة.

  2. متوسط (الصعوبة ⭐⭐): بمعلومية ndarray بـ shape=(5, 3, 2) و dtype=int16، احسب خطواتها و nbytes يدويًا، ثم تحقق من حسابك بالكود.

  3. متقدم (الصعوبة ⭐⭐⭐): اشرح بكلماتك الخاصة كيف يتم ترتيب ndarray بـ shape=(2,3,4) في الذاكرة. ارسم مخططًا، وسم الخطوات، وأظهر إزاحة الذاكرة لكل عنصر.

Web-Tutorial.com

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

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

100%