Typy danych w R
Każda wartość w R ma jeden z niewielkiego zestawu typów atomowych. Cztery z nich wykonują prawie całą pracę:
- double: liczby dziesiętne, np.
3.14,-2,1e6. To właśnie R ma na myśli, mówiąc "numeric", i to domyślny typ każdej wpisanej liczby. - integer: liczby całkowite przechowywane dokładnie, zapisywane z sufiksem
L:42L. - character: tekst w cudzysłowie:
"hello". - logical: dwie wartości logiczne
TRUEiFALSE(orazNA, wartość brakująca; zobacz brakujące wartości).
Jest też complex (2 + 3i) do okazjonalnej matematyki przetwarzania sygnałów; można latami obyć się bez niego. typeof() mówi, jaki typ ma wartość:
Zwróć uwagę na pierwszą linię: zwykła liczba to double, nawet jeśli wygląda na całkowitą. typeof(42) to "double"; tylko 42L jest liczbą całkowitą. W codziennej analizie różnica rzadko ma znaczenie, bo R po cichu konwertuje między nimi, ale wyjaśnia wiele mylących wyników typeof().
typeof() a class(): dlaczego się różnią
R ma dwie funkcje, które wyglądają, jakby odpowiadały na pytanie "czym to jest?", ale odpowiadają na nieco inne pytania.
typeof()podaje typ przechowywania: jak wartość leży w pamięci.class()podaje typ zachowania: etykietę, której mechanizm wywoływania metod w R używa, żeby zdecydować na przykład, któreprintczysummaryuruchomić.
Dla prostych wartości odpowiedzi różnią się tylko słownictwem:
typeof() mówi double (przechowywanie), class() mówi numeric (zachowanie). Dla struktur różnica rośnie:
Macierz jest przechowywana jako zwykły wektor liczb całkowitych, ale zachowuje się jak macierz: to class() mówi R, żeby wypisać ją jako siatkę. Ten sam podział widać przy ramkach danych (typeof mówi "list", class mówi "data.frame") i datach (typeof mówi "double", class mówi "Date").
Praktyczna zasada: używaj class(), gdy chcesz wiedzieć, czym coś jest w codziennym sensie, a typeof(), gdy debugujesz, co R robi pod maską.
Sprawdzanie typów przez is.*()
Każdy typ ma odpowiadającą mu funkcję sprawdzającą, która zwraca TRUE lub FALSE. Przydaje się wewnątrz funkcji, które muszą walidować dane wejściowe:
Jedna pułapka, o której warto wiedzieć: is.numeric() zwraca TRUE zarówno dla double, jak i integer (obie są liczbami), ale is.integer() sprawdza sposób przechowywania, więc dla zwykłego 42 zwraca FALSE:
Jeśli kiedyś zaskoczyło cię, że is.integer(7) zwraca FALSE dla liczby, która w sensie matematycznym oczywiście jest całkowita, to właśnie dlatego. 7 to double; 7L to integer.
Konwersja typów przez as.*()
Jawna konwersja korzysta z rodziny as.*, po jednej funkcji na typ docelowy:
Dwa zachowania warto zapamiętać. as.integer() obcina w stronę zera zamiast zaokrąglać: 7.9 staje się 7. A gdy konwersja nie ma sensu, R nie zgłasza błędu; zwraca NA i wyświetla ostrzeżenie:
Uruchom to, a zobaczysz NA i ostrzeżenie "NAs introduced by coercion". To naprawdę przydatne: zamień całą kolumnę nieuporządkowanego tekstu na liczby, a wpisy, których nie da się sparsować, staną się NA, zamiast wywrócić skrypt. Oznacza to jednak także, że ciche NA może wkraść się do danych. Gdy konwersja jest ważna, sprawdź potem, czy nie pojawiły się nowe NA.
Wartości logiczne konwertują się do liczb i z powrotem tak, jak można by się spodziewać: as.numeric(TRUE) to 1, as.logical(0) to FALSE. Dlatego sum() wektora logicznego zlicza wartości TRUE:
Niejawna koercja: zasada jednego typu w wektorach
Atomowy wektor w R może przechowywać tylko jeden typ. Połącz różne wartości przez c(), a R po cichu podniesie wszystko do najbardziej elastycznego obecnego typu według stałej drabiny:
logical → integer → double → character
Wartości logiczne stały się 1 i 0, liczby całkowite stały się double, a w ostatniej linii wszystko stało się tekstem. Character zawsze wygrywa, bo każdą wartość da się zapisać jako napis. Możesz to potwierdzić przez typeof():
Koercja to główne źródło błędów typu "dlaczego moja kolumna jest tekstem?": jeden zabłąkany napis "N/A" w kolumnie liczb zamienia cały wektor na character. Gdy tak się stanie, najpierw popraw problematyczną wartość, a potem przekonwertuj z powrotem przez as.numeric().
Co warto zapamiętać
- Cztery podstawowe typy: double ("numeric"), integer (
42L), character, logical. typeof()= jak coś jest przechowywane;class()= jak się zachowuje.3.14todouble, który zachowuje się jaknumeric.- Sprawdzaj przez
is.numeric()i pokrewne; konwertuj przezas.numeric()i pokrewne. Nieudana konwersja dajeNAz ostrzeżeniem, nie błąd. - Wektory przechowują tylko jeden typ; mieszanie powoduje koercję według logical → integer → double → character.
Dalej: bliższe spojrzenie na typy liczbowe, czyli zaokrąglanie, funkcje matematyczne i niespodzianki arytmetyki zmiennoprzecinkowej, które występują w każdym języku.
Najczęściej zadawane pytania
Jakie są podstawowe typy danych w R?
Typy atomowe to double (liczby dziesiętne, które R nazywa "numeric"), integer (liczby całkowite zapisywane z sufiksem L, np. 42L), character (tekst w cudzysłowie), logical (TRUE/FALSE) i rzadko używany complex. Wszystko większe (wektory, ramki danych, listy) jest zbudowane z tych typów.
Czym różni się typeof() od class() w R?
typeof() podaje, jak wartość jest przechowywana w pamięci (typ niskopoziomowy); class() podaje, jak wartość się zachowuje, co decyduje o tym, które metody wywoła R. Dla zwykłej liczby dziesiętnej różnią się słownictwem (typeof(3.14) to "double", a class(3.14) to "numeric"), a dla struktur takich jak ramki danych typeof() mówi "list", a class() mówi "data.frame".
Jak konwertować typy w R?
Użyj rodziny as.*: as.numeric("3.5") daje 3.5, as.character(42) daje "42", as.integer(7.9) obcina do 7. Gdy konwersja jest niemożliwa, R zwraca NA i zgłasza ostrzeżenie zamiast błędu: as.numeric("abc") to NA.
Czym jest koercja w R?
Gdy łączysz różne typy w jednym wektorze, R po cichu zamienia wszystko na najbardziej elastyczny typ według kolejności logical → integer → double → character. Dlatego c(1, 2, "three") staje się wektorem tekstowym: "1" "2" "three".