ספריית NumPy - חלק 1

NumPy

מבוא

ספריית NumPy היא ספריית python מאוד נפוצה. ספריה זו נועדה לסייע בעבודה עם מערכים רב ממדיים. אובייקט NumPy הוא טבלה של אלמנטים, בד"כ מספרים, שכולם מאותו הסוג, מאונדקסים ע"י tuple של מספרים חיוביים. ב-NumPy מימדים נקראים axes. 
לדוגמה: למערך [1,4,5] יש מימד 1 ואורך 3.
למערך הבא: 
[[1,4,2],
 [3,2,7]]
יש 2 מימדים. למימד הראשון יש אורך של 2 ולמימד השני אורך של 3.


ndarray

המחלקה של מערך NumPy נקראת ndarray. ויש לה גם שם נרדף array. 
שים לב ש-numpy.array זה לא אותו דבר כמו המחלקה של python עבור מערך array.array.


משתנים עיקריים של ndarray

ndarray.ndim 
    מספר המימדים של המטריצה.

ndarray.shape 
    המימדים של המטריצה. מציג מהו הגודל של כל מימד במטריצה. עבור מטריצה עם n שורות ו-m עמודות נקבל shape של (n,m). אורך ה-shape הוא מספר המימדים, ndim.

ndarray.size
    מספר האלמנטים במטריצה. שווה בעצם למכפלה של אורכי המימדים שזה מכפלה של הערכים שקיבלנו ב-ndarray.shape

ndarray.dtype
    אובייקט שמתאר את סוג האלמנטים במטריצה. יכול להיות אלמנטים בסיסיים של python כמו int, float או מסוגים של numpy כמו numpy.int32, nympy.float64.

ndarray.itemsize
    הגודל של כל איבר במטריצה ב-bytes. למשל איבר מסוג float64 הוא 8 bytes.

ndarray.data
    זהו ה-buffer שמחזיק את הערכים של האיברים במטריצה. בד"כ אין צורך לגשת אליו ישירות.


פונקציות בסיסיות של ndarray

min 
    מחזיר את האלמנט המינימאלי


max
    מחזיר את האלמנט המקסימאלי


argmin 

    מחזיר את האינדקס של האלמנט המינימאלי


argmax
    מחזיר את האינדקס של האלמנט המקסימאלי

sum
     מחזיר את סכום האלמנטים

בכל הפונקציות האלו יש פרמטר אופציונאלי שנקרא axis שמאפשר חישוב במימד מסוים, וכך למשל לקבל את הסכום של כל שורה או כל עמודה, או מינימום ומקסימום לפי שורות, עמודות או מימד יותר גבוה.


>>> a = np.array ( [[1,2,3],
                    [4,5,6]])

>>> a.min()
1

>>> a.max()
6

>>> a.argmin()
0

>>> a.argmax()
5

>>> a.sum()
21

>>> a.sum(axis=0) # columns
array([5, 7, 9])

>>> a.sum(axis=1) # rows
array([ 6, 15])

יצירת מערך

ניתן ליצור מערך ישירות מ-list או tuple רגילים ע"י הפונקציה array. סוג האיברים נגזר מהמקור שממנו נוצר.

>>> import numpy as np
>>> a = np.array([1,9,4])
>>> a
array([1, 9, 4])
>>> a.dtype
dtype('int32')
>>> b = np.array([1.3, 4.0, 9.2])
>>> b.dtype
dtype('float64')

ניתן גם לקבוע במפורש מה יהיה סוג המטריצה:


>>> a = np.array([1,2],[3,4],dtype=float)
>>> a
array([1., 2., 3.])
>>> a.dtype
dtype('float64')

לפעמים יודעים מראש מה גודל המערך הדרוש אך לא ידוע מראש מה הערכים שהמערך יכיל. לצורך כך NumPy מאפשר ליצור מערך בגודל מסוים עם ערכים התחלתיים שלאחר מכן יוחלפו לפי הצורך, ובכך למנוע את הצורך להגדיל את המערך בצורה דינאמית שזו פעולה יקרה יחסית.
האפשרויות הן: zeros, ones, empty. סוג המידע הדיפולטיבי הוא float64. אבל גם פה ניתן לקבוע מה יהיה סוג המידע באופן מפורש.

zeros
    יצירת מערך של אפסים

ones
    יצירת מערך שכולו ערכים של אחד

empty
    יצירת מערך של ערכים רנדומאליים לפי מה שיש כרגע בזיכרון

random.rand

    יצירת מערך של ערכים רנדומאליים בין 0 ל-1


>>> a = np.zeros( (2,3) )

>>> a
array([[0., 0., 0.],
       [0., 0., 0.]])

>>> a.dtype
dtype('float64')

>>> b = np.ones( (2,2),dtype=np.int16)

