Menu

Merge ו-Join ל-data frames ב-R (merge, left_join)

שילוב data frames לפי מפתח משותף: merge() ל-inner, left, right ו-full joins, שמות מפתח שונים עם by.x/by.y, משפחת ה-joins של dplyr, ו-rbind() לערימת שורות.

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

שתי טבלאות, מפתח אחד

נתונים אמיתיים כמעט אף פעם לא יושבים בטבלה אחת. הלקוחות נמצאים ב-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().

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

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

להתחיל