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



NumPy



פעולות בסיסיות

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

>>> a = np.arange(0,10,2)

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

>>> a+1
array([1, 3, 5, 7, 9])

>>> a**2
array([ 0,  4, 16, 36, 64], dtype=int32)

>>> b = np.linspace(1,5,5)

>>> b
array([1., 2., 3., 4., 5.])

>>> c = a - b

>>> c
array([-1.,  0.,  1.,  2.,  3.])

>>> c > 0
array([False, False,  True,  True,  True])

ישנם פעולות שמבוצעות ישירות על אותה מטריצה בלי ליצור מטריצה חדשה. למשל:
>>> a += b
>>> a *= 3

גם פעולת כפל מתבצעת פר אלמנט.
ואם רוצים לעשות כפל מטריצות צריך להשתמש בפונקציית dot. ב-Python גירסה 3.5 ומעלה ניתן להשתמש גם בסימן @ לצורך כפל מטריצות.


>>> a = np.array( [[1,0],
                   [2,3]] )

>>> b = np.array( [[0,2],
                   [1,4]] )

>>> a * b
array([[ 0,  0],
       [ 2, 12]])

>>> a.dot(b)
array([[ 0,  2],
       [ 3, 16]])

>>> a@b
array([[ 0,  2],
       [ 3, 16]])

כאשר עושים פעולות על בין מטריצות מסוגים שונים, התוצאה תהיה מטריצה מהסוג היותר כללי או היותר מדויק (זה נקרא upcasting):


>>> a = np.ones(3, dtype=int)

>>> b = np.linspace(0, 3.5, 3)

>>> b
array([0.  , 1.75, 3.5 ])

>>> b.dtype
dtype('float64')

>>> c = a + b

>>> c
array([1.  , 2.75, 4.5 ])

>>> c.dtype
dtype('float64')


פונקציות אוניברסליות - universal functions

הפונקציות sin, cos, exp נקראות Universal functions (או בקיצור ufunc) והן שייכות למחלקה numpy.ufunc. הפעולות מתבצעות פר אלמנט. יש במחלקה עוד פונקציות רבות וניתן לראות אותן כאן.

אינדקסים, חיתוכים ואיטרציות

מערך חד ממדי דומה מאוד ל-list ב-Python מבחינת האינדוקס שלו, ופעולות החיתוך עליו. 
אם למשל יש לנו מערך a: 
array[1,2,3,4,5,6,7,8,9]
אז:
a[2] -> 3
האיבר במקום 2. (המקום השלישי במערך כי האינדקס מתחיל מאפס)

a[2:5] -> 3,4,5
האיברים במקומות 2 עד 4 (האינדקס ההתחלתי כלול, האינדקס הסופי לא כלול)


a[1:6:2] -> 2,4,6
האיברים ממקום 1 עד מקום 6 (לא כולל 6) בדילוגים של 2 (1,3,5)

a[ :6:2] -> 1,3,5
האיברים ממקום 0 עד מקום 6 (לא כולל 6) בדילוגים של 2 (0,2,4)

a[ : :-1] -> 9,8,7,6,5,4,3,2,1
כל האיברים מהסוף להתחלה


מעבר על איברי המערך באיטרציות:
for i in a:
    print(i)
כל איטרציה i יהיה האיבר הבא במערך

במערך רב ממדי מתייחסים לכל מימד באינדקס משלו.
אם למשל יש לנו מערך b: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9,  10, 11],
       [ 12, 13, 14, 15],
       [ 16, 17, 18, 19]])
אז:
b[2,3] -> 11
האיבר בשורה 2 עמודה 3


b[0:2,2] -> 2,6
האיברים במקומות 0 עד 2 (לא כולל 2) בעמודה 2


b[1,:] -> 4,5,6,7
כל האיברים משורה 1

b[::2,1] -> 1,9,17
כל האיברים מעמודה 1 בדילוגים של 2 (0,2,4)

b[2,-1] -> 11
האיבר בשורה 2 עמודה אחרונה 

b[:,::-1] -> 
array([[ 3,  2,  1,  0],
       [ 7,  6,  5,  4],
       [11, 10,  9,  8],
       [15, 14, 13, 12],

       [19, 18, 17, 16]])


כל המערך בצורה הפוכה (העמודות מתחילות מהעמודה האחרונה ועד לראשונה) 

אם צוינו פחות אינדקסים ממספר המימדים, היחס למימדים החסרים יהיה כאילו ביקשנו את כל האיברים שלהם.
לדוגמה:
b[2] -> 8,9,10,11
כל שורה 2

b[-1] -> 16,17,18,19
כל השורה האחרונה
בעצם זה כאילו כתבנו: 
b[-1,:]
אם היו יותר מימדים זה היה כאילו כתבנו ":" עבור כל מימד נוסף. 
ניתן גם לכתוב זאת כך:
b[-1,...]

