W R wszystko jest wektorem
Większość języków ma skalary, czyli pojedyncze wartości, a do tego jakiś typ kontenera na kilka z nich. R pomija skalar. Wektor to uporządkowany zbiór wartości jednego typu i to na nim zbudowane jest wszystko inne. Nawet coś, co wygląda na samotną liczbę, jest wektorem o długości 1:
c(), skrót od combine (połącz), pozwala zbudować wektor ręcznie. length() mówi, ile ma elementów. A samo 5 zwraca TRUE dla is.vector i ma długość 1: R nigdy nie przestaje pracować z wektorami, po prostu czasem są one bardzo krótkie.
Z tego projektu wynika, że kod R wygląda inaczej niż kod w Pythonie czy JavaScripcie: operacje, dla których gdzie indziej pisze się pętlę, działają na całych wektorach w jednym wyrażeniu. Dojdziemy do tego niżej.
Jedna zasada, którą warto przyswoić już teraz: wszystkie elementy wektora mają ten sam typ. Jeśli przekażesz c() mieszankę, nie będzie narzekać, tylko po cichu przekształci wszystko na najbardziej elastyczny obecny typ:
Napis w mieszance zamienia wszystko w napisy ("1", "TRUE"). Wartości logiczne wśród liczb stają się 1 i 0. Ta koercja (konwersja typów) działa według stałej hierarchii: logical → integer → double → character, i odbywa się bez ostrzeżenia. Dlatego zabłąkane "7" w kolumnie liczb może po cichu zamienić cały zbiór danych w tekst. Pełną hierarchię opisuje artykuł o typach danych; jeśli potrzebujesz przechowywać naprawdę mieszane wartości, do tego służą listy.
Generowanie ciągów: :, seq() i rep()
Wpisywanie każdego elementu do c() szybko się nudzi. R ma trzy skróty dla regularnych wzorców:
1:10to codzienny sposób: liczby całkowite od jednej granicy do drugiej, z krokiem 1.seq()go uogólnia: wybierz krok przezby =albo podaj, ile elementów chcesz, przezlength.out =, a R sam wyliczy odstępy.seq_len(n)tworzy liczby od1doni jest bezpiecznym sposobem budowania indeksów pętli: w przeciwieństwie do1:npoprawnie daje pusty wektor, gdynwynosi 0, zamiast liczyć wstecz1 0.rep()powtarza:times =powtarza cały wektor od początku do końca (1 2 1 2 1 2), aeach =powtarza każdy element w miejscu (1 1 1 2 2 2). Łatwo je pomylić; uruchom fragment i porównaj.
Indeksowanie: R liczy od 1
Nawiasy kwadratowe wyciągają elementy. Pierwszy element to [1], a nie [0]. Jeśli przychodzisz z Pythona albo JavaScriptu, to najczęstsze wczesne potknięcie:
Trzy rzeczy, przy których warto się zatrzymać:
- Możesz indeksować wektorem pozycji:
fruits[c(2, 4)]pobiera za jednym razem drugi i czwarty element. - Ujemne indeksy oznaczają „wszystko oprócz”.
fruits[-1]to wektor bez pierwszego elementu. To zupełnie coś innego niż w Pythonie, gdzie-1oznacza ostatni element. W jednym wywołaniu nie można mieszać indeksów dodatnich i ujemnych. fruits[0]nie jest błędem: zwraca pustycharacter(0). Błąd o jeden w R często daje ciche puste wyniki zamiast awarii, więc warto sprawdzićlength(), gdy coś dalej w kodzie wygląda na tajemniczo puste.
Elementy mogą też mieć nazwy, co daje trzeci sposób indeksowania, według etykiety:
Nazwane wektory działają jak lekka tablica wyszukiwania i sprawiają, że kod jest czytelny: prices["tea"] mówi, o co chodzi, a prices[2] nie.
Maski logiczne i which()
Najpotężniejszy sposób indeksowania to wektor logiczny, czyli maska wartości TRUE/FALSE o tej samej długości co dane. Dokładnie to daje każde porównanie na wektorze:
temps > 24 nie daje jednej odpowiedzi, tylko pięć, po jednej na element. Wstawienie tej maski do [ ] zostawia elementy, dla których maska ma wartość TRUE. Warunki łączysz przez & (i) oraz | (lub), które opisuje artykuł o operatorach.
which() tłumaczy maskę na pozycje: tutaj 2 3 5, czyli indeksy gorących odczytów. Sięgaj po nią, gdy musisz wiedzieć, gdzie są dopasowania: żeby je zgłosić albo zaindeksować inny wektor w tych samych miejscach. Do zwykłego filtrowania temps[temps > 24] jest bardziej bezpośrednie niż temps[which(temps > 24)].
Ten wzorzec filtrowania maską to kręgosłup praktycznie całej pracy z danymi w R. Wraca od razu, gdy filtrujesz wiersze ramki danych.
Obliczenia wektorowe i zasada recyklingu
Arytmetyka w R działa element po elemencie na całych wektorach, bez pętli:
Pierwsza linia to główna cecha: prices * 2 podwaja każdy element. Tam, gdzie inne języki potrzebują pętli for, R potrzebuje operatora, a forma wektorowa jest zarówno krótsza, jak i szybsza, bo pętla odbywa się pod spodem w zoptymalizowanym C. Pisz pętlę for, gdy każdy krok zależy od poprzedniego; do obliczeń element po elemencie używaj wektoryzacji.
Trzecia linia pokazuje zasadę recyklingu: gdy wektory mają różne długości, R powtarza krótszy, żeby pasował. c(10, 20) zostaje powtórzony do 10 20 10 20, co daje 11 22 13 24. Powtarzanie 2 na wektorze o długości 3 to dokładnie to, dzięki czemu zadziałało prices * 2: skalar to po prostu wektor o długości 1, który jest powtarzany.
Recykling działa czysto, gdy dłuższa długość jest dokładną wielokrotnością krótszej. Gdy nie jest, R i tak oblicza wynik i zgłasza ostrzeżenie:
Dostajesz 11 22 13 i ostrzeżenie, że długość dłuższego obiektu nie jest wielokrotnością długości krótszego. Traktuj to ostrzeżenie jak zgłoszenie błędu: częściowy recykling prawie nigdy nie jest tym, o co ci chodziło, i zwykle oznacza, że dwa wektory, które miały mieć tę samą długość, jej nie mają.
Sortowanie, odwracanie, usuwanie duplikatów
Trzy małe narzędzia, których będziesz używać cały czas:
sort() porządkuje wartości, rev() odwraca istniejącą kolejność bez sortowania, a unique() usuwa duplikaty, zachowując pierwsze wystąpienia. Żadna z nich nie modyfikuje x: jak prawie wszystko w R zwracają nowy wektor, a oryginał zostawiają w spokoju.
Najważniejsze informacje
- Wektor to podstawowa jednostka R: uporządkowany, jednego typu, a nawet pojedyncze wartości są wektorami o długości 1.
- Buduj przez
c(), generuj wzorce przez:,seq()irep()i pamiętaj, żec()po cichu przekształca mieszane typy. - Indeksowanie zaczyna się od 1; ujemne indeksy usuwają elementy; nazwy pozwalają indeksować według etykiety.
- Maski logiczne (
x[x > 5]) to idiom filtrowania w całym języku;which()zamienia maskę na pozycje. - Obliczenia są wektorowe, krótsze wektory są powtarzane, a ostrzeżenie o częściowym recyklingu oznacza, że masz błąd.
Dalej: listy, czyli kontener na wartości, które nie mają jednego wspólnego typu.
Najczęściej zadawane pytania
Jak utworzyć wektor w R?
Funkcją c() (skrót od combine, czyli połącz): x <- c(10, 20, 30). Dla regularnych ciągów użyj 1:10, seq(0, 1, by = 0.25) albo rep(0, 5). Każdy element musi ostatecznie mieć ten sam typ: jeśli mieszasz typy, R po cichu przekształca wszystkie na najbardziej elastyczny z nich.
Czy indeksowanie w R zaczyna się od 0 czy od 1?
Od 1. x[1] to pierwszy element, x[length(x)] ostatni. To zaskakuje każdego, kto przychodzi z Pythona, JavaScriptu albo C: nie ma elementu x[0] (zapytanie o niego zwraca pusty wektor, a nie błąd, więc taki bug jest cichy).
Co robi zasada recyklingu w R?
Gdy wykonujesz działania na dwóch wektorach różnej długości, R powtarza krótszy, aż dorówna dłuższemu. c(1, 2, 3, 4) + c(10, 20) daje 11 22 13 24. Jeśli dłuższa długość nie jest wielokrotnością krótszej, R i tak oblicza wynik, ale zgłasza ostrzeżenie. Traktuj to ostrzeżenie jak błąd.
Co robi which() w R?
Zamienia wektor logiczny na pozycje jego wartości TRUE. Jeśli x > 5 daje FALSE TRUE TRUE, to which(x > 5) daje 2 3. Używaj jej, gdy potrzebujesz samych pozycji; do zwykłego filtrowania prostsze jest indeksowanie bezpośrednio wektorem logicznym (x[x > 5]).