Menu

NA ב-R: טיפול בערכים חסרים (is.na, na.rm, na.omit)

NA פירושו "לא ידוע", והוא מתפשט דרך כל חישוב שהוא נוגע בו. איך מזהים אותו עם is.na(), מדלגים עליו עם na.rm = TRUE, ומסירים או מחליפים אותו במכוון.

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

NA פירושו "לא ידוע", והוא מתפשט

במאגרי נתונים אמיתיים יש חורים: שאלת הסקר שנשארה ריקה, החיישן שפספס מדידה. R מייצג כל חור כזה ב-NA, not available. המודל המנטלי המכריע: NA אינו אפס, אינו מחרוזת ריקה ואינו מספר מיוחד. הוא אומר "יש כאן ערך, אבל אנחנו לא יודעים מהו."

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

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

בדיקת NA: is.na(), אף פעם לא ==

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

x == NA מחזיר NA NA NA, אף TRUE אחד. למה? עקבו אחרי ההיגיון של "לא ידוע": האם 4 שווה לערך לא ידוע כלשהו? אי אפשר לדעת, הלא ידוע עשוי להיות 4. אפילו התא של ה-NA מושווה כ-NA: האם לא ידוע אחד שווה ללא ידוע אחר? לא ידוע. השוואה עם NA לעולם לא מחזירה TRUE או FALSE, ולכן כבדיקה היא חסרת תועלת, וגרוע מכך, מסכה שכולה NA בתוך [ ] לא בוחרת את מה שציפיתם.

הכלי הנכון הוא is.na(), שנבנה לענות בדיוק על השאלה הזו ומחזיר ערכים לוגיים כנים: FALSE TRUE FALSE. משם, שני ביטויים שתשתמשו בהם כל הזמן:

sum(is.na(x)) סופר את הערכים החסרים (TRUE נסכם כ-1): הריצו את זה על כל עמודה של מאגר נתונים חדש לפני כל דבר אחר. which(is.na(x)) מאתר אותם. ו-x[!is.na(x)] שומר רק את הערכים שנצפו: הסרה ידנית דרך מסכה לוגית, אותו דפוס סינון של וקטורים כמו תמיד.

דילוג על NA בסיכומים: na.rm = TRUE

בדרך כלל לא צריך להסיר NA ידנית, כי לפונקציות הסיכום של R יש פתח מילוט מובנה: הארגומנט na.rm (NA remove):

עם na.rm = TRUE, הפונקציה משמיטה את הערכים החסרים ומחשבת על מה שנשאר: הממוצע של 4 ו-8 הוא 6. sum(), sd(), median(), min(), max(), var(): כל המשפחה של סטטיסטיקה תיאורית מקבלת אותו.

שימו לב שברירת המחדל היא FALSE. זה R שמביע דעה לטובתכם: הוא רוצה שהתעלמות מנתונים חסרים תהיה בחירה מפורשת שאתם כותבים, לא ברירת מחדל שקטה. כשאתם מקלידים na.rm = TRUE, אתם מצהירים "בטוח להתעלם כאן מהערכים החסרים", וזה נכון כשחיישן פספס כמה מדידות באקראי, ושגוי באופן מסוכן כשלמשל בעלי ההכנסה הנמוכה ביותר דילגו על שאלת ההכנסה. הארגומנט גורם לכם לקחת אחריות על ההחלטה.

הסרת שורות לא שלמות: na.omit() ו-complete.cases()

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

na.omit(df) מחזיר את ה-data frame בלי כל שורה שמכילה לפחות NA אחד: כאן רק Rosa שורדת. complete.cases(df) מחזיר את מסכת השורות הלוגית (TRUE FALSE FALSE) שמאחורי אותו רעיון, וגישה באמצעותה נותנת תוצאות זהות עם שני יתרונות: אפשר קודם לספור מה עומדים לאבד (sum(!complete.cases(df))), ואפשר להגביל אילו עמודות חשובות: df[complete.cases(df[, "age"]), ] מסיר רק שורות שחסר בהן age, ושומר את Mia אף שהציון שלה לא ידוע.

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

החלפת NA

לפעמים הצעד הנכון הוא למלא חורים ולא למחוק שורות. הביטוי משלב את is.na() עם השמה:

קראו את זה כך: "בתאים שבהם visits חסר, שימו 0". זה לגיטימי בדיוק כש-NA מקודד ערך ידוע: ללקוח בלי רשומת ביקור באמת היו אפס ביקורים.

אבל היו כנים לגבי מתי זה נכון. אם NA פירושו "לא הצלחנו למדוד", החלפה ב-0 מפברקת נתונים: החלפת ציוני מבחן חסרים ב-0 מושכת את הממוצע למטה כאילו התלמידים האלה קיבלו אפס, כשבאמת אתם לא יודעים מה הם קיבלו. השוו את הממוצע למעלה (2.4) לממוצע עם na.rm של המקור (4): אותם נתונים, טענות שונות. החלפה בממוצע או בחציון מעוותת פחות, אבל עדיין ממעיטה בשונות. הכלל: השלימו ערך רק כשאתם יכולים להסביר במילים פשוטות למה הערך הזה הוא מה שהרשומה החסרה הייתה באמת. אחרת השאירו את ה-NA והשתמשו ב-na.rm: "לא ידוע" הוא לעיתים קרובות הערך הכי אמיתי במאגר הנתונים.