שלוש הנקודות מייצגות כמה נקודותיים שיש צורך לפי מספר המימדים. ולכן אם יש לנו 5 ממדים:
 b[...] is equivalent b
 b[2,...] is equivalent b[2,:,:,:,:]
 b[...,4] is equivalent b[:,:,:,:,4]
 b[3,...,4,:] is equivalent b[3,:,:,4,:]

מעבר על איברי המערך באיטרציות נעשה ביחס למימד הראשון:
for i in b:
    print(i)
בכל איטרציה i יהיה השורה הבאה (שזה האיבר הבא במימד הראשון שהוא השורות).


>>> for i in b:
       print(i)
    
[0 1 2 3]
[4 5 6 7]
[ 8  9 10 11]
[12 13 14 15]
[16 17 18 19]

כדי לעבור על כל האיברים במערך ניתן להשתמש בפונקציה flat:


>>> for i in b.flat:
       print(i)
    
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


שינוי מימדי המערך

לכל מערך יש משתנה שנקרא shape שמתאר את מימדי המערך. כל מימד מצוין לפי מספר האלמנטים שבו.
למשל עבור המערך a שנראה כך:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9,  10, 11]])
נקבל:
a.shape -> (3,4)

יש כמה פונקציות שמאפשרות שינוי של מימדי המערך. כל אחת מהן יוצרת מערך חדש ולא משנה את המערך הקיים.

פונקציית ravel משטחת את המערך למימד אחד:

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


הפונקציה reshape משנה את המימדים של המערך לפי הפרמטרים ששולחים אליה:
לדוגמה שינוי המערך a מ-(3,4)  ל-(6,2):


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


אם הפרמטר שאנו מבקשים עבור מימד מסוים הוא -1 גודל המימד יחושב אוטומטית:


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


הפונקציה T הופכת את המטריצה מ-(3,4)  ל-(4,3):


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


בשונה מהפונקציות האלו, הפונקציה resize משנה משנה את המערך עצמו:


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


שירשור מערכים

ניתן לשרשר מערכים. למשל אם המערכים שלנו הם:


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


שירשור בצורה אופקית ע"י הפונקציה hstack:


>>> np.hstack((a,b))
array([[1, 2, 5, 6],
       [3, 4, 7, 8]])

עבור מערכים עם יותר משני מימדים השירשור יתבצע למימד השני.

שירשור בצורה אנכית ע"י הפונקציה vstack:


>>> np.vstack((a,b))
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])


עבור מערכים עם יותר משני מימדים השירשור יתבצע למימד הראשון.

בכללי, 

הפונקציה column_stack מאפשרת שירשור של מערך חד-ממדי כעמודות למערך דו-ממדי:


>>> np.column_stack((a,c))
array([[1, 2, 7],
       [3, 4, 8]])

ולעומת זאת הפונקציה row_stack מאפשרת שירשור של מערך חד-ממדי כשורות למערך דו-ממדי:




>>> np.row_stack((a,c))
array([[1, 2],
       [3, 4],
       [7, 8]])

אם רוצים לשרשר למימד אחר מאשר הראשון והשני ניתן להשתמש בפונקציה שנקראת concatenate.



פיצול מערכים

ניתן לפצל מערך אחד לכמה מערכים. אם רוצים לפצל בצורה אופקית ניתן להשתמש בפונקציה hsplit. אפשר לקבוע לכמה חלקים המערך יתפצל, או לקבוע באיזה נקודות הוא יתפצל.
לדוגמה, פיצול מערך ל-4:


>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[7., 7., 8., 4., 1., 7., 7., 8., 0., 9., 9., 0.],
       [0., 2., 2., 6., 7., 4., 4., 1., 4., 9., 0., 0.]])

>>> np.hsplit(a,4)
[array([[7., 7., 8.],
        [0., 2., 2.]]), array([[4., 1., 7.],
        [6., 7., 4.]]), array([[7., 8., 0.],
        [4., 1., 4.]]), array([[9., 9., 0.],
        [9., 0., 0.]])]

פיצול מערך בעמודה 1 ובעמודה 6:


>>> np.hsplit(a,(1,6))
[array([[7.],
        [0.]]), array([[7., 8., 4., 1., 7.],
        [2., 2., 6., 7., 4.]]), array([[7., 8., 0., 9., 9., 0.],
        [4., 1., 4., 9., 0., 0.]])]

אם רוצים לפצל מערך בצורה אנכית ניתן לשתמש ב-vsplit. והפונקציה array_split מאפשרת פיצול מערך במימד מסוים לפי הצורך.







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

אין תגובות:

הוסף רשומת תגובה