6.3. إنشاء المصفوفات¶
كل مثال في بقية هذه الصفحات يبدأ بوجود ndarray جاهزة في اليد. وهذه الصفحة هي فهرس كيفية نشوء تلك المصفوفة. وهناك أربع عائلات من المُنشئات:
من كائن قابل للتكرار في Python -- الصيغة الحرفية / القائمة / الصف المعتادة.
مملوءة مسبقًا بشكل معطى -- أصفار، أو آحاد، أو قيمة ثابتة، أو مصفوفة وحدة.
مولّدة كمتتالية -- قيم ضمن نطاق أو متباعدة بالتساوي.
تغليف مخزن مؤقت موجود بالفعل في RAM -- حالة الطرفية.
كل مُنشئ يأخذ كلمة مفتاحية dtype= ويكون افتراضه float. وبيانات المستشعر تتطلب دائمًا تقريبًا نوع بيانات أصغر من الافتراضي.
كل مثال أدناه يبدأ بـ:
from ulab import numpy as np
6.3.1. من كائن قابل للتكرار في Python¶
يبني array() مصفوفة ndarray من أي كائن أرقام قابل للتكرار:
a = np.array([1, 2, 3, 4])
print(a)
الخرج:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
تنتج الكائنات القابلة للتكرار المتداخلة مصفوفات متعددة الأبعاد. ويجب أن يكون لجميع الكائنات الداخلية القابلة للتكرار نفس الطول، وإلا أُطلق ValueError
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
تُعد مصفوفة ndarray موجودة مسبقًا مدخلًا صالحًا أيضًا؛ وarray() تنسخ دائمًا. ولتجنّب النسخ عند عدم الحاجة إليه، استخدم asarray()
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. مملوءة مسبقًا بشكل معطى¶
عندما يكون الشكل الهدف معروفًا ولكن المحتويات لم تتحدد بعد، خصّص المخزن المؤقت مسبقًا واكتب فيه لاحقًا:
zeros()-- مملوءة بالأصفار.ones()-- مملوءة بالآحاد.full()-- مملوءة بقيمة معطاة.empty()-- اسم مرادف لـzeros()(لا يتركulabالمخزن المؤقت غير مُهيّأ).eye()-- مصفوفة شبيهة بمصفوفة الوحدة بحجمNفيMمع آحاد على القطر رقمk.diag()-- مصفوفة قطرية من متجه، أو قطر مصفوفة.
np.zeros((3, 3)) # 3x3 of zeros
np.ones(5, dtype=np.uint8) # length-5 vector of ones
np.full((2, 3), 7, dtype=np.int8) # 2x3, all 7
np.eye(4) # 4x4 identity
np.diag([1, 2, 3]) # 3x3, [1, 2, 3] on the diagonal
وسيط shape هو إما عدد صحيح واحد (لمصفوفة أحادية البعد) أو صف.
6.3.3. مولّدة كمتتالية¶
arange()-- قيم متباعدة بالتساوي مثلrange()المدمجة، لكنها تعيد دائمًا مصفوفةndarraynp.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()-- عددnumمن النقاط المتباعدة بالتساوي بين حدّين، مع تضمين الحد الأعلى عندما يكونendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()-- نقاط متباعدة هندسيًا. القيمتانstartوstopهما أُسّان، وليستا نقطتي نهاية؛ تمتد النتيجة منbase ** startإلىbase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()-- يبني مصفوفتي إحداثيات من مصفوفتين أحاديتي البعد بحيث يمكن تقييم دالة لكل بكسلf(x, y)على شبكة كاملة في استدعاء واحد متجهي. وبالنظر إلى متجه x بطولWومتجه y بطولH، يعيدmeshgridمصفوفتين بحجمHفيW:Xهي متجه x مكررًا أسفل كل صف، وYهي متجه y مكررًا عبر كل عمود، بحيث تكونX[i, j]هي إحداثي x وY[i, j]هي إحداثي y للخلية عند الصفiوالعمودjx = np.arange(4) # [0, 1, 2, 3] y = np.arange(3) # [0, 1, 2] X, Y = np.meshgrid(x, y) # X = [[0, 1, 2, 3], # [0, 1, 2, 3], # [0, 1, 2, 3]] # Y = [[0, 0, 0, 0], # [1, 1, 1, 1], # [2, 2, 2, 2]]
ثم تقيّم
f(X, Y)الدالة عند كل خلية من الشبكة في تعبير واحد. فخريطة المسافة من المركز عبر إطار(H, W)، على سبيل المثال، هيnp.sqrt((X - cx)**2 + (Y - cy)**2)مقابل المصفوفتين اللتين أعادتهماmeshgrid().
6.3.4. الدمج¶
تدمج concatenate() صف مصفوفات على طول محور موجود:
a = np.array([[1, 2], [3, 4]], dtype=np.uint8)
b = np.array([[5, 6]], dtype=np.uint8)
np.concatenate((a, b), axis=0)
# array([[1, 2], [3, 4], [5, 6]], dtype=uint8)
يجب أن تشترك جميع المدخلات في نفس نوع البيانات ونفس ndim، وأن تتطابق على كل محور عدا محور الدمج. وتخصّص concatenate() مصفوفة جديدة كبيرة بما يكفي لاحتواء كل مدخل وتنسخ البيانات فيها، لذا فهي الأداة المناسبة للدمج لمرة واحدة لمصفوفات موجودة بالفعل؛ وهي الأداة الخاطئة داخل حلقة بثّ، حيث يكون النمط هو تخصيص الوجهة مسبقًا مرة واحدة والكتابة فيها عبر إسناد الشرائح.
6.3.5. تغليف مخزن مؤقت موجود¶
أكثر المُنشئات فائدة على الكاميرا هو frombuffer(). فهو يعيد تفسير مخزن مؤقت موجود شبيه بالبايتات على أنه ndarray أحادية البعد دون نسخ بايت واحد:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
الكتابة عبر audio تكون مرئية في buf والعكس صحيح. ويجب أن يقسم نوع dtype المختار طول المخزن المؤقت بالتساوي.
يتخطى offset= ترويسة في بداية المخزن المؤقت؛ ويحدّ count= من عدد العناصر التي تُقرأ:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
هذا هو المُنشئ المناسب كلما سلّمت طرفية للتطبيق مخزنًا مؤقتًا خامًا -- عينات ADC في bytearray، أو حمولة مسحوبة من SPI. فالبايتات التي كتبتها الطرفية هي المصفوفة.
عندما تكتب طرفية قيمًا متعددة البايتات بترتيب بايتات لا تقرؤه وحدة المعالجة المركزية في الكاميرا بشكل أصلي، تعكس byteswap() ترتيب بايتات كل عنصر بحيث تُقرأ القيم بشكل صحيح. وتعيد مصفوفة جديدة افتراضيًا؛ ويؤدي تمرير inplace=True إلى تعديل المصدر في مكانه.
تتعامل frombuffer() فقط مع أنواع البيانات التي يعرّفها numpy نفسه. وبالنسبة للطرفيات التي تنتج عينات أعداد صحيحة بطول 32 بت، تحوّل from_int32_buffer() وما شابهها إلى float في تمريرة واحدة.
6.3.6. اقتطاع الطباعة¶
تُظهر طباعة مصفوفة كبيرة عناصرها الأولى والأخيرة القليلة فقط، مع ... في المنتصف، بحيث لا تمتلئ طرفية IDE بآلاف القيم:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
تتجاوز set_printoptions() العتبات عندما يتطلب تنقيح الأخطاء عرض المخزن المؤقت بالكامل:
np.set_printoptions(threshold=2000) # print up to 2000 elements in full
np.set_printoptions(edgeitems=10) # 10 items at each end, not 3
تقرأ get_printoptions() الإعدادات الحالية كقاموس (dict).