Menu

מספרים ב-R: Numeric, Integer ופונקציות מתמטיות

עבודה עם מספרים ב-R: numeric מול integer, משפחת פונקציות העיגול, sqrt ו-log, אופרטור המודולו %%, והערכים המיוחדים Inf ו-NaN.

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

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.

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

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

להתחיל