>>> b
array([[1, 1],
       [1, 1]], dtype=int16)

>>> c = np.empty( (2,3) )

>>> c
array([[1.23918553e-311, 1.23916722e-311, 1.31585255e-047],
       [2.11161559e+257, 6.60925411e-062, 2.88067937e+214]])

>>> d = np.random.rand(2,2)

>>> d
array([[0.47693581, 0.71026692],
       [0.70636664, 0.56773883]])

ב-NumPy יש אפשרות ליצור מטריצה עם סדרה של ערכים (בדומה ל-range של Python):

arange
    יוצר מטריצה בטווח ערכים מסוים עם הפרשים שווים בין הערכים. מחזיר ndarray.
arange([start,] stop, [step,] dtype=None)

הדיפולט של start הוא 0. והדיפולט של step הוא 1. אם מציינים במפורש את step חייבים גם לציין את start. ה-dtype נגזר מתוך שאר הערכים שנשלחו לפונקציה.
שים לב: הערך stop לא נכלל. הערכים יגיעו עד אליו אבל לא כולל אותו (יש מקרים יוצאים מהכלל שהערך של ה-stop יכלל, וזה יכול לקרות רק במקרים שה-step הוא לא מספר שלם)


>>> a = np.arange(0, 25, 5)

>>> a
array([ 0,  5, 10, 15, 20])

>>> b = np.arange(1.1, 2, 0.3)

>>> b
array([1.1, 1.4, 1.7])

כשמשתמשים במספר מסוג float עבור step לא תמיד ניתן לדעת מראש כמה אלמנטים יהיו במטריצה. אם רוצים מספר אלמנטים מסוים עדיף להשתמש ב-linspace:

linspace
    יוצר מטריצה בטווח ערכים מסוים עם הפרשים שווים בין הערכים. מספר האיברים ניתן כ-input ולא ההפרש בין האיברים.

linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
ה-endpoint קובע האם ה-stop כלול או לא כלול.
לדוגמה:


>>> a = np.linspace(0, 10, 6)

>>> a
array([ 0.,  2.,  4.,  6.,  8., 10.])

>>> b = np.linspace(0, 10, 6, False)

>>> b
array([0. , 1.66666667, 3.33333333, 5. , 6.66666667, 8.33333333])

אם ה-retstep שווה ל-True הפונקציה תחזיר (samples, step) כשאר step הוא ההפרש בין האלמנטים.


>>> c = np.linspace(0, 10, 6, True, True)

>>> c
(array([ 0.,  2.,  4.,  6.,  8., 10.]), 2.0)

ה-axis מאפשר לקבל מטריצה עם כמה מימדים, לדוגמה:


>>> d = np.linspace([0,0], [10,20], 6, True, True, axis=1)

>>> d
(array([[ 0.,  2.,  4.,  6.,  8., 10.],
        [ 0.,  4.,  8., 12., 16., 20.]]), array([2., 4.]))

קיבלנו מטריצה דו-ממדית עם 2 שורות ו-4 עמודות. אפשרי רק אם start ו-stop הם מערכים. 
יש עוד הרבה אפשרויות, כמו להתחיל ממספר גדול ולהגיע למספר קטן, או כמו נקודת התחלה אחת והרבה נקודות סיום ואז מקבלים מטריצה דו-ממדית למשל:


>>> e = np.linspace(start=[5, 6, 14, 24], stop=1, num=5)

>>> e
array([[ 5.  ,  6.  , 14.  , 24.  ],
       [ 4.  ,  4.75, 10.75, 18.25],
       [ 3.  ,  3.5 ,  7.5 , 12.5 ],
       [ 2.  ,  2.25,  4.25,  6.75],
       [ 1.  ,  1.  ,  1.  ,  1.  ]])

הדפסת מטריצות

ההדפסה של מערך דו-ממדי היא משמאל לימין ומלמעלה למטה. אם יש מימדים נוספים הם יודפסו בשורה חדשה.


>>> a = np.arange(24).reshape(2,3,4)

>>> a
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

אם המטריצה גדולה מדיי, רק הקצוות יודפסו:


>>> b = np.arange(10000).reshape(100,100)

>>> b
array([[   0,    1,    2, ...,   97,   98,   99],
       [ 100,  101,  102, ...,  197,  198,  199],
       [ 200,  201,  202, ...,  297,  298,  299],
       ...,
       [9700, 9701, 9702, ..., 9797, 9798, 9799],
       [9800, 9801, 9802, ..., 9897, 9898, 9899],
       [9900, 9901, 9902, ..., 9997, 9998, 9999]])

כדי להדפיס את כל המערך ניתן לשנות את ההגדרות כך:


>>> np.set_printoptions(threshold=np.nan)



אם אהבתם, אשמח שתכתבו תגובה.

2 תגובות: