שימו לב: על מנת להריץ את התאים ב-Live Code, יש לייבא תחילה את ספרית pandas ע”י הרצת השורת הראשונה בתא למטה.
בנוסף, נגביל את מספר השורות והעמודות שתופענה בהדפסת הטבלאות ע”י שורות הקוד השניה והשלישית:

import pandas as pd
pd.options.display.max_rows=5
pd.options.display.max_columns=5

גישה בסיסית לטבלה#

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

נתחיל מטעינת טבלת הציונים שלנו מהקובץ files/StudentsGrades.csv לתוך df:

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

בדיקת נתונים בסיסיים על הטבלה#

כדי להכיר את הטבלה יותר טוב, נרצה לחלץ ממנה מספר נתונים בסיסיים.

כדי לקבל את מספר השורות בטבלה, נוכל להשתמש בפונקציה שכבר ראינו - len:

print(len(df))
13

מה לגבי מספר העמודות?
בדומה לarray בnumpy, גם בDataFrame בpandas ישנו שדה מיוחד בשם shape, המייצג את מימדי הטבלה כtuple:

print(df.shape)
(13, 8)

כפי שהזכרנו ביחידה הקודמת, כל עמודה יכולה להכיל ערכים מטיפוס שונה. כדי לקבל את הטיפוס של העמודות ניתן להשתמש בשדה dtypes:

print(df.dtypes)
Name               object
Programming         int64
                    ...  
Planet Survival     int64
Art                 int64
Length: 8, dtype: object

שימו לב

עמודות מחרוזת (כמו Name בדוגמא לעיל) מיוצגות בpandas ע”י הטיפוס object

גישה לערכים בטבלאות וסדרות: [], [,]iloc ו-[,]loc#

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

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

בpandas קיימות מספר דרכים לגשת לנתונים מטבלה. השיטה הפשוטה ביותר היא df[x], שמחזירה עמודה לפי השם שלה. אם נפעיל את [] על סדרה (Series), לדוגמא, s[x], נקבל ערך שנמצא בתא בשם x.

בנוסף, קיימות שתי מתודות מאוד שימושיות: df.loc[x,y] שמבוססת על שמות השורות (x) ועמודות (y), ו־df.iloc[x,y] שמבוססת על המיקומי של השורות והעמודות (x ו-y) בהתאמה.
באמצעות מתודות אלו, ניתן לבצע חיתוך על השורות והעמודות יחדיו בתוך הסוגריים המרובעים.

df[x]

s[x]

df.loc[x,y]

df.iloc[x,y]

בכל אחת מהאופציות הללו, x יכול לייצג עבור טבלה:

  • שורה בודדת

  • Slicing של שמות/מיקומי שורות

  • רשימה של שמות/מיקומי שורות.

באופן דומה ניתן לגשת לעמודה בודדת או מספר עמודות באמצעות y.

חשוב להבחין בין שלושת הדרכים הללו, משום שכל אחת מהן מתנהגת אחרת.

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

  • גישה לתא יחיד מחזירה ערך בודד בהתאם לטיפוס הנתונים של העמודה.

  • גישה לעמודה אחת או שורה אחת מחזירה אובייקט מסוג Series, שהוא וקטור חד-ממדי.

  • גישה למספר עמודות ומספר שורות, התוצאה היא DataFrame, כלומר טבלה דו-ממדית.

שימוש בiloc[x,y]#

שימוש בiloc[x,y] בטבלה#

באמצעות שימוש בiloc מתאפשרת גישה לערכים, שורות ועמודות לפי מיקומים מספריים (בדומה לגישה לערכים ברשימות, מערכים ומטריצות).

לדוגמא, ניתן לגשת לערך בודד באמצעות ציון השורה והעמודה של הערך. לדוגמא, כך נחזיר את הערך הנמצא בשורה השניה והעמודה השניה:

print(df.iloc[1, 1])
61

על מנת לגשת לשורה שלמה, נפרט רק את האינדקס הראשון. לדוגמא, הקוד הבא מחלץ את השורה הראשונה (אינדקס 0):

s = df.iloc[0]
print(s)
Name               Yael
Programming          50
                   ... 
Planet Survival      65
Art                  91
Name: 0, Length: 8, dtype: object

ניתן לראות כי במקרה הזה מכיוון שחילצנו שורה, הערך שחזר הוא מטיפוס series

print(type(s))
<class 'pandas.core.series.Series'>

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

ואם נרצה לבחור עמודה? נוכל לשים את האינדקס של העמודה במיקום השני בסוגריים המרובעים (כלומר, לאחר הפסיק). אך בניגוד להחזר שורה, אין ערך ברירת מחדל לערכי השורות שחוזרות עבור העמודה. על מנת להחזיר את כל ערכי השורות של העמודה, נוכל להשתמש ב: ללא פירוט נוסף. כפי שראינו בslicing, : משתמשים לציון כל הטווח, כלומר, במקרה שלנו, ערכי העמודה בכל השורות.

print(df.iloc[:,0])
0      Yael
1     Nadav
      ...  
