סינון שורות: המסכה הלוגית
כדי לסנן data frame ב-R, שימו תנאי במיקום השורות בתוך הסוגריים: df[condition, ]. התנאי מוערך לווקטור של TRUE/FALSE, אחד לכל שורה, ו-R משאירה את השורות שהן TRUE:
קראו את scores[scores$score > 80, ] מבפנים החוצה: scores$score > 80 מייצר TRUE FALSE TRUE TRUE FALSE, והסוגריים משאירים את שורות 1, 3 ו-4. הפסיק שבסוף אינו אופציונלי. סוגריים על data frame מקבלים [rows, columns]; השארת מקום העמודות ריק פירושה "כל העמודות". שכחו את הפסיק ואתם מאנדקסים עמודות במקום, אחת משגיאות המתחילים הנפוצות ביותר ב-R.
שימו לב שמספרי השורות המודפסים הם 1 3 4, לא 1 2 3: הסינון שומר את תוויות השורות המקוריות. לא מזיק, אבל זה מפתיע אנשים.
כמה תנאים: & ו-| (לא &&)
משלבים תנאים עם & (AND) ו-| (OR). כל תנאי מקבל השוואה שלמה משלו:
המלכודת: ב-R יש גם && ו-||, והם לא ניתנים להחלפה עם & ו-| כאן. הצורות הכפולות עובדות על ערכים בודדים (הן קיימות בשביל תנאי if); כשמקבלות עמודות שלמות, R מודרנית (4.3 ומעלה) עוצרת עם שגיאה כמו 'length = 5' in coercion to 'logical(1)', וגרסאות R ישנות יותר השוו בשקט רק את השורה הראשונה, מה שאפשר לטעון שגרוע יותר. בתוך סוגריים, תמיד & ו-| הבודדים. המסמך על אופרטורים מסביר את ההבחנה במלואה.
%in%: התאמה מול קבוצת ערכים
כשעמודה צריכה להתאים לאחד מכמה ערכים, אל תשרשרו == עם |: השתמשו ב-%in%:
x %in% set מחזיר TRUE בכל מקום שבו x הוא אחד מהערכים ב-set. זה נקרא טוב יותר מ-status == "pending" | status == "shipped", מתאים לכל מספר של ערכים, ומתהפך בצורה נקייה: !(orders$status %in% c("refunded")).
בחירת עמודות
מקום העמודות בסוגריים מקבל שמות או מיקומים:
שתי הערות. בחירה לפי שם שורדת שינוי בסדר העמודות; בחירה לפי מיקום (scores[, c(1, 3)]) נשברת ביום שמישהו מכניס עמודה. ובקשה של עמודה בודדת מחזירה וקטור רגיל, לא data frame: זו הסיבה שה-print() השני מציג 91 88 בלי טבלה מסביב. כשאתם צריכים לשמור על צורת ה-data frame, הוסיפו drop = FALSE: scores[, "score", drop = FALSE].
subset(): ה-one-liner הידידותי של base
Base R מגיעה עם פונקציה עוטפת שמטפלת בשורות ובעמודות בקריאה אחת קריאה, בלי $ ובלי הנהלת חשבונות של פסיקים:
בתוך subset() כותבים שמות עמודות חשופים (score, לא scores$score): היא מעריכה אותם מול ה-data frame. זה נקרא הערכה לא סטנדרטית, ויש לזה הסתייגות מתועדת: היא מפענחת שמות בזמן ריצה בדרכים שמתנהגות לא טוב בתוך פונקציות שאתם כותבים (משתנה בשם score בפונקציה שלכם יכול להיות מוסתר על ידי עמודה בשם score). כלל האצבע, ישר מ-?subset: מצוינת בעבודה אינטראקטיבית, הימנעו ממנה בתכנות: שם השתמשו באינדוקס בסוגריים.
מלכודת ה-NA
השוואה מול NA נותנת NA, לא FALSE, וסינון בסוגריים משאיר שורות שהמסכה שלהן NA כשורות מלאות ב-NA:
התוצאה הראשונה מכילה שורת זבל של NA כי התנאי של שורה 2 לא היה TRUE וגם לא FALSE. התיקון הוא לדרוש !is.na() במפורש. subset() ו-filter() של dplyr משמיטות שתיהן בשקט שורות שהתנאי שלהן NA: נוח, אבל דעו שזה קורה. המסמך על ערכים חסרים מסביר למה NA מתפשט כך.
הדרך של dplyr: filter() ו-select()
החבילה dplyr מפצלת את העבודה לשני פעלים, filter() לשורות ו-select() לעמודות, עם שמות עמודות חשופים ובלי חזרה על df$ (סטטי; סביבת ההרצה מריצה רק base R):
library(dplyr)
scores |> filter(score > 80)
scores |> filter(score > 80, team == "red") # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)
filter() משמיטה אוטומטית שורות שהתנאי שלהן NA ותמיד מחזירה data frame (אף פעם לא וקטור חשוף), וזה מסיר את שתי המלכודות של base שלמעלה. המחיר הוא תלות בחבילה ואותן הסתייגויות של הערכה לא סטנדרטית כמו ב-subset(): ראו את המבוא ל-dplyr לסיור המלא בפעלים.
מה לקחת מכאן
df[condition, ]הוא הביטוי הבסיסי, והפסיק חובה.- שלבו תנאים עם
&ו-|בודדים;&&נותן שגיאה על וקטורים. %in%עדיף על שרשור של==להתאמה מול קבוצת ערכים.- בחרו עמודות לפי שם, וזכרו שעמודות בודדות יורדות לווקטורים אלא אם
drop = FALSE. subset()הוא ה-one-liner הנעים לעבודה אינטראקטיבית; סוגריים הם הדרך שמתאימה לתכנות.- השוואות עם
NAמייצרות שורות רפאים בסוגריים: הגנו עם!is.na().
הבא בתור: הוספה ושינוי של עמודות: df$new <- ..., ifelse() ו-mutate() של dplyr.
שאלות נפוצות
איך מסננים שורות של data frame ב-R?
שמים תנאי לוגי במיקום השורות בתוך הסוגריים: df[df$score > 80, ]. התנאי מייצר וקטור של TRUE/FALSE, ו-R משאירה את השורות שהן TRUE. הפסיק חשוב: הוא מפריד בין סינון השורות לבין סינון העמודות (הריק). subset(df, score > 80) עושה את אותו הדבר עם פחות הקלדה.
איך מסננים עם כמה תנאים ב-R?
משלבים תנאים עם & (AND) ו-| (OR): df[df$score > 80 & df$team == "red", ]. השתמשו ב-& הבודד, לא ב-&&: הצורה הכפולה עובדת רק על ערכים בודדים ונותנת שגיאה על וקטורים ב-R מודרנית.
מה ההבדל בין subset() לסינון בסוגריים ב-R?
שניהם משאירים את אותן שורות, עם שני הבדלים: subset() משמיטה בשקט שורות שבהן התנאי הוא NA (הסוגריים משאירים אותן כשורות מלאות ב-NA), ו-subset() משתמשת בהערכה לא סטנדרטית: כותבים שמות עמודות חשופים, וזה נוח בעבודה אינטראקטיבית אבל לא אמין בתוך פונקציות שאתם כותבים.
איך מסננים שורות שבהן עמודה תואמת לרשימת ערכים?
השתמשו ב-%in%: df[df$team %in% c("red", "blue"), ] משאיר שורות שהצוות שלהן הוא אחד מהערכים ברשימה. זה מחליף שרשרת של השוואות == שמחוברות ב-|, ובניגוד ל-==, זה אף פעם לא מחזיר NA.