Smart-World Surf

יחידה 7: ניתוח נתונים עם Pandas I

מבני נתונים בסיסיים: Series ו-DataFrame.
SeriesDataFrameיצירה ואינדוקסטיפול בערכים חסרים

ברוכים הבאים ליחידה הראשונה בנושא ניתוח נתונים עם Pandas! ספריית Pandas היא אבן יסוד בעולם ניתוח הנתונים בפייתון, ומספקת מבני נתונים עוצמתיים וכלים גמישים לעבודה עם נתונים מובנים. ביחידה זו נתמקד בשני מבני הנתונים הבסיסיים והחשובים ביותר של Pandas: Series ו-DataFrame. נלמד כיצד ליצור אותם, לגשת לנתונים בתוכם באמצעות אינדוקס מתקדם, וכיצד לטפל באחד האתגרים הנפוצים ביותר בניתוח נתונים – ערכים חסרים. הבנה מעמיקה של נושאים אלו חיונית להצלחה בקורס ובעבודה מעשית עם נתונים.

מבוא למבני נתונים ב-Pandas

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

Series: מבנה נתונים חד-ממדי של Pandas, הדומה למערך NumPy אך כולל אינדקס (תוויות) לכל אלמנט. ניתן לחשוב עליו כעל עמודה בטבלה או סדרה של נתונים עם תוויות.
DataFrame: מבנה נתונים דו-ממדי של Pandas, הדומה לטבלה בבסיס נתונים או לגיליון אלקטרוני. הוא מורכב מאוסף של אובייקטי Series החולקים את אותו אינדקס שורות, וכולל גם אינדקס עמודות.

Series

מבנה חד-ממדי. דומה לעמודה אחת. לכל ערך יש אינדקס (תווית) ייחודי. יכול להכיל סוג נתונים אחיד (לרוב).

DataFrame

מבנה דו-ממדי. דומה לטבלה. מורכב מעמודות (Series) ושורות. לכל שורה ולכל עמודה יש אינדקס (תווית).

יצירה ואינדוקס של Series ו-DataFrame

יצירת Series

  • מתוך רשימה: pd.Series([10, 20, 30]) - יקבל אינדקס מספרי ברירת מחדל.
  • מתוך רשימה עם אינדקס מוגדר: pd.Series([10, 20, 30], index=['a', 'b', 'c']).
  • מתוך מילון: pd.Series({'a': 10, 'b': 20}) - מפתחות המילון הופכים לאינדקס.
  • מתוך סקלר: pd.Series(5, index=['x', 'y', 'z']) - יצור Series עם ערך 5 בכל המקומות.

יצירת DataFrame

  • מתוך מילון של רשימות/Series: הדרך הנפוצה ביותר. מפתחות המילון הופכים לשמות העמודות.
    data = {'שם': ['איתי', 'נועה'], 'גיל': [25, 30]}
    df = pd.DataFrame(data)
  • מתוך רשימה של מילונים: כל מילון מייצג שורה.
    data = [{'שם': 'איתי', 'גיל': 25}, {'שם': 'נועה', 'גיל': 30}]
    df = pd.DataFrame(data)
  • מתוך מערך NumPy דו-ממדי: יש לספק שמות עמודות ואינדקס שורות בנפרד.

אינדוקס וגישה לנתונים

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

  • Series:
    • גישה לפי אינדקס (תווית): s['a']
    • גישה לפי מיקום מספרי: s[0]
    • חיתוך (slicing): s[0:2] או s['a':'c'] (כולל את הקצה הימני בתוויות!)
  • DataFrame:
    • בחירת עמודה: df['שם'] או df.שם (אם שם העמודה חוקי). מחזיר Series.
    • בחירת מספר עמודות: df[['שם', 'גיל']]. מחזיר DataFrame.
הבחנה בין .loc ל-.iloc: זהו נושא קריטי לבחינה ולעבודה מעשית!
  • .loc משמש לגישה מבוססת תוויות (labels). הוא כולל את הקצה הימני בחיתוך.
  • .iloc משמש לגישה מבוססת מיקום מספרי (integer-location). הוא אינו כולל את הקצה הימני בחיתוך, בדומה לחיתוך ברשימות פייתון.

דוגמה: אם יש DataFrame עם אינדקס ['a', 'b', 'c']:

  • df.loc['a':'b'] יחזיר שורות עם תוויות 'a' ו-'b'.
  • df.iloc[0:2] יחזיר שורות במיקומים 0 ו-1 (לא כולל 2).

