שימו לב: על מנת להריץ את התאים ב-Live Code, יש לייבא תחילה את ספרית pandas ע”י הרצת השורת הראשונה בתא למטה.
בנוסף, נגביל את מספר השורות והעמודות שתופענה בהדפסת הטבלאות ע”י שורות הקוד השניה והשלישית:
import pandas as pd
pd.options.display.max_rows=5
pd.options.display.max_columns=5
עריכת טבלאות מתקדמת#
בפרק זה נעמיק עוד את היכרותנו עם פעולות העריכה בpandas ונלמד שתי טכניקות מתקדמות יותר לעבודה עם טבלאות.
הראשונה היא שימוש במיסוך (Masking), המאפשר לסנן ולעדכן נתונים בטבלה לפי תנאים מסוימים.
לאחר מכן נכיר את המתודה החזקה apply, המאפשרת לבצע חישובים מורכבים או ליצור עמודות חדשות מבלי להשתמש בלולאות מפורשות, על-ידי הפעלת פונקציה על שורות או עמודות שלמות.
הפעולות להלן יודגמו טבלת הציונים "files/StudentsGrades.csv":
inputFileName = "files/StudentsGrades.csv"
df = pd.read_csv(inputFileName)
display(df)
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 0 | Yael | 50 | ... | 65 | 91 |
| 1 | Nadav | 61 | ... | 52 | 88 |
| ... | ... | ... | ... | ... | ... |
| 11 | Tom | 98 | ... | 92 | 80 |
| 12 | Adi | 76 | ... | 84 | 70 |
13 rows × 8 columns
מיסוך (Masking) בpandas#
העמקה: מה זה Masking?
Mask (מסכה) היא מערך בוליאני (של ערכי True/False) שמשמש כדי לבחור אילו איברים ממערך אחר (בעל אותם ממדים) ייכללו בפעולה מסוימת, ואילו יישארו מוסתרים או יתעלמו מהם.
אפשר לחשוב על המסכה כעל שכבת פילטר שמכסה חלקים מהנתונים וחושפת רק את מה שצריך, כמו מסננת או שכבת שקף עם חורים.
לדוגמא, עבור הטבלה שלנו df ניתן לייצר מסיכה מאחת העמודות (לדוגמא, m=df["Art"]>90)’ ולבצע מיסוך df[m] או df.loc[m].
במיסוך זה, שורות בהן m מכיל את הערך True ייכללו בחישוב, ונתעלם משורות בהן m מכיל את הערך False.
ביצוע Masking יכול לשמש אותנו כדי להחזיר תת-טבלה, או כדי לבצע פעולה על תת-טבלה.
כעת נבחן כמה דוגמאות לשימוש ב-Masking על DataFrame:
נניח כי נרצה להסיר את כל הסטודנטיות ששמן יעל.
תחילה ניצור מסיכה:
msk=df['Name'] != 'Yael'
display(msk)
0 False
1 True
...
11 True
12 True
Name: Name, Length: 13, dtype: bool
ולאחר מכן נסנן את הטבלה:
display(df[msk])
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 1 | Nadav | 61 | ... | 52 | 88 |
| 2 | Michal | 81 | ... | 81 | 78 |
| ... | ... | ... | ... | ... | ... |
| 11 | Tom | 98 | ... | 92 | 80 |
| 12 | Adi | 76 | ... | 84 | 70 |
12 rows × 8 columns
ניתן גם להשאיר רק סטודנטיות ששמן יעל באמצעות יצירת מסיכה של התנאי ההפוך.
נראה כיצד לעשות זאת בשורה אחת בלבד:
df[df['Name'] == 'Yael']
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 0 | Yael | 50 | ... | 65 | 91 |
1 rows × 8 columns
בדומה לאופרטורים אריתמטיים, ניתן להפעיל פעולות and, or ו-not עבור סדרות וטבלאות בוליאניות (או במילים אחרות, עבור מסיכות).
אך בשונה מערכים בוליאניים רגילים, כאן לאופרטורים אלו יש סימון אחר:
and–>&or–>|not–>~
נדגים זאת באמצעות החזרת כל הסטודנטים שקיבלו מעל 70 מתמטיקה ומעל 90 באומנות:
display(df[(df['Math'] > 70) & (df['Art'] > 90)])
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 6 | Yarden | 63 | ... | 98 | 94 |
| 7 | Avi | 78 | ... | 76 | 100 |
2 rows × 8 columns
שימו לב
בpandas האופרטורים הלוגיים & | ~ קודמים להשוואתיים (כמו < > ==). לכן חשוב לעטוף כל מסיכה בסוגריים על מנת למנוע מהאופרטור הלוגי לפעול לפני האופרטור ההשוואתי.
באמצעות Masking ניתן גם לבצע השמה מותנית, כלומר, לבצע השמה רק במקומות בהם יש במסיכה True.
לדוגמא, בשורה הבאה “נעביר” את כל הסטודנטים שנכשלו בתכנות, וניתן להם את הציון 60 (אתם יכולים לראות שהציון של יעל התחלף מ50 ל60).
df.loc[df["Programming"] < 60, "Programming"] = 60
display(df)
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 0 | Yael | 60 | ... | 65 | 91 |
| 1 | Nadav | 61 | ... | 52 | 88 |
| ... | ... | ... | ... | ... | ... |
| 11 | Tom | 98 | ... | 92 | 80 |
| 12 | Adi | 76 | ... | 84 | 70 |
13 rows × 8 columns
מתודת apply#
המתודה apply מאפשרת להפעיל פונקציה על עמודה או על כל שורה ב-DataFrame. במקום להשתמש בלולאות, apply מאפשרת לנו לבצע חישוב או שינוי על כל השורות או העמודות של הטבלה בבת אחת.
באופן דומה, עבור סדרה, apply תבצע את הפעולה על כל ערכים בסדרה בבת אחת.
לדוגמא, אם נרצה להעלות את כל הציונים בעמודה Art ב10, אבל לוודא שלא יהיו ציונים גבוהים מ100, נוכל לעשות זאת באופן הבא:
df["Art"]=df["Art"].apply(lambda a: min(100, a+10))
display(df)
| Name | Programming | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 0 | Yael | 60 | ... | 65 | 100 |
| 1 | Nadav | 61 | ... | 52 | 98 |
| ... | ... | ... | ... | ... | ... |
| 11 | Tom | 98 | ... | 92 | 90 |
| 12 | Adi | 76 | ... | 84 | 80 |
13 rows × 8 columns
בדומה לחישוב ממוצע המקצועות שראינו קודם, גם לapply, יש פרמטר בשם axis:
בברירת מחדל, apply מופעל עם הקלט axis=0. כלומר, מתבצעת פעולה בין השורות השונות, או במילים אחרות - על כל עמודה בנפרד.
ולהיפך, הפעלת apply עם axis=1 תבצע פעולה בין העמודות השונות, או במילים אחרות - על כל שורה בנפרד.
נדגים זאת באמצעות ממוצע באמצעות apply:
display(df.iloc[:,1:].apply(lambda a: a.mean(), axis=1))
0 71.142857
1 71.571429
...
11 93.142857
12 77.000000
Length: 13, dtype: float64
שימו לב שapply מחלץ ממוצע עבור כל סטודנט בנפרד (כלומר, עבור כל שורה), והתוצאה היא סדרה במבנה על עמודה בטבלה, בה קיים ממוצע כל סטודנט.
מה היה קורה אם היינו מפעילים את אותה השורה עם axis=0?
היינו מחלצים ממוצע עבור כל מקצוע בנפרד (כלומר, עבור כל טור), מה שהיה מסתכם לכדי שורה חדשה (ללא עמודת שם הסטודנט, אותה חתכנו באמצעות iloc).
נחזור למשימת הוספת פקטור של 10 נקודות. מה אם במקום להוסיף זאת רק עבור אומנות, היינו מוסיפים זאת לכלל המקצועות?
היינו חושבים אולי לבצע משהו כזה:
(df.iloc[:,1:]=df.iloc[:,1:].apply(lambda a: min(100, a+10)
אבל מכיוון שאנו פועלים כעת על טבלה (ולא על סדרה כמו בדוגמא הראשונה), a בפונקציית הlambda ייצג שורה שלמה. כלומר פעולת המינימום לא תתבצע עבור כל תא בנפרד, כפי שהיינו רוצים.
לכן, נעזר במתודה clip של pandas המאפשרת לקטום ערכים בכל תא בנפרד. במקרה שלנו, היינו צריכים להגביל את הערכים רק מלמעלה, ולכן נשתמש בפרמטר upper=100.
כעת המימוש יראה כך:
df.iloc[:,1:].apply(lambda a: a+10).clip(upper=100)
| Programming | Marine Biology | ... | Planet Survival | Art | |
|---|---|---|---|---|---|
| 0 | 70 | 66 | ... | 75 | 100 |
| 1 | 71 | 87 | ... | 62 | 100 |
| ... | ... | ... | ... | ... | ... |
| 11 | 100 | 86 | ... | 100 | 100 |
| 12 | 86 | 97 | ... | 94 | 90 |
13 rows × 7 columns
הערה
במקרה הזה, אין חשיבות לפרמטר axis בapply מכיוון שהפעולה נעשית בסופו של דבר על כל ערך בנפרד, והם אינם “נסכמים” ביחד.
תרגיל#
בשורה אחת בלבד, שנו באמצעות המתודה apply את שמות הסטודנטים כך שכולם יהיו באותיות גדולות.
# Write your code here
display(df)