Listy i data frame'y
Poznałeś/aś już wektory i macierze, pora na odrobinę bardziej zaawansowane struktury danych. W tym rozdziale poznasz listy, ramki danych i typ czynnikowy.
Listy są trochę podobne do wektorów, ale ich elementy nie muszą mieć takiego samego typu. Nic nie stoi na przeszkodzie, żeby stworzyć listę zawierającą liczby, napisy i wartości logiczne jednocześnie. Tworzy się je za pomocą funkcji list(). Przykładowo:
> ( dane = list(imie = "walter", nazwisko = "white", wzrost = 171, czy_zonaty = TRUE ) ) $imie [1] "walter" $nazwisko [1] "white" $wzrost [1] 171 $czy_zonaty [1] TRUE > dane$imie # odwolujemy sie do nazwanych elementow listy za pomoca znaku dolara [1] "walter" > dane[["imie"]] # albo za pomoca podwojnych nawiasow kwadratowych, ale wtedy w cudzyslowie [1] "walter" > dane["imie"] # to tez zadziala, ale zwroci jednoelementowa liste $imie [1] "walter" > dane[[imie]] # to nie ma prawa zadzialac Error: object 'imie' not found > dane[1] # mozna tez odwolywac sie do indeksow $imie [1] "walter" > dane[2] $nazwisko [1] "white"
Przypominam, że zapis ze znakiem dolara pojawił się już przy wczytywaniu plików, gdzie okazało się, że plik wczytał nam się jako data.frame.
Ramki danych, czyli data frame'y (będę raczej posługiwać się nazwą angielską) są dla macierzy tym, czym listy dla wektorów - tzn. różnią się nieznacznie niektórymi funkcjami i zastosowaniami, a najbardziej rzucającą się w oczy różnicą jest to, że w przeciwieństwie do macierzy data frame potrafi trzymać wartości różnych typów:
> data.frame( jakies_liczby = c(12, 15, 128), wartosci_logiczne = c(TRUE, FALSE, TRUE), napisy = c("ala ma kota", "kot ma ale", "ola nie ma parasola") ) jakies_liczby wartosci_logiczne napisy 1 12 TRUE ala ma kota 2 15 FALSE kot ma ale 3 128 TRUE ola nie ma parasola
...ale uwaga, typy powinny się zgadzać w obrębie kolumn. Możesz spróbować do kolumny jakies_liczby dodać napisy, i nawet będzie wyglądało, że zadziałało, dopóki nie będziesz próbować na liczbach w tej kolumnie wykonać jakiegoś działania - wtedy zorientujesz się, że R tak naprawdę zdradziecko podmienił Ci Twoje wszystkie liczby na napisy.
Co ciekawego można robić na data frame'ach?
> data_frejm = data.frame(wzrost = c(123, 145, 167), waga = c(54, 43, 100) ) > rownames(data_frejm) = c("florek", "florcia", "matylda") # nadajemy nazwy wierszom > data_frejm wzrost waga florek 123 54 florcia 145 43 matylda 167 100 > data_frejm$wzrost # mozemy odwolac sie do kolumny za pomoca dolara [1] 123 145 167 > data_frejm$florek # do wiersza nie mozemy; bedzie NULL, bo nie ma kolumny florek NULL > data_frejm["florek", "waga"] [1] 54 > data_frejm[1] # to bedzie ciagle data frame wzrost florek 123 florcia 145 matylda 167 > > data_frejm[[1]] # a to jest wektor z pierwszej kolumny [1] 123 145 167 > data_frejm + 10 # dodawac mozna, czemu nie wzrost waga florek 133 64 florcia 155 53 matylda 177 110 > rbind(data_frejm, data_frejm) # zlaczyc dwa data frame'y w jeden; jesli nazwy wierszy sie powtarzaja, dodaje liczbe 1 wzrost waga florek 123 54 florcia 145 43 matylda 167 100 florek1 123 54 florcia1 145 43 matylda1 167 100 > cbind(data_frejm, data_frejm) # laczymy kolumnami wzrost waga wzrost waga florek 123 54 123 54 florcia 145 43 145 43 matylda 167 100 167 100 > data_frejm["zyta",] = c(198, 93) # dodajemy wartosci > data_frejm["franek","wzrost"] = 128 # tam, gdzie wartosci brakuje bedzie NA, not available > data_frejm wzrost waga florek 123 54 florcia 145 43 matylda 167 100 zyta 198 93 franek 128 NA
Zauważ, że nazwy kolumn mogą się powtarzać. Skąd R będzie wiedział, o którą z kolumn "wzrost" nam chodzi? Nie będzie wiedział :( Da nam po prostu pierwszą od lewej. Więc lepiej uważać z powtarzaniem nazw.
Specyficzną strukturą danych jest tzw. typ czynnikowy, po angielsku prostu factor. Wygląda on tak:
...czyli wygląda trochę jak zwyczajny wektor, tylko że linijkę niżej pada słowo "Levels" i w kolejności alfabetycznej wypisane są (bez powtórzeń) wszystkie wartości, które wystąpiły w naszym wektorze. W tym tutorialu factorom nie poświęcę zbyt wiele uwagi, ale warto je znać, chociażby żeby nie przestraszyć się, kiedy nagle okaże się, że kolumna w naszym data frame'ie ma jakieś Levele; a zdarzy się to, jeśli są w niej napisy:
> dane = data.frame( row.names = c("Danaerys", "Robb", "Joffrey"), nazwisko_rodowe = c("Targeryan", "Stark", "Baratheon"), wzrost = c(164, 169, 159)) > dane nazwisko_rodowe wzrost Danaerys Targeryan 164 Robb Stark 169 Joffrey Baratheon 159 > dane$wzrost # to bedzie zwykly wektor [1] 164 169 159 > dane$nazwisko_rodowe # a to juz bedzie factor! [1] Targeryan Stark Baratheon Levels: Baratheon Stark Targeryan