Array indexing (אינדוקס במערכים)#
ל־NumPy יש כמה דרכים לגשת לטווח אינדקסים במערכים.
Slicing (פריסה)#
בדומה לרשומות בפייתון, גם מערכים ניתנים לפריסה (slice). מאחר שמערכים יכולים להיות רב־ממדיים, יש לציין פריסה לכל ממד.
ניצור מערך בגודל 3x4, כלומר שלוש שורות וארבעה עמודות:
import numpy as np
# Create the following rank 2 array with shape (3, 4)
a = np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12]])
חיתוך (Slicing) של מערך#
נשתמש ב־slicing כדי לבחור תת־מערך: שתי השורות הראשונות (אינדקסים 0 ו־1) ועמודות 1 ו־2 (האינדקסים האמצעיים).
# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
b = a[:2, 1:3]
קשר בין מערך ותת־מערך#
חשוב לדעת: חיתוך במערכים של NumPy מחזיר מבט (View) אל הנתונים המקוריים, ולא עותק. לכן שינוי בתת־מערך ישפיע על המערך המקורי.
# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1])
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1])
2
77
ניתן לשלב אינדוקס עם פריסה. שילוב כזה מפיק מערך בדרגה נמוכה יותר מהמקור.
אינדוקס של שורות: Rank 1 לעומת Rank 2#
כאשר משלבים אינדוקס עם מספר שלם וחיתוך, מתקבלת שורה בייצוג חד־ממדי (Rank 1). כאשר משתמשים רק בפריסה (slice), נשמרת הדרגה המקורית (Rank 2) ולכן מקבלים עדיין מערך דו־ממדי.
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print(row_r1, row_r1.shape)
print(row_r2, row_r2.shape)
[5 6 7 8] (4,)
[[5 6 7 8]] (1, 4)
אינדוקס של עמודות: Rank 1 לעומת Rank 2#
אותו עיקרון חל גם על עמודות:
אינדוקס עם מספר שלם יחזיר וקטור חד־ממדי.
שימוש בפריסה ישאיר את העמודה כתת־מערך דו־ממדי.
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape)
print(col_r2, col_r2.shape)
[77 6 10] (3,)
[[77]
[ 6]
[10]] (3, 1)
Integer array indexing (אינדוקס במערך באמצעות מספרים שלמים)#
בעת פריסה מתקבל תמיד תת־מערך. אינדוקס בעזרת מערכי מספרים שלמים מאפשר לבנות מערך חדש מאיברים שרירותיים של מערך אחר.
ניצור מערך בגודל 3x2, כלומר שלוש שורות ושתי עמודות:
import numpy as np
a = np.array([[1,2],
[3, 4],
[5, 6]])
print(a)
[[1 2]
[3 4]
[5 6]]
ניתן לבחור איברים ממקומות שונים במערך בו־זמנית, באמצעות מתן רשימות של אינדקסים. התוצאה היא מערך חדש שבו מופיעים הערכים שנבחרו לפי המיקומים שצוינו.
print(a[[0, 1, 2],
[0, 1, 0]])
[1 4 5]
התוצאה הקודמת זהה לבחירה ידנית של אותם איברים אחד־אחד, אך כאן עושים זאת בפקודה אחת.
print(np.array([a[0, 0], a[1, 1], a[2, 0]]))
[1 4 5]
באמצעות אינדוקס שלם אפשר גם לבחור את אותו איבר מספר פעמים, ולבנות ממנו מערך חדש.
print(a[[0, 0], [1, 1]])
[2 2]
גם כאן, אפשר לכתוב את אותו הדבר בעזרת גישה רגילה לכל איבר, ולבנות ידנית מערך חדש.
print(np.array([a[0, 1], a[0, 1]]))
[2 2]
טריק נפוץ: לבחור/לעדכן איבר אחד מכל שורה באמצעות אינדקסים#
נבנה מערך בגודל 4x3 (ארבע שורות ושלושה עמודות):
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
נגדיר מערך של אינדקסים (b) שאומר לנו איזה עמודה לבחור בכל שורה. במקרה הזה: בשורה הראשונה נבחר את העמודה ה־0, בשנייה את ה־2, בשלישית שוב את ה־0, וברביעית את ה־1.
b = np.array([0, 2, 0, 1])
השילוב a[np.arange(4), b] מאפשר לבחור איבר אחד מכל שורה:
np.arange(4)מייצר את הרשימה[0,1,2,3]- כלומר את כל השורות.bנותן את האינדקס של העמודה המתאימה בכל שורה.
ביחד מתקבלים ארבעה איברים - אחד מכל שורה.
print(a[np.arange(4), b])
[ 1 6 7 11]
ניתן גם לעדכן ישירות את אותם איברים שנבחרו, למשל להוסיף להם 10. כיוון שמדובר בגישה ישירה לנתוני המערך, השינוי מתבצע בתוך המערך המקורי.
a[np.arange(4), b] += 10
print(a)
[[11 2 3]
[ 4 5 16]
[17 8 9]
[10 21 12]]
Boolean array indexing (אינדוקס בוליאני)#
מאפשר לבחור איברים שמקיימים תנאי.
נבנה מערך בגודל 3x2:
import numpy as np
a = np.array([[1,2],
[3,4],
[5,6]])
print(a)
[[1 2]
[3 4]
[5 6]]
נשתמש במסיכה בוליאנית (Boolean Mask). נבדוק אילו איברים במערך גדולים מ־2. התוצאה היא מערך חדש באותו גודל, המכיל ערכי True/False לפי התנאי.
bool_idx = (a > 2)
print(bool_idx)
[[False False]
[ True True]
[ True True]]
כאשר משתמשים במערך הבוליאני כאינדקס, מתקבל מערך חד־ממדי עם כל האיברים עבורם התנאי מתקיים.
print(a[bool_idx])
[3 4 5 6]
ניתן לבצע את כל השלבים יחד בשורה אחת, על ידי הכנסת התנאי ישירות לאינדוקס.
print(a[a > 2])
[3 4 5 6]