Numeric ו-Integer: שני טיפוסי המספרים של R
R מאחסן מספרים בשתי דרכים. Numeric (מאוחסן כנקודה צפה בדיוק כפול) הוא ברירת המחדל: כל מספר שמקלידים הוא double אלא אם אומרים אחרת. Integer הוא טיפוס נפרד ומדויק למספרים שלמים, שמבקשים עם הסיומת L:
בפועל רק לעיתים רחוקות צריך להתעניין בזה: R ממיר ביניהם בשקט, ו-is.numeric() הוא TRUE לשניהם (ראו טיפוסי נתונים למערכת הטיפוסים המלאה). המקום היחיד שבו ההבחנה נחשפת הוא חילוק: / תמיד מחזיר double, גם בין שני מספרים שלמים:
מספרים שלמים מופיעים בעיקר כפלט של פונקציות ספירה (length(), seq_len(), nrow()) וכערכי אינדקס. כשצריך חילוק שלמים, ל-R יש אופרטור ייעודי, שמוסבר בהמשך.
משפחת העיגול
R נותן חמש דרכים לקצץ מספר, ולכל אחת משמעות שונה:
round(x, digits): למספר ספרות אחרי הנקודה (ברירת מחדל 0).floor(x): למטה, למספר השלם הקרוב, תמיד לכיוון מינוס אינסוף.ceiling(x): למעלה, תמיד לכיוון פלוס אינסוף.trunc(x): חותך את הספרות אחרי הנקודה, תמיד לכיוון אפס. שימו לב להבדל במספרים שליליים:trunc(-2.7)הוא-2, אבלfloor(-2.7)הוא-3.signif(x, digits): למספר ספרות משמעותיות, לא ספרות אחרי הנקודה:signif(123456, 2)הוא120000.
והפתעה מפורסמת אחת: round() משתמש בעיגול חצי לזוגי (עיגול בנקאי) על חצאים מדויקים, לפי תקן IEEE 754:
זה מדפיס 0 2 2 4: כל חצי מתעגל למספר הזוגי הקרוב. זה לא באג; זה מונע הטיה שיטתית כלפי מעלה כשסוכמים הרבה ערכים מעוגלים. אם דוח צריך עיגול של בית הספר, הוסיפו דחיפה זעירה או עצבו בשכבת התצוגה במקום.
פונקציות מתמטיות יומיומיות
הבסיס עובד בדיוק כמו שהייתם מנחשים:
sqrt() הוא השורש הריבועי, abs() הערך המוחלט, ^ הוא העלאה בחזקה, ו-exp(x) הוא e בחזקת x, כך ש-exp(1) הוא המספר של אוילר, בערך 2.718282.
הפונקציה היחידה שמכשילה אנשים היא log(). ב-R, log() הוא הלוגריתם הטבעי (בבסיס e), לא בבסיס 10:
השורה הראשונה מדפיסה בערך 4.60517, לא את ה-2 שקורא שחושב בבסיס 10 מצפה לו. פנו ל-log10() ול-log2() כשאתם מתכוונים לבסיסים האלה, או העבירו base = במפורש. (המוסכמה הזו סטנדרטית בכל הסטטיסטיקה, שבה הלוגריתם הטבעי הוא ברירת המחדל.)
מודולו %% וחילוק שלמים %/%
שני אופרטורים מכסים חשבון של שארית:
%% הוא המודולו (השארית): 17 חלקי 5 הוא 3 ושארית 2. %/% הוא חילוק שלמים: כמה פעמים 5 שלם נכנס ב-17. יחד הם מקיימים x == (x %/% y) * y + (x %% y).
השימוש הקלאסי ב-%% הוא בדיקת התחלקות:
עדינות אחת עם מספרים שליליים: %% של R מקבל את הסימן של המחלק (כמו Python, בשונה מ-C):
זה 2, לא -1: R עונה על השאלה "מה מוסיפים לכפולה של 3 כדי להגיע למינוס 7?", מה ששומר את התוצאות בטווח 0..2 עבור מחלק חיובי. שימושי לגלישה של אינדקסים; מפתיע אם אתם מגיעים מ-C או מ-Java.
ערכים מיוחדים: Inf, -Inf ו-NaN
המספרים של R עוקבים אחרי IEEE 754, ולכן חלק מהפעולות מפיקות ערכים מיוחדים במקום שגיאות:
1/0 הוא Inf (אינסוף), -1/0 הוא -Inf, ו-0/0, כמות שבאמת אינה מוגדרת, הוא NaN, "not a number". ההבחנה חשובה: Inf הוא תשובה ("גדול מכל דבר"), NaN הוא היעדר של תשובה. בודקים אותם עם פונקציות ייעודיות, כי == NaN אף פעם לא עובד:
שימו לב לשורה האחרונה: NaN נחשב גם NA, ולכן is.na() תופס אותו. עוד סיבה לכך ש-is.na() היא הבדיקה הסטנדרטית ל"האם הערך הזה לא שמיש?" (עוד בערכים חסרים).
R גם קורא וכותב כתיב מדעי באופן טבעי: 2.5e3 הוא 2500, ומספרים קטנים או גדולים מאוד מודפסים בכתיב e כברירת מחדל:
השתמשו ב-format(x, scientific = FALSE) (או באפשרות scipen) כשדוח צריך מספרים עשרוניים רגילים.
ההפתעה של הנקודה הצפה
כל שפה שמאחסנת מספרים עשרוניים בבינארי חולקת את זה, ו-R אינה יוצאת דופן:
FALSE, כי 0.1 + 0.2 הוא בעצם 0.30000000000000004. לא ל-0.1 ולא ל-0.2 יש ייצוג בינארי מדויק, והשגיאות הזעירות מצטברות. ההדפסה של R כברירת מחדל מסתירה את זה כי היא מציגה 7 ספרות משמעותיות, ולכן הבעיה מרגישה בלתי נראית עד שהשוואת == נכשלת.
הכלל: לעולם אל תשוו מספרים עשרוניים מחושבים עם ==. השתמשו ב-all.equal(), שמשווה בתוך סובלנות סבירה:
עטפו אותו ב-isTRUE() כי all.equal() מחזיר תיאור של ההבדל (ולא FALSE) כשהערכים שונים. לעבודה עם מספרים שלמים שבה הדיוק חשוב, מספרי integer מדויקים עד בערך 2.1 מיליארד, עוד סיבה לכך שקוד ספירה משתמש בטיפוס integer.
מה לקחת מכאן
- כל מספר מוקלד הוא double;
42Lיוצר integer, ו-/מחזיר double בכל מקרה. round()מעגל חצי לזוגי;floor/ceiling/trunc/signifכל אחת מקצצת אחרת, דעו לאיזו אתם מתכוונים.log()הוא הלוגריתם הטבעי; השתמשו ב-log10(), ב-log2()או ב-base =לבסיסים אחרים.%%נותן את השארית (הסימן לפי המחלק),%/%את המנה השלמה.1/0הואInf,0/0הואNaN, ו-0.1 + 0.2 != 0.3: השוו מספרים עשרוניים עםall.equal(), אף פעם לא עם==.
בהמשך: החצי השני של הנתונים היומיומיים, מחרוזות, והפונקציות ש-R נותן כדי לבנות, לעצב ולחפש בהן.
שאלות נפוצות
מה ההבדל בין numeric ל-integer ב-R?
Numeric (double) הוא ברירת המחדל של R לכל מספר שמקלידים: 42 הוא double אף שהוא נראה שלם. Integer הוא טיפוס אחסון נפרד שמבקשים עם הסיומת L: 42L. חילוק רגיל תמיד מחזיר double, גם בין מספרים שלמים; השתמשו ב-%/% לחילוק שלמים.
האם log() ב-R הוא הלוגריתם הטבעי?
כן: log(x) ב-R הוא הלוגריתם הטבעי (בבסיס e), לא בבסיס 10. השתמשו ב-log10() לבסיס 10, ב-log2() לבסיס 2, או ב-log(x, base = b) לכל בסיס. log(100) הוא בערך 4.605, לא 2.
איך round() עובד ב-R?
round(x, digits) מעגל למספר הספרות אחרי הנקודה שביקשתם, אבל חצאים מדויקים משתמשים ב"עיגול חצי לזוגי" (עיגול בנקאי): round(2.5) הוא 2 ו-round(3.5) הוא 4. זה תואם לתקן IEEE 754 ומקטין הטיה כשסוכמים ערכים מעוגלים, אבל זה מפתיע את מי שמצפה לעיגול של בית הספר.
למה 0.1 + 0.2 לא שווה ל-0.3 ב-R?
ערכי double מאוחסנים בבינארי, ול-0.1, 0.2 ו-0.3 אין ייצוג בינארי מדויק, ולכן 0.1 + 0.2 הוא בעצם 0.30000000000000004. לעולם אל תשוו מספרים עשרוניים מחושבים עם ==; השתמשו ב-isTRUE(all.equal(x, y)) או בדקו abs(x - y) < 1e-9.