Menu

Liczby w R: numeric, integer i funkcje matematyczne

Praca z liczbami w R: numeric kontra integer, rodzina funkcji zaokrąglających, sqrt i log, operator modulo %% oraz wartości specjalne Inf i NaN.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Numeric i integer: dwa typy liczb w R

R przechowuje liczby na dwa sposoby. Numeric (zapisywany jako liczba zmiennoprzecinkowa podwójnej precyzji) jest domyślny: każda wpisana liczba to double, chyba że powiesz inaczej. Integer to osobny, dokładny typ liczb całkowitych, o który prosisz przyrostkiem L:

W praktyce rzadko musisz się tym przejmować: R po cichu konwertuje między nimi, a is.numeric() zwraca TRUE dla obu (pełny system typów opisuje artykuł o typach danych). Jedyne miejsce, w którym to rozróżnienie wychodzi na wierzch, to dzielenie: / zawsze zwraca double, nawet między dwiema liczbami całkowitymi:

Liczby całkowite pojawiają się głównie jako wynik funkcji liczących (length(), seq_len(), nrow()) i jako indeksy. Gdy potrzebujesz dzielenia całkowitego, R ma do tego osobny operator, opisany niżej.

Rodzina funkcji zaokrąglających

R daje pięć sposobów przycinania liczby, każdy o innym znaczeniu:

  • round(x, digits): do podanej liczby miejsc po przecinku (domyślnie 0).
  • floor(x): w dół do najbliższej liczby całkowitej, zawsze w stronę minus nieskończoności.
  • ceiling(x): w górę, zawsze w stronę plus nieskończoności.
  • trunc(x): odcina część ułamkową, zawsze w stronę zera. Zwróć uwagę na różnicę przy liczbach ujemnych: trunc(-2.7) to -2, ale floor(-2.7) to -3.
  • signif(x, digits): do podanej liczby cyfr znaczących, a nie miejsc po przecinku: signif(123456, 2) to 120000.

I jedna słynna niespodzianka: round() stosuje dla dokładnych połówek zaokrąglanie do parzystej (zaokrąglanie bankierskie), zgodnie ze standardem IEEE 754:

To wypisuje 0 2 2 4: każda połówka jest zaokrąglana do najbliższej liczby parzystej. To nie błąd: zapobiega systematycznemu zawyżaniu, gdy sumujesz wiele zaokrąglonych wartości. Jeśli raport wymaga zaokrąglania ze szkoły, dodaj malutką poprawkę albo formatuj wynik dopiero na etapie prezentacji.

Codzienne funkcje matematyczne

Podstawy działają dokładnie tak, jak się spodziewasz:

sqrt() to pierwiastek kwadratowy, abs() wartość bezwzględna, ^ to potęgowanie, a exp(x) to e do potęgi x, więc exp(1) to liczba Eulera, około 2.718282.

Funkcja, która myli ludzi, to log(). W R log() to logarytm naturalny (o podstawie e), a nie dziesiętny:

Pierwsza linia wypisuje mniej więcej 4.60517, a nie 2, którego oczekuje ktoś myślący o podstawie 10. Sięgaj po log10() i log2(), gdy chodzi o te podstawy, albo podawaj base = jawnie. (Ta konwencja jest standardem w statystyce, gdzie logarytm naturalny jest domyślny.)

Modulo %% i dzielenie całkowite %/%

Dwa operatory obsługują arytmetykę reszt:

%% to modulo (reszta z dzielenia): 17 podzielone przez 5 to 3 reszty 2. %/% to dzielenie całkowite: ile pełnych piątek mieści się w 17. Razem spełniają x == (x %/% y) * y + (x %% y).

Klasycznym zastosowaniem %% jest sprawdzanie podzielności:

Jedna subtelność przy liczbach ujemnych: %% w R przyjmuje znak dzielnika (jak w Pythonie, inaczej niż w C):

Wynik to 2, a nie -1: R odpowiada na pytanie "co dodać do wielokrotności 3, żeby dostać -7?", dzięki czemu przy dodatnim dzielniku wyniki mieszczą się w 0..2. To wygodne przy zawijaniu indeksów, ale zaskakujące dla osób przychodzących z C albo Javy.

Wartości specjalne: Inf, -Inf i NaN

Liczby w R działają według IEEE 754, więc niektóre operacje dają wartości specjalne zamiast błędów:

1/0 to Inf (nieskończoność), -1/0 to -Inf, a 0/0, czyli wielkość naprawdę nieokreślona, to NaN ("not a number", nie liczba). Rozróżnienie ma znaczenie: Inf jest odpowiedzią ("większe niż cokolwiek"), a NaN jej brakiem. Sprawdzasz je osobnymi funkcjami, bo == NaN nigdy nie działa:

Zwróć uwagę na ostatnią linię: NaN liczy się też jako NA, więc is.na() je wyłapuje. To kolejny powód, dla którego is.na() jest standardowym testem "czy ta wartość nadaje się do użytku?" (więcej w artykule o brakujących wartościach).

R natywnie czyta i zapisuje też notację naukową: 2.5e3 to 2500, a bardzo małe albo bardzo duże liczby domyślnie wypisują się w notacji z e:

Użyj format(x, scientific = FALSE) (albo opcji scipen), gdy raport wymaga zwykłego zapisu dziesiętnego.

Niespodzianka z liczbami zmiennoprzecinkowymi

Dotyczy to każdego języka, który przechowuje ułamki dziesiętne binarnie, i R nie jest wyjątkiem:

FALSE, bo 0.1 + 0.2 to w rzeczywistości 0.30000000000000004. Ani 0.1, ani 0.2 nie ma dokładnej reprezentacji binarnej, a malutkie błędy się kumulują. Domyślne wypisywanie w R ukrywa to, pokazując 7 cyfr znaczących, i dlatego problem wydaje się niewidoczny, dopóki porównanie == nie zawiedzie.

Zasada: nigdy nie porównuj obliczonych ułamków dziesiętnych przez ==. Użyj all.equal(), które porównuje z rozsądną tolerancją:

Owiń to w isTRUE(), bo all.equal() przy różnych wartościach zwraca opis różnicy (a nie FALSE). W pracy z liczbami całkowitymi, gdzie liczy się dokładność, typ integer jest dokładny do około 2.1 miliarda. To kolejny powód, dla którego kod liczący używa typu integer.

Co warto zapamiętać

  • Każda wpisana liczba to double; 42L tworzy integer, a / i tak zwraca double.
  • round() zaokrągla połówki do parzystej; floor/ceiling/trunc/signif przycinają każda inaczej, więc wiedz, której potrzebujesz.
  • log() to logarytm naturalny; dla innych podstaw użyj log10(), log2() albo base =.
  • %% daje resztę (znak zgodny z dzielnikiem), %/% iloraz całkowity.
  • 1/0 to Inf, 0/0 to NaN, a 0.1 + 0.2 != 0.3: porównuj ułamki przez all.equal(), nigdy przez ==.

Dalej: druga połowa codziennych danych, czyli napisy i funkcje, którymi R pozwala je budować, formatować i przeszukiwać.

Najczęściej zadawane pytania

Czym różni się numeric od integer w R?

Numeric (double) to domyślny typ R dla każdej wpisanej liczby: 42 jest typu double, choć wygląda na całkowitą. Integer to osobny typ przechowywania, o który prosisz przyrostkiem L: 42L. Zwykłe dzielenie zawsze zwraca double, nawet między liczbami całkowitymi; do dzielenia całkowitego użyj %/%.

Czy log() w R to logarytm naturalny?

Tak, log(x) w R to logarytm naturalny (o podstawie e), a nie dziesiętny. Użyj log10() dla podstawy 10, log2() dla podstawy 2 albo log(x, base = b) dla dowolnej podstawy. log(100) to około 4.605, a nie 2.

Jak działa round() w R?

round(x, digits) zaokrągla do podanej liczby miejsc po przecinku, ale dokładne połówki zaokrągla "do parzystej" (zaokrąglanie bankierskie): round(2.5) to 2, a round(3.5) to 4. Wynika to ze standardu IEEE 754 i zmniejsza obciążenie przy sumowaniu zaokrąglonych wartości, ale zaskakuje osoby, które oczekują zaokrąglania ze szkoły.

Dlaczego 0.1 + 0.2 nie równa się 0.3 w R?

Liczby double są przechowywane binarnie, a 0.1, 0.2 i 0.3 nie mają dokładnej reprezentacji binarnej, więc 0.1 + 0.2 to w rzeczywistości 0.30000000000000004. Nigdy nie porównuj obliczonych ułamków dziesiętnych przez ==; użyj isTRUE(all.equal(x, y)) albo sprawdź abs(x - y) < 1e-9.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