11      Tom
12      Adi
Name: Name, Length: 13, dtype: object

ניתן גם לבחור תת טבלה לפי טווחים של שורות ושל עמודות יחד.

display(df.iloc[0:3,0:3])
Name Programming Marine Biology
0 Yael 50 56
1 Nadav 61 77
2 Michal 81 72

שימוש בiloc[x,y] בסדרה#

בדומה לטבלה, גם מסדרה ניתן לחלץ ערכים.

בדוגמא למטה, נחלץ תחילה שורה הרביעית בטבלה:

df_row=df.iloc[3]

כעת נוכל להשתמש בiloc (שוב) כדי לחלץ ערך מהסדרה:

print(df_row.iloc[0])
Shoshana

כלומר, כאן חילצנו את הערך הראשון של הסדרה, שהוא למעשה ערך העמודה הראשונה בשורה הרביעית.

כפי שהזכרנו קודם, הטיפוס של שורה הוא series, כלומר, סדרת ערכים חד מימדית. לכן נוכל לבחור רק לפי מימד אחד של אינדקסים (כלומר, x ללא y).

אם ננסה לבחור גם לפי y נקבל שגיאה:

print(df_row.iloc[:,0])
---------------------------------------------------------------------------
IndexingError                             Traceback (most recent call last)
Cell In[15], line 1
----> 1 print(df_row.iloc[:,0])

File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/pandas/core/indexing.py:1185, in _LocationIndexer.__getitem__(self, key)
   1183     if self._is_scalar_access(key):
   1184         return self.obj._get_value(*key, takeable=self._takeable)
-> 1185     return self._getitem_tuple(key)
   1186 else:
   1187     # we by definition only have the 0th axis
   1188     axis = self.axis or 0

File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/pandas/core/indexing.py:1691, in _iLocIndexer._getitem_tuple(self, tup)
   1690 def _getitem_tuple(self, tup: tuple):
-> 1691     tup = self._validate_tuple_indexer(tup)
   1692     with suppress(IndexingError):
   1693         return self._getitem_lowerdim(tup)

File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/pandas/core/indexing.py:963, in _LocationIndexer._validate_tuple_indexer(self, key)
    958 @final
    959 def _validate_tuple_indexer(self, key: tuple) -> tuple:
    960     """
    961     Check the key for valid keys across my indexer.
    962     """
--> 963     key = self._validate_key_length(key)
    964     key = self._expand_ellipsis(key)
    965     for i, k in enumerate(key):

File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/pandas/core/indexing.py:1002, in _LocationIndexer._validate_key_length(self, key)
   1000             raise IndexingError(_one_ellipsis_message)
   1001         return self._validate_key_length(key)
-> 1002     raise IndexingError("Too many indexers")
   1003 return key

IndexingError: Too many indexers

שימוש בloc[x,y]#

הגישה באמצעות loc מאפשרת לנו לבחור שורות ועמודות לפי שמות, ולא לפי מיקומים מספריים. זוהי אחת מהדרכים הברורות והנוחות ביותר לגשת למידע בDataFrame.

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

לדוגמא, ניגש לעמודת הציונים במקצוע אמנות באופן הבא:

display(df.loc[:,'Art'])

כעת ניגש לשורה בטבלה לפי שמה.

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

display(df.loc[0])
Name               Yael
Programming          50
                   ... 
Planet Survival      65
Art                  91
Name: 0, Length: 8, dtype: object
display(df.iloc[0])
Name               Yael
Programming          50
                   ... 
Planet Survival      65
Art                  91
Name: 0, Length: 8, dtype: object

ניתן גם לתת לשורות שמות בעלי משמעות, ולחלץ שורות לפי שמות אלו.
כדי להדגים זאת, נשתמש במתודה set_index כדי לשנות את שמות שורות בטבלה לערכים המופעים בעמודה Name:

df = df.set_index("Name")
display(df)
Programming Marine Biology ... Planet Survival Art
Name
Yael 50 56 ... 65 91
Nadav 61 77 ... 52 88
... ... ... ... ... ...
Tom 98 76 ... 92 80
Adi 76 87 ... 84 70

13 rows × 7 columns

שימו לב

  • בברירת המחדל, המתודה set_index מורידה את העמודה שהיא הופכת לאינדקס

  • יש להמנע מהגדרת ערכי אינדקסים המכילים כפילויות, מכיוון שזה עלול לגרור שגיאות בשימושים רבים בpandas

כעת נוכל לחלץ באמצעות loc את השורה לפי שמות הסטודנטים:

print(df.loc['Adi'])
Programming        76
Marine Biology     87
                   ..
Planet Survival    84
Art                70
Name: Adi, Length: 7, dtype: int64

כעת נחלץ את הציון של עדי נדב באמנות:

print(df.loc[['Adi','Nadav'], 'Art'])
Name
Adi      70
Nadav    88
Name: Art, dtype: int64

הערה

כאשר מעבירים שמות שורות (או עמודות) ברשימה לloc סדר השורות (או העמודות) שיוחזר יהיה תואם לסדר של השמות ברשימה.

