Menu

Group By ו-Summarize ב-R (aggregate, tapply, dplyr)

כל הדרכים לחשב סטטיסטיקות לפי קבוצה ב-R: ספירה עם table(), tapply() לסטטיסטיקה אחת לכל קבוצה, ממשק הנוסחה של aggregate(), ו-group_by() עם summarize() של dplyr.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

ספירת שורות לפי קבוצה: table()

שאלת הקיבוץ הפשוטה ביותר היא "כמה יש מכל אחד?", ו-R הבסיסי עונה עליה בקריאה אחת. table() סופר כמה פעמים מופיע כל ערך:

עמודה אחת נותנת ספירה לכל ערך; שתי עמודות נותנות טבלת הצלבה מלאה (אזורים כשורות, תוכניות כעמודות). לשאלה "איזה חלק?" עטפו אותה ב-prop.table(table(...)). table() היא הדרך המהירה ביותר לתשובה על שכיחויות בכל R, ואין סיבה לפנות לכלי כבד יותר כשכל מה שצריך הוא ספירה.

סטטיסטיקה אחת לכל קבוצה: tapply()

tapply(values, groups, function) מפצל את הווקטור הראשון לפי השני ומפעיל את הפונקציה על כל חלק:

התוצאה היא וקטור בעל שמות: תוויות הקבוצות הן השמות והסטטיסטיקות הן הערכים, מה שהופך אותו למושלם לשליפות מהירות (means["EU"]). השם מתפענח כ-"table apply": הפעלת פונקציה לאורך טבלת קיבוץ. הוא שייך לאותה משפחה של sapply() ו-lapply(), שמוסברות במדריך על משפחת apply.

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

סוס העבודה של הנוסחאות: aggregate()

aggregate() הוא ה-group-by המלא של R הבסיסי: הוא מחזיר data frame, וממשק הנוסחה שלו נקרא כמו המשפט שהייתם אומרים. value ~ group פירושו "value, מפולח לפי group":

הוספת משתני קיבוץ היא פשוט + עמודה_נוספת בנוסחה: הקריאה השנייה סוכמת לכל צירוף של אזור ורבעון. אפשר גם לסכם כמה עמודות ערכים בבת אחת עם cbind(a, b) ~ group. מכיוון שהפלט הוא data frame רגיל, הוא נכנס ישר ל-merge, למיון או לגרף. זה הכלי הבסיסי שכדאי לבחור כברירת מחדל לסיכומים לפי קבוצות.

התנהגות שקטה אחת שכדאי להכיר: ממשק הנוסחה משמיט שורות עם NA בכל עמודה שבשימוש לפני הסיכום. בדרך כלל זה מה שרוצים; לפעמים זה ההסבר לספירה שנראית נמוכה מדי.

הדרך של dplyr: group_by() + summarize()

הסטנדרט המודרני הוא דפוס שני הפעלים של dplyr: group_by() מצהיר על הקיבוץ, ו-summarize() מכווץ כל קבוצה לשורה אחת ומחשב כמה סטטיסטיקות שתבקשו (סטטי; סביבת ההרצה מריצה R בסיסי בלבד):

library(dplyr)

sales |>
    group_by(region) |>
    summarize(
        n     = n(),
        total = sum(amount),
        avg   = mean(amount)
    )

כאן dplyr באמת עולה על R הבסיסי: כמה סטטיסטיקות לכל קבוצה בקריאה אחת וברורה (ל-aggregate() זה דורש התפתלויות), n() בחינם, והתוצאה זורמת ישר ל-pipe הבא. (summarise() היא אותה פונקציה, בכתיב בריטי.)

דבר אחד שמבלבל מתחילים: כשיש כמה משתני קיבוץ, summarize() מסיר רק את האחרון, והתוצאה נשארת מקובצת, עם הודעה על כך. אמרו במפורש מה אתם רוצים עם הארגומנט .groups: summarize(avg = mean(amount), .groups = "drop") מחזיר data frame רגיל ולא מקובץ, וזה הרגל ברירת המחדל הנכון. data frame מקובץ שמתגנב לקוד מאוחר יותר גורם ל-mutate() ולחבריו לפעול בשקט לפי קבוצה, מקור קלאסי לתוצאות מבלבלות.

איך לבחור ביניהם

  • ספירה: table(), שום דבר לא מנצח קריאה אחת.
  • סטטיסטיקה אחת, מבט מהיר: tapply(), וקראו את התשובה מתוך הווקטור בעל השמות.
  • פלט של data frame, סביבה של R בסיסי בלבד: aggregate() עם נוסחה.
  • כמה סטטיסטיקות, חלק מ-pipeline, או כל דבר שאפתני: group_by() |> summarize().

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

דוגמה מלאה: mtcars לפי מספר צילינדרים

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

אחת עשרה מכוניות עם 4 צילינדרים בממוצע של כ-26.7 mpg, שבע עם 6 צילינדרים סביב 19.7, ארבע עשרה עם 8 צילינדרים סביב 15.1, וכוח הסוס צועד בכיוון ההפוך. שתי קריאות, טבלת סיכום שלמה: זה בדיוק סוג השאלה שבשבילה קיים סיכום לפי קבוצות.

מה לקחת מכאן

  • table() לספירות, prop.table() לחלקים יחסיים.
  • tapply(values, groups, fn) מחזיר וקטור בעל שמות: מבטים מהירים, שליפות קלות.
  • aggregate(value ~ group, data, FUN) מחזיר data frame; + מוסיף משתני קיבוץ, cbind() מוסיף עמודות ערכים.
  • group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop") של dplyr הוא הסטנדרט המודרני לסיכומים עם כמה סטטיסטיקות.
  • בחרו לפי צורת הפלט; כולם מסכימים על המספרים.

בהמשך: שילוב טבלאות שחולקות מפתח, merge() ומשפחת ה-joins של dplyr.

שאלות נפוצות

איך מחשבים ממוצע לפי קבוצה ב-R?

ל-R הבסיסי יש שני כלים: tapply(df$value, df$group, mean) מחזיר וקטור בעל שמות של ממוצעי הקבוצות, ו-aggregate(value ~ group, data = df, FUN = mean) מחזיר את אותה תוצאה כ-data frame. ב-dplyr: df |> group_by(group) |> summarize(avg = mean(value)).

איך סופרים מופעים לפי קבוצה ב-R?

table(df$group) סופר שורות לכל ערך קבוצה בקריאה אחת; table(df$a, df$b) מצליב שתי עמודות בטבלת שכיחויות. ב-dplyr, count(df, group) עושה את אותו הדבר ומחזיר data frame, שקל יותר להמשיך לעבד.

מה עושה aggregate() ב-R?

aggregate() מפצל data frame לפי עמודת קיבוץ אחת או יותר, מפעיל פונקציה על כל חלק ומחזיר data frame של תוצאות. ממשק הנוסחה נקרא באופן טבעי: aggregate(sales ~ region + quarter, data = df, FUN = mean) פירושו sales, מקובץ לפי region ו-quarter, בממוצע.

מה ההבדל בין tapply ל-aggregate?

אותו חישוב, צורת פלט שונה. tapply() מחזיר וקטור בעל שמות (או מערך כשיש שני משתני קיבוץ), נוח לשליפות מהירות. aggregate() מחזיר data frame, עדיף כשהתוצאה ממשיכה לניתוח נוסף, ל-merge או לגרף. אם אתם מתלבטים, aggregate().

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל