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.