התנהגות דומה תהיה גם עבור iloc עם רשימת אינדקסים

השוואה בין iloc לloc#

נטען מחדש את הטבלה המקורית:

inputFileName = "files/StudentsGrades.csv"
df = pd.read_csv(inputFileName)
display(df)

נראה כעת שלוש דרכים לחלץ את השורה הראשונה, השלישית והחמישית מתוך df:

display(df.iloc[[0,2,4]]) 
Name Programming Marine Biology Stellar Cartography Math History Planet Survival Art
0 Yael 50 56 70 60 87 65 91
2 Michal 81 72 76 94 67 81 78
4 Danielle 36 74 82 40 78 86 65
display(df.iloc[0:5:2])
Name Programming Marine Biology Stellar Cartography Math History Planet Survival Art
0 Yael 50 56 70 60 87 65 91
2 Michal 81 72 76 94 67 81 78
4 Danielle 36 74 82 40 78 86 65
display(df.loc[0:4:2])
Name Programming Marine Biology Stellar Cartography Math History Planet Survival Art
0 Yael 50 56 70 60 87 65 91
2 Michal 81 72 76 94 67 81 78
4 Danielle 36 74 82 40 78 86 65

שימו לב

בניגוד לסדרות מספריות כפי שראינו עד כה בקורס, Slicing לפי שמות (ב[] ו-loc[]) רץ מהשם בראשון *כולל עד השם האחרון כולל, לפי סדר הופעת השורות/העמודות.

שימוש בSlicing בiloc[] מתנהג כפי שראינו עד כה בSlicing: כלומר, רץ מהמספר הראשון כולל עד האחרון לא כולל

בגלל שבדוגמא האחרונה אנו משתמשים בloc הגדרנו את הטווח עד 4 ולא 5.
אם היינו מנסים להפעיל אותו slicing על iloc, לא היינו מקבלים את הערך החמישי:

display(df.iloc[0:4:2])
Name Programming Marine Biology Stellar Cartography Math History Planet Survival Art
0 Yael 50 56 70 60 87 65 91
2 Michal 81 72 76 94 67 81 78

תרגול#

  1. חלצו מהטבלה df את ארבע השורות האחרונות בכל אחת משלוש השיטות שהדגמנו למעלה.

רמז: השתמשו באינדקסים שליליים.

# Write your code here
  1. בשורה להלן בוצע ניסיון לחלץ את השורה האחרונה מהטבלה

print(df.loc[-1])

מדוע התקבלה שגיאה?

שימוש ב[]#

שימוש ב[] בטבלה#

כאשר משתמשים בסוגריים מרובעים [] עם אובייקט מסוג DataFrame, ברירת המחדל היא גישה לעמודה לפי שמה.
כמו בloc, גם כאן ניתן להעביר שם בודד, רשימת שמות, או טווח של שמות.

לדוגמא, השורה הבאה תחזיר את הציונים באמנות:

display(df["Art"])
Name
Yael     91
Nadav    88
         ..
Tom      80
Adi      70
Name: Art, Length: 13, dtype: int64

והשורה שלהלן תחזיר את הציונים באמנות ובתכנות:

display(df[["Art", "Programming"]])
Art Programming
Name
Yael 91 50
Nadav 88 61
... ... ...
Tom 80 98
Adi 70 76

13 rows × 2 columns

בדומה לloc וiloc, גם ב[] יוחזר טיפוס series עבור שם בודד (עמודה בודדת) וטבלה עבור מספר עמודות.

ואם נעביר ערך שאינו קיים?

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

df[1]

שימוש ב[] בסדרה#

אם נפעיל את [] על סדרה (Series), לדוגמא, s[x], נקבל ערך שנמצא בתא בשם x.

s = df["Art"]
print(type(s))
print(s[0])
<class 'pandas.core.series.Series'>
91

שמות שורות ועמודות בטבלאות וסדרות#

ב-DataFrame שמות השורות ושמות העמודות נשמרים בשדות ייעודיים:

  • שמות השורות נשמרים בשדה index

  • שמות העמודות נשמרים במאפיין columns

שני השדות הם מסוג המחלקה Index, שניתן לראות בה מחלקה כללית לייצוג שמות.

שמות התאים בתוך Series נקראים גם הם index, ללא קשר אם ה-Series מייצגת מעמודה או משורה.
זכרו כי Series היא חד-מימדית בעוד הקונספט של שורה ועמודה נגזר מכך קיים רק בהקשר של DataFrame - באיך שה-Series ממקום בו (בדומה לשורה או עמודה בודדת במטריצה).

s=df.loc[0]
print(type(s))
print(s.index)
<class 'pandas.core.series.Series'>
Index(['Name', 'Programming', 'Marine Biology', 'Stellar Cartography', 'Math',
       'History', 'Planet Survival', 'Art'],
      dtype='object')

לסדרה גם יכול להיות שם, השמור בשדה name. אם הסדרה נגזרה משורה/עמודה בטבלה, הערך של nameיהיה שם השורה או העמודה כפי שהופיע במקור בטבלה:

print(s.name)
0