ברוכים הבאים ליחידת הלימוד "מבוא ל-NumPy"! יחידה זו מהווה את אבן היסוד לחישובים נומריים וניתוח נתונים בפייתון. נלמד כיצד NumPy, באמצעות מבנה הנתונים המרכזי שלו – מערכי ndarray רב-ממדיים – מאפשר לבצע פעולות מתמטיות מורכבות ביעילות ובמהירות חסרות תקדים, תוך התגברות על מגבלות הביצועים של רשימות פייתון רגילות. הבנה מעמיקה של עקרונות אלו חיונית לכל מי שעוסק במדעי הנתונים, למידת מכונה וחישוב מדעי.
מערכי ndarray: עמוד השדרה של NumPy
הליבה של ספריית NumPy היא אובייקט ה-ndarray (N-dimensional array), שהוא מבנה נתונים יעיל לאחסון ועיבוד מערכים הומוגניים (כלומר, כל האיברים הם מאותו טיפוס נתונים) רב-ממדיים. בניגוד לרשימות פייתון, מערכי ndarray מאוחסנים בזיכרון באופן רציף, מה שמאפשר גישה מהירה וביצועים אופטימליים.
יצירת מערכי ndarray
- מתוך רשימות פייתון:
np.array([1, 2, 3]) - מערכים מאופסים/אחדות:
np.zeros((2, 3)),np.ones((4,)) - טווחים:
np.arange(0, 10, 2),np.linspace(0, 1, 5) - נתונים אקראיים:
np.random.rand(2, 2)
תכונות חשובות של ndarray
.shape: טופל המייצג את מימדי המערך (לדוגמה:(3, 4)למערך 3x4)..ndim: מספר הממדים של המערך..dtype: טיפוס הנתונים של אלמנטי המערך (לדוגמה:int64,float32)..size: המספר הכולל של אלמנטים במערך.
מערך NumPy (ndarray)
יתרונות: יעילות בזיכרון, מהירות בביצוע פעולות מספריות (בזכות מימוש ב-C), תמיכה מובנית בפעולות וקטוריות, הומוגניות בטיפוס הנתונים.
חסרונות: קשיח יותר בגודלו וטיפוסו לאחר יצירה, פחות גמיש לאחסון טיפוסי נתונים שונים באותו מערך.
רשימת פייתון (Python List)
יתרונות: גמישות רבה (יכולה להכיל טיפוסי נתונים שונים), קלה לשינוי גודל.
חסרונות: פחות יעילה בזיכרון ובביצועים עבור חישובים מספריים גדולים (כל איבר הוא אובייקט פייתון נפרד), דורשת לולאות מפורשות לפעולות על כל האיברים.
פעולות וקטוריות ו-Universal Functions (ufuncs)
אחד היתרונות הגדולים ביותר של NumPy הוא היכולת לבצע פעולות על מערכים שלמים (או תתי-מערכים) מבלי לכתוב לולאות מפורשות בפייתון. פעולות אלו נקראות פעולות וקטוריות והן ממומשות ב-C, מה שמקנה להן מהירות עצומה.
דוגמאות לפעולות וקטוריות
- פעולות אריתמטיות: חיבור, חיסור, כפל, חילוק בין מערכים או בין מערך וסקלאר. לדוגמה:
arr1 + arr2,arr * 2. - פונקציות אוניברסליות (ufuncs): פונקציות הפועלות על כל אלמנט במערך. לדוגמה:
np.sqrt(arr),np.sin(arr),np.exp(arr).
Broadcasting
Broadcasting הוא מנגנון חזק ב-NumPy המאפשר לבצע פעולות אריתמטיות על מערכים בעלי צורות (shapes) שונות, בתנאי שצורות אלו תואמות לכללי Broadcasting מסוימים. זהו למעשה הרחבה "וירטואלית" של המערך הקטן יותר כדי להתאים למערך הגדול, מבלי לשכפל נתונים פיזית.
אינדוקס ופריסה (Indexing and Slicing)
גישה לאלמנטים או תתי-מערכים ב-NumPy דומה לאופן שבו אנו עושים זאת ברשימות פייתון, אך עם הרחבות לטיפול בממדים מרובים.
סוגי אינדוקס
- אינדוקס בסיסי: גישה לאלמנט יחיד (
arr[0],arr[1, 2]) או פריסה (arr[0:5],arr[:, 1]). - אינדוקס בוליאני: בחירת אלמנטים על בסיס תנאי לוגי. לדוגמה:
arr[arr > 5]יחזיר את כל האלמנטים הגדולים מ-5. - אינדוקס "Fancy": שימוש במערכי אינדקסים כדי לבחור אלמנטים לא רציפים. לדוגמה:
arr[[0, 2, 4]]יבחר את האלמנטים באינדקסים 0, 2 ו-4.
arr[0:5]), התוצאה היא לרוב view (תצוגה) של המערך המקורי, ולא עותק חדש. משמעות הדבר היא ששינוי ב-view ישפיע גם על המערך המקורי. לעומת זאת, אינדוקס "Fancy" או שימוש בפונקציה .copy() ייצרו עותק נפרד. חשוב להבין הבדל זה כדי למנוע באגים בלתי צפויים בטיפול בנתונים.ביצועים ויעילות
היתרון המרכזי של NumPy טמון בביצועים. על ידי שימוש במימושים בשפות כמו C ו-Fortran, ועל ידי הימנעות מלולאות פייתון איטיות, NumPy מספקת שיפור דרמטי במהירות החישובים המספריים, במיוחד עבור מערכי נתונים גדולים. אחסון נתונים בזיכרון באופן רציף גם תורם ליעילות הגישה והעיבוד.
- הימנעות מלולאות פייתון: פעולות וקטוריות מחליפות לולאות Python איטיות בלולאות ממוטבות ב-C.
- יעילות בזיכרון: אחסון הומוגני ורציף מפחית את צריכת הזיכרון בהשוואה לרשימות פייתון.
- בסיס למערכת האקולוגית: NumPy הוא הבסיס לספריות רבות אחרות במדעי הנתונים בפייתון, כמו Pandas, SciPy ו-Scikit-learn, המשתמשות במערכי ndarray כפורמט הנתונים המרכזי שלהן.
שאלות לדיון
- הסבר מדוע NumPy נחשבת ליעילה ומהירה יותר מרשימות פייתון לחישובים מספריים. ציין לפחות שני הבדלים מבניים ותפקודיים.
- נתון מערך NumPy
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]). כתוב קוד NumPy שיבחר את כל האלמנטים בשורה הראשונה שהם גדולים מ-1, ואת האלמנטים בעמודה השנייה. - הסבר את עקרון ה-Broadcasting ב-NumPy ותן דוגמה קצרה הממחישה כיצד הוא מאפשר פעולה בין מערך דו-ממדי לבין מערך חד-ממדי.
- מה ההבדל המהותי בין "view" ל-"copy" בפריסת מערכי NumPy, ומדוע הבנה זו קריטית למניעת באגים? תן דוגמה קוד קצרה שתמחיש את ההבדל.
נקודות לתשובת מודל
- NumPy vs. רשימות פייתון: NumPy משתמשת ב-ndarray (הומוגני, רציף בזיכרון, ממומש ב-C) לעומת רשימות פייתון (הטרוגניות, מצביעים לאובייקטים מפוזרים בזיכרון). פעולות וקטוריות ב-NumPy מהירות בהרבה מלולאות פייתון.
- אינדוקס ופריסה:
- אלמנטים בשורה הראשונה הגדולים מ-1:
arr[0][arr[0] > 1]אוarr[0, arr[0] > 1]. - אלמנטים בעמודה השנייה:
arr[:, 1].
- אלמנטים בשורה הראשונה הגדולים מ-1:
- Broadcasting: מאפשר פעולות בין מערכים עם צורות שונות על ידי הרחבה וירטואלית. לדוגמה: חיבור מטריצה (2D) לוקטור (1D) כאשר הוקטור תואם לאחד הממדים של המטריצה.
matrix + vector_rowאוmatrix + vector_column[:, np.newaxis]. - View vs. Copy:
- View: פריסה רגילה (לדוגמה:
sub_arr = arr[0:2]) יוצרת view. שינוי ב-sub_arrישנה אתarr. - Copy: אינדוקס "Fancy" (לדוגמה:
sub_arr = arr[[0, 1]]) או שימוש מפורש ב-.copy()(לדוגמה:sub_arr = arr[0:2].copy()) יוצרים עותק נפרד. שינוי ב-sub_arrלא ישפיע עלarr. - חשיבות: מניעת שינויים לא מכוונים בנתונים המקוריים.
- View: פריסה רגילה (לדוגמה: