שתי טבלאות, מפתח אחד
נתונים אמיתיים כמעט אף פעם לא יושבים בטבלה אחת. הלקוחות נמצאים ב-data frame אחד, ההזמנות שלהם באחר, והשאלה, "כמה הוציא כל לקוח?", צריכה את שניהם. מה שמחבר ביניהם הוא מפתח: עמודה שקיימת בכל טבלה ומזהה את אותה ישות. שילוב טבלאות לפי מפתח הוא join (המילה של SQL) או merge (המילה של R הבסיסי); אותה פעולה.
הנה זוג הטבלאות שבו משתמש שאר העמוד. שימו לב שלקוח 5 ביצע הזמנה אבל לא נמצא בטבלת הלקוחות, ושלקוחות 2 ו-4 מעולם לא הזמינו:
אי ההתאמות מכוונות: מה ש-join עושה עם שורות שלא נמצאה להן התאמה הוא בדיוק מה שמבדיל בין סוגי ה-join.
merge(): inner join כברירת מחדל
merge(x, y, by = "key") מתאים שורות עם מפתחות שווים ומדביק את העמודות שלהן יחד. כברירת מחדל הוא שומר רק את המפתחות שקיימים בשתי הטבלאות: inner join:
חוזרות שלוש שורות. Ana מופיעה פעמיים: יש לה שתי הזמנות, ו-join מפיק שורת פלט אחת לכל זוג תואם. Ben ו-Dana נעלמו (אין הזמנות), וכך גם ההזמנה המסתורית של לקוח 5 (אין לקוח). inner join משליך בשקט שורות לא תואמות משתי הטבלאות: בדיוק נכון כשאכפת לכם רק מזוגות שלמים, ובאג שקט של אובדן נתונים כשלא.
left, right ו-full joins: all.x, all.y, all
כדי לשמור שורות לא תואמות, אמרו של איזו טבלה השורות קדושות. all.x = TRUE שומר כל שורה של הטבלה הראשונה: left join, ה-join הנפוץ ביותר בפועל:
עכשיו Ben ו-Dana שורדים, עם NA ב-amount: "הלקוח הזה קיים; שום הזמנה לא התאימה". ה-NA האלה אינפורמטיביים, לא זבל: is.na(result$amount) היא בדיוק רשימת הלקוחות שמעולם לא הזמינו (המדריך על ערכים חסרים מסביר איך לעבוד איתם). שאר הגרסאות הן אותו רעיון שמכוון למקום אחר: all.y = TRUE שומר כל שורה של הטבלה השנייה (right join: ההזמנה של הלקוח הלא מוכר 5 הייתה שורדת עם NA ב-name), ו-all = TRUE שומר הכול משני הצדדים (full join).
בחרו על ידי השאלה: של מי השורות אסור לי לאבד? העשרת טבלת אב בנתוני חיפוש: left join, טבלת האב ראשונה. ביקורת בשני הכיוונים: full join.
שמות מפתח שונים: by.x ו-by.y
טבלאות כמעט אף פעם לא מסכימות על שמות: id באחת, customer_id בשנייה. אל תשנו שמות; ספרו ל-merge() את שני השמות:
הפלט שומר את השם של הטבלה הראשונה עבור המפתח. ובאותו עניין: אם לשתי הטבלאות יש שמות עמודות משותפים שאינם מפתח (לשתיהן יש date, למשל), merge מוסיף להן סיומות date.x ו-date.y. שנו את שמותיהן מהר, הן נקראות נורא.
ה-joins של dplyr
dplyr נותן לכל סוג join פועל משלו, כך שהכוונה נמצאת בשם הפונקציה ולא בארגומנטים של דגלים (סטטי; סביבת ההרצה מריצה R בסיסי בלבד):
library(dplyr)
left_join(customers, orders, by = "id")
inner_join(customers, orders, by = "id")
full_join(customers, orders, by = "id")
left_join(customers, orders, by = c("id" = "customer_id")) # different names
מעבר לקריאות, left_join() שומר על סדר השורות של הטבלה הראשונה (merge() ממיין מחדש לפי מפתח) ומזהיר בקול רם על התאמות של רבים לרבים. ראו את המבוא ל-dplyr למשפחת הפעלים.
החבר שלא מקבל מספיק הערכה הוא anti_join(): הוא מחזיר את השורות של הטבלה הראשונה שאין להן התאמה בשנייה, בלי להוסיף עמודות, רק את השאריות:
anti_join(customers, orders, by = "id") # customers who never ordered
השאלה הזו, "אילו שורות לא הצליחו להתאים?", עולה כל הזמן בניקוי נתונים (מזהים לא תואמים, רשומות יתומות, חיפושים שנכשלו), ו-anti_join() עונה עליה בקריאה אחת, כשב-R הבסיסי צריך customers[!(customers$id %in% orders$id), ].
ערימת שורות: rbind()
join משלב עמודות של שתי טבלאות. כשיש לכם במקום זאת שתי מנות של שורות מאותו סוג, ההזמנות של ינואר ושל פברואר, עורמים אותן עם rbind():
הדרישה נוקשה: לשני ה-data frames חייבים להיות אותם שמות עמודות (בכל סדר, rbind מתאים לפי שם). עמודה חסרה או עודפת היא שגיאה, לא מילוי ב-NA. כשהעמודות של המנות השתנו עם הזמן, bind_rows() של dplyr סלחני יותר: הוא מיישר לפי שם וממלא פערים ב-NA.
התפוצצות המפתחות הכפולים
תאונת ה-join הקלאסית: מפתחות שחשבתם שהם ייחודיים, אבל הם לא, בשתי הטבלאות. כל התאמה מתחברת לכל התאמה, והשורות מוכפלות:
שתי שורות שמחוברות לשתי שורות מניבות ארבע: כל x מוצמד לכל y. בנתונים אמיתיים, כך טבלה של 10,000 שורות הופכת ל-3 מיליון שורות ולסך הכנסות כפול. merge() עושה את זה בשקט. ההגנה היא הרגל: לפני join, בדקו את המפתח שאתם מניחים שהוא ייחודי, anyDuplicated(customers$id) צריך להיות 0, ואחרי ה-join, בדקו את nrow() מול מה שציפיתם.
מה לקחת מכאן
merge(x, y, by = "key")הוא inner join: שורות לא תואמות נעלמות בשקט.all.x = TRUE(left),all.y = TRUE(right),all = TRUE(full) שומרים שורות לא תואמות וממלאים ב-NA.- שמות מפתח שונים:
by.x/by.yב-R הבסיסי,by = c("a" = "b")ב-dplyr. - dplyr נותן שם לכל join;
anti_join(), השורות שלא התאימו, הוא זה שלא מקבל מספיק הערכה. rbind()עורם טבלאות באותה צורה; העמודות חייבות להתאים לפי שם.- מפתחות כפולים מכפילים שורות בשקט: בדקו
anyDuplicated()לפני,nrow()אחרי.
בהמשך: שינוי צורה בין פורמט רחב לפורמט ארוך עם pivot_longer() ו-pivot_wider().
שאלות נפוצות
איך ממזגים שני data frames ב-R?
השתמשו ב-merge(x, y, by = "key") עם עמודת המפתח המשותפת. כברירת מחדל מתבצע inner join: רק שורות שהמפתח שלהן מופיע בשני ה-data frames שורדות. הוסיפו all.x = TRUE ל-left join, all.y = TRUE ל-right join, או all = TRUE ל-full join.
איך עושים left join ב-R?
ב-R הבסיסי: merge(x, y, by = "key", all.x = TRUE) שומר כל שורה של x וממלא את העמודות של y ב-NA היכן שאין התאמה. ב-dplyr: left_join(x, y, by = "key"), אותה תוצאה, והוא גם שומר על סדר השורות המקורי של x, מה ש-merge() לא עושה.
איך ממזגים data frames כשלעמודות המפתח יש שמות שונים?
ספרו ל-merge() את שני השמות: merge(x, y, by.x = "id", by.y = "customer_id"). ב-dplyr המקבילה היא left_join(x, y, by = c("id" = "customer_id")), או עם פונקציית העזר המודרנית, by = join_by(id == customer_id).
מה ההבדל בין merge ל-rbind ב-R?
הם משלבים בממדים שונים. merge() מתאים שורות של שתי טבלאות לפי מפתח ומשלב את העמודות שלהן: join. rbind() עורם את השורות של טבלה אחת מתחת לשורות של אחרת, ולשתיהן חייבים להיות אותם שמות עמודות. קבצים חודשיים עם עמודות זהות מתאימים ל-rbind(); לקוחות ועוד הזמנות מתאימים ל-merge().