Operatory, które daje R
Operatory w R dzielą się na cztery robocze grupy: arytmetyczne (+ - * / ^ %% %/%), porównania (== != < <= > >=), logiczne (& | && || ! xor) oraz test przynależności %in%. Dwie rzeczy odróżniają je od większości języków: prawie wszystkie są wektorowe, czyli działają naraz na całych wektorach, element po elemencie, a R ma dwa operatory AND i dwa operatory OR, których nie można stosować zamiennie. Ta strona omawia je wszystkie oraz pułapki kolejności działań, które po cichu dają złe odpowiedzi.
Arytmetyka: +, -, *, /, ^, %% i %/%
Pierwsze pięć robi to, czego się spodziewasz. Dwa otoczone znakami procentu, czyli %% (modulo, reszta) i %/% (dzielenie całkowite, iloraz), to te, których ludzie szukają:
Zauważ, że / zawsze wykonuje dzielenie zmiennoprzecinkowe: 17 / 5 to 3.4, nigdy 3. Jeśli chcesz część całkowitą, właśnie do tego służy %/%.
Codzienną pracą %% jest sprawdzanie podzielności. Liczba jest parzysta, gdy dzielenie przez 2 nie zostawia reszty:
Na drugiej linii warto się zatrzymać: przy ujemnym argumencie %% w R zwraca wynik ze znakiem dzielnika (-7 %% 3 to 2, bo -7 = -3 * 3 + 2). Niektóre języki robią to odwrotnie; jeśli przenosisz kod, sprawdź to.
Operatory porównania są wektorowe
==, !=, <, <=, >, >= porównują element po elemencie i zwracają wektor logiczny, a nie jedną odpowiedź:
To silnik niemal całego filtrowania w R: porównujesz cały wektor z wartością, dostajesz maskę logiczną i używasz jej do wybrania podzbioru. Jedna przestroga przy == na ułamkach: liczby zmiennoprzecinkowe są przechowywane w przybliżeniu, więc 0.1 + 0.2 == 0.3 daje FALSE. Do porównań ułamków dziesiętnych wybieraj all.equal() albo sprawdzaj abs(x - y) < 1e-9.
Operatory logiczne: & kontra && (klasyczne pomieszanie)
R ma dwa operatory AND i dwa operatory OR, a wybranie złego to obowiązkowy rytuał przejścia.
& i | są wektorowe. Łączą dwa wektory logiczne element po elemencie:
Używaj ich zawsze, gdy budujesz filtr na danych: df[df$age > 30 & df$city == "Lisbon", ].
&& i || są skalarne i stosują skrócone obliczanie. Przyjmują pojedyncze wartości, zwracają jedno TRUE/FALSE i całkowicie pomijają drugi argument, jeśli pierwszy już rozstrzyga odpowiedź:
Druga linia pokazuje skrócone obliczanie: ponieważ x < 0 to FALSE, R nigdy nie wykonuje wywołania stop(). Właśnie dlatego && pasuje do warunków if(): możesz napisać if (!is.na(x) && x > 10), a część x > 10 zostanie bezpiecznie pominięta, gdy x to NA.
Praktyczna zasada: &/| do wektorów i filtrowania danych, &&/|| do warunków if(). Od R 4.3 jest to egzekwowane na serio: przekazanie do && albo || wektora o długości większej niż 1 to błąd (starsze wersje R po cichu brały tylko pierwszy element, co przez lata ukrywało prawdziwe błędy).
xor(a, b) uzupełnia zestaw: daje TRUE, gdy dokładnie jeden z dwóch argumentów jest TRUE:
%in%: sprawdzanie przynależności
x %in% table pyta dla każdego elementu x: "czy występuje on gdziekolwiek w table?". To jeden z najczęściej używanych operatorów w prawdziwym kodzie R:
Sprawdzana strona może być całym wektorem, dzięki czemu %in% jest naturalnym narzędziem do filtrowania wierszy według zbioru dozwolonych wartości.
Jest też lepszy od alternatywy, którą trzeba by inaczej napisać, czyli łańcucha == sklejonego przez |:
Przy pięciu dozwolonych wartościach łańcuch == zamienia się w ścianę powtórzeń, a wersja z %in% po prostu wydłuża wektor. Jest też druga, subtelniejsza przewaga: %in% nigdy nie zwraca NA:
NA == 1 daje NA, bo R nie może wiedzieć, czy nieznana wartość równa się 1. To zachowanie szczegółowo opisuje artykuł o brakujących wartościach. Takie NA zatruwa potem każde if(), do którego trafi. %in% omija cały problem, bo zawsze odpowiada TRUE albo FALSE, i dlatego jest bezpieczniejszym wyborem w warunkach na danych, w których mogą być braki.
Pułapki kolejności działań
Dwie pułapki kolejności operatorów odpowiadają za nieproporcjonalnie dużą część chwil "R jest zepsuty". Po pierwsze, ^ wiąże mocniej niż jednoargumentowy minus:
Po drugie, dwukropek wiąże mocniej niż dwuargumentowa arytmetyka:
W razie wątpliwości dodaj nawiasy. Nic nie kosztują, a każdy czytelnik (łącznie z tobą w przyszłości) odczyta je tak samo jak interpreter.
$ i [ ]: operatory dostępu
Stale będziesz też widzieć $, [ ] i [[ ]]. Technicznie to również operatory, tylko służą do wyciągania wartości ze struktur, a nie do obliczeń:
Szczegółowo omawiają je strony o wektorach, listach i ramkach danych; tutaj wystarczy rozpoznawać je jako członków tej samej rodziny operatorów.
Co warto zapamiętać
%%daje resztę,%/%iloraz całkowity;x %% 2 == 0sprawdza parzystość.- Porównania są wektorowe: zwracają wektor logiczny, którym możesz filtrować.
&/|łączą wektory element po elemencie;&&/||służą do pojedynczych wartości wif()i stosują skrócone obliczanie. Od R 4.3&&na dłuższym wektorze to błąd.x %in% tablezastępuje łańcuchy==i nigdy nie zwracaNA.-2^2to-4, a1:n - 1zaczyna się od 0: w razie wątpliwości dodawaj nawiasy.
Dalej: wykorzystanie tych operatorów w if, else i ifelse(), czyli instrukcjach warunkowych w R.
Najczęściej zadawane pytania
Co robi %% w R?
%% to operator modulo: zwraca resztę z dzielenia. 17 %% 5 to 2. Jego towarzysz %/% wykonuje dzielenie całkowite i zwraca iloraz bez reszty: 17 %/% 5 to 3. Klasyczne zastosowanie %% to sprawdzanie parzystości: x %% 2 == 0.
Czym różni się & od && w R?
& jest wektorowy: porównuje dwa wektory element po elemencie i zwraca wektor tej samej długości. && działa tylko na pojedynczych wartościach, stosuje skrócone obliczanie (pomija drugi argument, jeśli pierwszy już przesądza o wyniku) i zwraca dokładnie jedno TRUE albo FALSE. Używaj & do filtrowania wektorów, a && w warunkach if(). Od R 4.3 przekazanie do && albo || wektora dłuższego niż 1 to błąd, a nie ostrzeżenie.
Co robi %in% w R?
x %in% table sprawdza, czy każdy element x występuje gdziekolwiek w table, i zwraca TRUE albo FALSE dla każdego elementu. "mango" %in% basket zastępuje łańcuch porównań == połączonych przez |, a w przeciwieństwie do == nigdy nie zwraca NA: brakująca wartość po stronie sprawdzanej po prostu daje FALSE.
Dlaczego -2^2 zwraca -4 w R?
Ponieważ ^ wiąże mocniej niż jednoargumentowy minus, R czyta -2^2 jako -(2^2), czyli -4. Jeśli chodzi ci o kwadrat minus dwóch, napisz (-2)^2, co daje 4. Dwukropek ma podobną pułapkę: 1:n - 1 oznacza (1:n) - 1, a nie 1:(n - 1).