• 0

ما الفرق بين المصفوفات من نوع contiguous و non-contiguous في Numpy؟

أثناء قرائتي لأمثلة لمكتبة Numpy وجود الكود التالي:

>>> a = np.zeros((9, 3))
# A transpose make the array non-contiguous
>>> b = a.T

# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()

>>> c.shape = (27)
AttributeError: Incompatible shape for in-place modification. Use `.reshape()` to make a copy with the desired shape.

لكني لم أفهم ما الذي تعنيه مصفوفة non-contiguous؟ وما الفرق بينها وبين المصفوفات من نوع contiguous؟ ولماذا لا يمكن إستخدام الخاصية shape مع مصفوفات non-contiguous ويظهر الخطأ السابق؟

1 شخص أعجب بهذا

انشر على الشّبكات الاجتماعية


رابط هذه المساهمة
شارك على الشبكات الإجتماعية
  • 0

المصفوفة المتجاورة هي مصفوفة مخزنة في كتلة غير متقطعة في الذاكرة أي قيمها مخزنة بشكل متجاور، وبالتالي للوصول إلى العنصر التالي من المصفوفة، ننتقل فقط إلى عنوان الذاكرة التالي. ويشار لذلك بأن المصفوف C-order أي "C contiguous".

import numpy as np
# لنفرض لدينا المصفوفة التالية
arr = np.arange(8).reshape(4,2)
arr
# سيكون شكلها كالتالي
"""
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7]])
"""
# وفي الذاكرة ستكون مخزنة بالشكل التالي
# [0, 1, 2, 3, 4, 5, 6, 7]
# أي أن هذه المصفوفة هي مصفوفة متجاورة حيث أن الأسطر الخاصة بالمصفوفة مخزنة على شكل كتل متجاورة وليس منفصلة وبالتالي
# يحتوي عنوان الذاكرة التالي على قيمة الصف التالي في هذا الصف
# مثلاً إذا أردنا التحرك لأسفل، فنحن نحتاج فقط إلى القفز فوق كتلة واحدة
# أي مثلاً للانتقال من 0 ل 2 نحتاج فقط للقفز فوق القيمة 1
# 

أما منقول المصفوفة باستخدام array.T يؤدي إلى فقدان هذا التجاور بالنسبة للأسطر. ومع ذلك ، فإن arr.T هو Fortran متجاور لأن الأعمدة أصبحت موجودة في كتل متجاورة من الذاكرة. ومن ناحية الأداء، فغالباً ما يكون الوصول إلى عناوين الذاكرة المجاورة لبعضها البعض أسرع من الوصول إلى العناوين المتناثرة  فقد يستلزم جلب قيمة من ذاكرة الوصول العشوائي عددًا من العناوين المجاورة التي يتم جلبها وتخزينها مؤقتًا لوحدة المعالجة المركزية. يعني أن العمليات عبر المصفوفات المتجاورة ستكون غالباً أسرع.
ونتيجة لذلك فدوماً مانجد أن العمليات على الأسطر أسرع من العمليات على الأعمدة في المصفوفات. وبالمثل، ستكون العمليات على الأعمدة أسرع قليلاً بالنسبة لمصفوفات Fortran المتجاورة. أيضاً يجب أن تعلم أننا لا يمكننا تسطيح مصفوفة Fortran المتجاورة من خلال تعيين shape جديد أي:

import numpy as np
# لنفرض لدينا المصفوفة التالية
arr = np.arange(8).reshape(4,2)
arr
array=arr.T
array.shape=8
"""
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-17-a71f03f19106> in <module>()
      4 arr
      5 array=arr.T
----> 6 array.shape=8
AttributeError: Incompatible shape for in-place modification. Use `.reshape()` to make a copy with the desired shape.
"""

ولكي يكون هذا ممكناً ، يجب على NumPy وضع صفوف array.T معاً أي يجب أن يكون ترتيبهم في الذاكرة:

[0, 2, 4, 6,1, 3, 5, 7]

حيث أن بايثون يفترض عند تعيين shape جديد للمصفوفة أن المصفوفة تتبع C-order أي يحاول NumPy تنفيذ العملية على مستوى الصف. وبالتال هذا مستحيل القيام به. لأي محور، يحتاج NumPy إلى طول خطوة ثابت (عدد البايتات المراد نقلها) للوصول إلى العنصر التالي من المصفوفة. وبالتالي سيتطلب التسطيح  بهذه الطريقة التخطي للأمام وللخلف في الذاكرة لاسترداد القيم المتتالية للمصفوفة. والحل الوحيد هو استخدام reshape(8)  حيث يقوم NumPy بنسخ قيم array في كتلة جديدة من الذاكرة لأنه لا يمكنه إرجاع طريقة عرض view إلى البيانات الأصلية لهذا الشكل.

انشر على الشّبكات الاجتماعية


رابط هذه المساهمة
شارك على الشبكات الإجتماعية

يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن