6.3. יצירת מערכים#
כל דוגמה בשאר העמודים האלה מתחילה עם ndarray שכבר נמצא בידינו. עמוד זה הוא הקטלוג של איך מערך זה נוצר. יש ארבע משפחות של בנאים:
מתוך איטרבל של Python – הצורה הרגילה של ליטרל / רשימה / tuple.
מלא מראש בצורה נתונה – אפסים, אחדים, ערך קבוע, מטריצת יחידה.
מיוצר כסדרה – ערכים בטווח או במרווח אחיד.
עטיפת חוצץ שכבר נמצא ב-RAM – מקרה ההתקן ההיקפי.
כל בנאי מקבל מילת מפתח dtype= ובברירת מחדל הוא float. נתוני חיישן כמעט תמיד רוצים dtype קטן יותר מברירת המחדל.
כל דוגמה למטה מתחילה ב:
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 הוא מספר שלם בודד (עבור מערך חד-ממדי) או tuple.
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() מחבר tuple של מערכים לאורך ציר קיים:
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)
כל הקלטים חייבים לחלוק את אותו dtype ו-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. הבתים שההתקן ההיקפי כתב הם המערך.
כאשר התקן היקפי כותב ערכים רבי-בתים בסדר בתים שה-CPU של המצלמה אינו קורא באופן טבעי, byteswap() הופך את סדר הבתים של כל איבר כך שהערכים נקראים נכון. הוא מחזיר מערך חדש כברירת מחדל; העברת inplace=True משנה את המקור במקום.
frombuffer() מטפל רק ב-dtypes ש-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.