טיפול בערכים חסרים (Missing Values)

נתונים בעולם האמיתי כמעט תמיד מכילים ערכים חסרים, המיוצגים ב-Pandas לרוב כ-NaN (Not a Number) עבור נתונים מספריים, או None עבור אובייקטים.

זיהוי ערכים חסרים

  • df.isnull(): מחזיר DataFrame בוליאני המציין היכן יש ערכים חסרים (True).
  • df.notnull(): ההפך מ-isnull().
  • df.isnull().sum(): סופר את מספר הערכים החסרים בכל עמודה.

הסרת ערכים חסרים

dropna(): פונקציה להסרת שורות או עמודות המכילות ערכים חסרים.
  • df.dropna(): מסיר כל שורה המכילה לפחות ערך חסר אחד.
  • df.dropna(axis=1): מסיר כל עמודה המכילה לפחות ערך חסר אחד.
  • df.dropna(how='all'): מסיר רק שורות (או עמודות, עם axis=1) שכל ערכיהן חסרים.
  • df.dropna(thresh=N): משאיר רק שורות (או עמודות) שיש להן לפחות N ערכים לא חסרים.
  • זכרו להשתמש ב-inplace=True כדי לשנות את ה-DataFrame המקורי, אחרת הפונקציה מחזירה DataFrame חדש.

מילוי ערכים חסרים

fillna(): פונקציה למילוי ערכים חסרים בערך ספציפי או בשיטה מסוימת.
  • df.fillna(0): ממלא את כל הערכים החסרים ב-0.
  • df.fillna(df.mean()): ממלא ערכים חסרים בכל עמודה בממוצע של אותה עמודה (עבור עמודות מספריות).
  • df.fillna(method='ffill'): ממלא ערכים חסרים עם הערך הלא-חסר הקודם (forward fill).
  • df.fillna(method='bfill'): ממלא ערכים חסרים עם הערך הלא-חסר הבא (backward fill).
  • גם כאן, inplace=True משנה את ה-DataFrame המקורי.

שאלות לדיון

  • הסבירו את ההבדל המהותי בין אובייקט Series לאובייקט DataFrame ב-Pandas, ומתי נכון להשתמש בכל אחד מהם.
  • בהינתן DataFrame בשם df, תארו את ההבדל בשימוש ובתוצאה בין df.loc[0:5] לבין df.iloc[0:5]. מתי תעדיפו להשתמש בכל אחת מהשיטות?
  • כיצד תזהו ותטפלו בערכים חסרים בעמודה ספציפית ב-DataFrame, למשל, עמודה בשם 'גיל', אם ברצונכם למלא אותם בערך החציוני של אותה עמודה? כתבו קוד לדוגמה.
  • מהי המשמעות של הפרמטר axis בפונקציות כמו dropna() או mean() ב-Pandas, וכיצד הוא משפיע על הפעולה?

נקודות לתשובת מודל

  • Series vs. DataFrame: Series הוא חד-ממדי עם אינדקס, מתאים לעמודה בודדת. DataFrame הוא דו-ממדי, אוסף של Series עם אינדקס שורות ועמודות, מתאים לטבלאות. בחירה תלויה במבנה הנתונים (עמודה בודדת מול טבלה).
  • loc vs. iloc: loc משתמש בתוויות (labels) וכולל את הקצה הימני בחיתוך. iloc משתמש במיקומים מספריים (integers) ואינו כולל את הקצה הימני. loc עדיף כאשר האינדקס בעל משמעות סמנטית (תאריכים, שמות), iloc כאשר רוצים גישה לפי מיקום מוחלט.
  • טיפול בערכים חסרים:
    • זיהוי: df['גיל'].isnull().sum().
    • מילוי: median_age = df['גיל'].median(), ואז df['גיל'].fillna(median_age, inplace=True).
  • הפרמטר axis: קובע אם הפעולה תתבצע לאורך השורות (axis=0, ברירת מחדל) או לאורך העמודות (axis=1). לדוגמה, df.dropna(axis=0) מסיר שורות, בעוד df.dropna(axis=1) מסיר עמודות. df.mean(axis=0) מחשב ממוצע לכל עמודה, df.mean(axis=1) לכל שורה.
מצאתם טעות או שחסר משהו?
→ הקודמת
מבוא ל-NumPy
הבאה ←
ניתוח נתונים עם Pandas II