שימו לב: על מנת להריץ את התאים ב-Live Code, יש לייבא תחילה את ספריית numpy ע”י הרצת השורת הבאה:
import numpy as np
אתחול מערכים ב-numpy#
טקסט המופיע למטה בסגול מציין קטעים המופיעים בסרטון
ניתן להיעזר בו כדי לחזור על התכנים או לעיין בהם שוב.
האובייקט המרכזי בספריית numpy הוא מערך רב־ממדי (ndarray), או np.array.
המערך הוא מבנה נתונים הומוגני, כלומר כל האיברים שבו הם מאותו טיפוס. למשל, כולם מספרים שלמים או כולם שברים עשרוניים.
ניתן לחשוב על מערך גם כוקטור חד מימדי או כמטריצה של איברים (בדרך כלל מספרים).
ניתן לייצג במערכי numpy גם מבנים רב מימדיים כמו מטריצה תלת מימדית, אך לא נעסוק בכך במסגרת נושא זה.
בחלק זה נכיר דרכים שונות ליצור מערכים חדשים, ונלמד מעט פעולות אריתמתיות שניתן לבצע על מערכים כאלו.
יצירת מערך חדש#
באופן אינטואיטיבי, ניתן ליצור מערך על ידי המרה מרשימה (וקטור חד מימדי) או מרשימה מקוננת (מטריצה):
a = np.array([0, 1])
print('a is:' , a)
b = np.array([[1, 2 , 3], [4, 5, 6]])
print('b is: \n' , b)
c = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
print('c is: \n' , c)
a is: [0 1]
b is:
[[1 2 3]
[4 5 6]]
c is:
[[0.1 0.2 0.3]
[0.4 0.5 0.6]]
שימו לב
כדי ליצור ndarray שמייצג מטריצה, צריך לוודא שכל הרשימות המקוננות בעלות אורך זהה. אחרת, לא נקבל מטריצה.
פעולות אריתמטיות פשוטות#
בהנתן 2 מטריצות בעלות אותם מימדים, ניתן להפעיל עליהן פעולות אריתמטיות. לדוגמא, חיבור שתי מטריצות cell by cell מתבצע על-ידי פעולת החיבור.
b = np.array([[1, 2 , 3], [4, 5, 6]])
c = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
print(b+c)
[[1.1 2.2 3.3]
[4.4 5.5 6.6]]
שימו לב!
פעולת חיבור בין שתי מטריצות מוגדרת אך אם המימדים זהים.
אם ננסה לבצע חיבור על שתי מטריצות בעלות מימדים שונים, הפעולה תכשל:
a = np.array([0, 1])
b = np.array([[1, 2 , 3], [4, 5, 6]])
print(a+b)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[6], line 3
1 a = np.array([0, 1])
2 b = np.array([[1, 2 , 3], [4, 5, 6]])
----> 3 print(a+b)
ValueError: operands could not be broadcast together with shapes (2,) (2,3)
יוצא דופן לכך הוא מקרה בו מחברים וקטור (חד מימדי) עם מטריצה שאורך שורותיה (כלומר, מס’ העמודות) זהה לאורך הוקטור: לפעולה כזו קוראים גם broadcasting.
b = np.array([[1, 2 , 3], [4, 5, 6]])
d = np.array([10,10,10])
print(b+d)
[[11 12 13]
[14 15 16]]
דרכים נוספות ליצירת מערכים#
מעבר להמרה מרשימות, קיימות פונקציות שמסייעות לנו לאתחל מערך חדש בצורה פשוטה.
שתי פונקציות נפוצות המשמשות לצורך זה הן zeros ו-ones, המקבלות כארגומנט ראשון את מימדי הוקטור או המטריצה שרוצים לאתחל.
print(np.zeros(7))
[0. 0. 0. 0. 0. 0. 0.]
אם נרצה ליצור מטריצה, נעביר tuple של מימדי המטריצה (מספר השורות ומספר העמודות). שימו לב לסוגריים הנוספים עבור ה-tuple.
print(np.ones((2,5)))
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
שימו לב!
הנקודות שמופיעות אחרי האפסים רומזות לנו שהערכים במטריצה הם מטיפוס float.
אם נרצה לשנות את איתחול המטריצה כך שתכיל ערכים מטיפוס אחר, נגדיר לפונקציה את הפרמטר dtype. לדוגמא, באתחול המטריצה להלן:
print(np.ones((2,3), dtype=int))
[[1 1 1]
[1 1 1]]
עצרו וחישבו: מה אם נרצה לאתחל את המטריצה במספר קבוע, שאינו 0 או 1? הרי לא הגיוני לממש twos, threes וכן הלאה.
הדרך הכי אינטואיטיבית (למי שנושם אלגברה ליניארית), הוא להשתמש בכפל מטריצה במספר (סקלאר):
3.17*np.ones((3,2))
מערכים לא אחידים#
נניח שנרצה לייצר מערך שמייצג סדרה של מספרים.
היינו יכולים ליצור רשימה המכילה סדרה זו ולהעביר אותה לnp.array.
עצרו וחישבו: כיצד הייתם יוצרים סדרה של מספרים?
באמצעות range כמובן!
נזכיר כי הקלט לrange הוא אינדקס ההתחלה (כולל), אינדקס הסיום (לא כולל) והקפיצה של כל צעד בסדרה.
מסתבר ש-numpy מימשו עבורנו כבר פונקציה דומה בשם arange המבצעת פעולה דומה וחוסכת לנו את פעולת ההמרה:
print(np.arange(1, 10, 1))
[1 2 3 4 5 6 7 8 9]
לעומת range שראינו, באמצעות arange ניתן ליצור סדרות עם מספרים שבריים (float):
print(np.arange(1.5, 2.5, 0.1))
[1.5 1.6 1.7 1.8 1.9 2. 2.1 2.2 2.3 2.4]
מערכים עם מספרים אקראיים#
כעת נראה איתחול של וקטורים ומטריצות עם ערכים אקראיים.
באמצעות np.random.random, אשר מקבלת tuple המייצג את מימדי המטריצה, ניתן לאתחל ערכים אקראיים שבריים בין 0 ל-1.
rand_arr=np.random.random((2,5))
print(rand_arr)
[[0.73428763 0.00970003 0.83290801 0.116219 0.48874271]
[0.07470792 0.97817039 0.24542713 0.72107082 0.03691685]]
נסו בעצמכם
הריצו את התא למעלה בשנית. האם קיבלתם את אותם מספרים?
ואיך נוכל ליצור מערכים אקראיים בטווח מספרים אחר?#
באמצעות כפל בסקלאר ניתן “למתוח” או “לכווץ” את הטווח.
print(rand_arr*2)
[[1.46857526 0.01940006 1.66581601 0.23243799 0.97748543]
[0.14941583 1.95634078 0.49085426 1.44214164 0.07383371]]
print(rand_arr*0.5)
[[0.36714381 0.00485002 0.416454 0.0581095 0.24437136]
[0.03735396 0.48908519 0.12271357 0.36053541 0.01845843]]
ובאמצעות הוספת סקלאר ניתן “להזיז” את טווח הערכים.
print(-4+rand_arr)
[[-3.26571237 -3.99029997 -3.16709199 -3.883781 -3.51125729]
[-3.92529208 -3.02182961 -3.75457287 -3.27892918 -3.96308315]]
למעשה, ע”י הוספת והכפלה ניתן להגיע לכל טווח שנרצה. לדוגמא:
print(3+rand_arr*0.2)
[[3.14685753 3.00194001 3.1665816 3.0232438 3.09774854]
[3.01494158 3.19563408 3.04908543 3.14421416 3.00738337]]
נסו בעצמכם! צרו מערך בעל 3 שורות ו2 עמודות המכיל ערכים אקראיים בטווח 10-12:
# Write your code here
לחצו כאן כדי לצפות בפתרון
rand_arr=np.random.random((3,2))
print(rand_arr*2 + 10)
ואם נרצה ערכים רנדומליים שלמים? לצורך כך, נוכל להשתמש np.random.randint.
כאן, הערכים הראשונים שנעביר מייצגים את טווח המספרים השלמים מהם נרצה להגריל את המספר האקראי שלנו: המספר הראשון הוא תחילת הטווח (כולל), והשני סוף הטווח (לא כולל).
הפרמטר השלישי הוא טאפל המייצג את מימדי הוקטור/מטריצה.
print(np.random.randint(0,7,(5,2)))
[[1 1]
[4 0]
[1 1]
[3 0]
[2 5]]