NA מול NULL מול NaN מול Inf

ל-R יש ארבעה ערכים מיוחדים שנראים דומים אבל אומרים דברים שונים באמת:

ערךמשמעותאורךמקור טיפוסי
NAערך קיים אבל לא ידוע1 (ממלא תא)נתונים חסרים
NULLאין אובייקט בכלל0 (אין תא)איבר רשימה שנמחק, תוצאה ריקה
NaNחישוב עם תשובה לא מוגדרת10 / 0, log(-1)
Infמספר מעבר לטווח הייצוג11 / 0, גלישה (overflow)

ההבחנות שחשובות בפועל: NULL נעלם בתוך וקטורים (ל-c(1, NULL, 3) יש שני איברים, הוא לא יכול לייצג תצפית חסרה), בעוד NA שומר על מקומו. NaN נחשב חסר (is.na(NaN) הוא TRUE, ולכן na.rm מסיר גם אותו), אבל ההפך לא נכון: is.nan(NA) הוא FALSE. ו-Inf אינו חסר: זה מספר אמיתי שאפשר להשוות (Inf > 1e300 הוא TRUE), ולכן na.rm לא יסיר אותו; השתמשו ב-is.finite() כדי לסנן למספרים רגילים.

לשם השלמות: NA מגיע בשקט בטעמים עם טיפוס (NA_integer_, NA_real_, NA_character_) כדי שיוכל לשבת בכל וקטור בלי לשבור את כלל הטיפוס האחד. רק לעיתים רחוקות תקלידו אותם, אבל תראו אותם בקוד של חבילות ובהודעות שגיאה של dplyr.

מה לקחת מכאן

  • NA פירושו "לא ידוע", ודברים לא ידועים מדבקים: כל חישוב שנוגע ב-NA מחזיר NA, בכוונה.
  • בדקו עם is.na(), אף פעם לא עם == NA; ספרו חורים עם sum(is.na(x)).
  • na.rm = TRUE גורם לפונקציות סיכום לדלג על NA: החלטה מפורשת, בכל קריאה, שמותר להתעלם מהערכים החסרים.
  • na.omit() מסיר שורות לא שלמות בסיטונאות; complete.cases() נותן לכם את המסכה, שאפשר לספור ולהגביל לעמודות שחשובות.
  • החליפו NA (x[is.na(x)] <- value) רק כשאתם יכולים להצדיק מה הערך החסר היה באמת.
  • NA ≠ NULL ≠ NaN ≠ Inf: ערך חסר, אובייקט נעדר, חישוב לא מוגדר, מספר לא חסום.

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

שאלות נפוצות

למה mean() מחזיר NA ב-R?

כי לפחות ערך אחד בווקטור הוא NA, ו-NA מדבק: אם קלט כלשהו לא ידוע, R אומר שגם התשובה לא ידועה. העבירו na.rm = TRUE, כלומר mean(x, na.rm = TRUE), כדי לחשב את הממוצע של הערכים הקיימים. רוב פונקציות הסיכום (sum, sd, median, min, max) מקבלות את אותו ארגומנט.

איך בודקים אם יש NA ב-R?

עם is.na(x), שמחזיר TRUE בכל מקום שבו ערך חסר. לעולם אל תבדקו עם x == NA: השוואה של כל דבר לערך לא ידוע מניבה NA, לא TRUE או FALSE, ולכן הבדיקה נכשלת בשקט. sum(is.na(x)) סופר את הערכים החסרים; which(is.na(x)) מוצא את המיקומים שלהם.

איך מסירים שורות עם NA מ-data frame ב-R?

na.omit(df) מסיר כל שורה שמכילה לפחות NA אחד. לשליטה רבה יותר, complete.cases(df) מחזיר וקטור לוגי שמסמן שורות שנצפו במלואן, כך ש-df[complete.cases(df), ] עושה את אותו הדבר במפורש, ואפשר להפעיל אותו רק על העמודות שחשובות, למשל df[complete.cases(df[, c("age", "score")]), ].

מה ההבדל בין NA ל-NULL ב-R?

NA הוא ערך חסר: הוא תופס מקום בווקטור ואורכו 1. NULL הוא היעדר של אובייקט: אורכו 0 והוא נעלם כשמכניסים אותו לווקטור: ל-c(1, NULL, 3) יש רק שני איברים. השתמשו ב-NA לנקודת נתונים חסרה; NULL מופיע כשמסירים איברים מרשימה או כערך החזרה ריק.

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

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

להתחיל