Rozdział 10 Postać wąska i szeroka
Przechowywanie danych wiąże się nie tylko z różnymi formatami zapisu danych, ale także z różnymi możliwościami rozłożenia tych samych informacji na wiersze i kolumny. W analizie danych rozróżnia się dwa podstawowe typy przechowywania informacji: postać wąską i szeroką. “Po co taka różnorodność? Otóż w zależności od tego co z danymi chcemy zrobić czasem lepiej je mieć w takiej czy innej postaci” (Biecek 2016)
Przejście z jednej postaci do drugiej jest dość często wykonywaną operacją (nie tylko w R), choć przez wielu uznawaną za operację czasochłonną. Rozwiązaniem są funkcje pakietu tidyr
.
10.1 Postać wąska
Dane w postaci wąskiej mogą przypominać swoim kształtem rozwiązania bazodanowe (np. SQL
i pokrewne). Przykładowa baza danych zawiera 6-godz. sumy opadów atmosferycznych pobranych ze strony https://dane.imgw.pl. Dane dla kilku stacji zapisano do postaci wąskiej w pliku .rds udostępnionym pod adresem: http://enwo.pl/przetwarzanie/dane/opady.rds
- Wczytaj plik do środowiska R i nazwij go
dane
. - Zapoznaj się z jego strukturą za pomocą funkcji:
summary()
istr()
- Sprawdź dla ilu stacji dostępne są historyczne dane opadowe?
dane <- readRDS(gzcon(url("http://enwo.pl/przetwarzanie/dane/opady.rds")))
# ... Przyjrzyjmy się strukturze wczytanej bazy:
head(dane)
## data wartosc stacja
## 1 1966-01-01 00:00:00 NA 12560
## 2 1966-01-01 06:00:00 0.4 12560
## 3 1966-01-01 12:00:00 NA 12560
## 4 1966-01-01 18:00:00 0.0 12560
## 5 1966-01-02 00:00:00 1.1 12560
## 6 1966-01-02 06:00:00 NA 12560
# lub:
str(dane)
## 'data.frame': 220111 obs. of 3 variables:
## $ data : POSIXct, format: "1966-01-01 00:00:00" "1966-01-01 06:00:00" ...
## $ wartosc: num NA 0.4 NA 0 1.1 NA NA NA 0.8 NA ...
## $ stacja : num 12560 12560 12560 12560 12560 ...
# Policzmy ile wartości jest dla każdej stacji
table(dane$stacja)
##
## 12415 12520 12560
## 74543 73655 71913
Konwersja postaci wąskiej do szerokiej - spread()
Jest to typowy przykład wąskiej postaci bazy danych, który bardzo dobrze sprawdza się np. w rozwiązaniach z grupowaniem i agregowaniem wartości (group_by()
i summarise()
). Jeśli chcielibyśmy “przenieść” wartości dla stacji, tak aby znajdowały się one w kolumnach obok siebie możemy skorzystać z funkcji spread()
.
Funkcja spread()
wymaga zadeklarowania 3 argumentów: data
- zbioru danych, key
- nazwy kolumny, która zostanie przetransformowana jako nazwy nowych nagłówków kolumn, value
- nazwa kolumny z wartościami, którymi zostanie wypełniona tabela.
Sprawdźmy działanie tej funkcji na przykładzie zbioru dane
:
library(tidyr) # musimy pakiet aktywować / instalować jeśli uruchamiany po raz pierwszy
head(dane) # przypomnienie kształtu bazy
## data wartosc stacja
## 1 1966-01-01 00:00:00 NA 12560
## 2 1966-01-01 06:00:00 0.4 12560
## 3 1966-01-01 12:00:00 NA 12560
## 4 1966-01-01 18:00:00 0.0 12560
## 5 1966-01-02 00:00:00 1.1 12560
## 6 1966-01-02 06:00:00 NA 12560
wynik <- spread(dane, stacja, wartosc) # konwertujemy do postaci szerokiej
head(wynik) # i sprawdzamy otrzymany wynik
## data 12415 12520 12560
## 1 1966-01-01 00:00:00 0.0 NA NA
## 2 1966-01-01 06:00:00 NA NA 0.4
## 3 1966-01-01 12:00:00 0.0 NA NA
## 4 1966-01-01 18:00:00 0.9 0.0 0.0
## 5 1966-01-02 00:00:00 1.1 1.3 1.1
## 6 1966-01-02 06:00:00 NA NA NA
Zadania
- Sprawdź co się stanie jeśli odwrócisz kolejnosć argumentów
key
ivalue
? - Za pomocą funkcji
group_by()
orazsummarise()
oblicz roczną sumę opadów na każdej ze stacji a następnie wynik tego działania przekonwertuj do dowolnej postaci szerokiej
10.2 Postać szeroka
Często bardziej intuicyjna w działaniu jest postać szeroka, która wizualnie pozwala na przeglądnięcie większej liczby danych. Czasem taki format danych może nie być zgodny np. z niektórymi funkcjami graficznymi, stąd konieczność transformacji z postaci szerokiej do wąskiej.
Konwersja postaci szerokiej do wąskiej - gather()
Wczytaj zbiór ze średnimi miesięcznymi temperaturami powietrza w Polsce po 1971 r.: http://enwo.pl/przetwarzanie/dane/pl1.csv. Nazwij zbiór pl
i zapoznaj się z jego strukturą.
pl <- read.csv("http://enwo.pl/przetwarzanie/dane/pl1.csv")
head(pl)
## rok I II III IV V VI VII VIII IX X XI
## 1 1971 -2.96 0.37 -0.11 7.41 14.48 14.91 17.81 18.74 11.25 8.39 2.61
## 2 1972 -5.81 0.27 3.91 7.36 12.48 16.25 19.40 16.56 11.36 6.14 4.36
## 3 1973 -1.67 1.27 3.69 6.13 12.35 15.77 17.58 17.12 13.14 6.62 1.85
## 4 1974 0.06 2.29 4.37 6.89 10.75 14.04 15.62 17.70 13.40 6.29 3.86
## 5 1975 2.97 -0.56 3.87 6.58 13.35 15.40 18.55 18.27 15.79 7.98 1.75
## 6 1976 -1.97 -3.32 -0.85 6.72 11.95 15.09 18.06 15.31 12.58 7.59 4.71
## XII
## 1 3.02
## 2 -0.01
## 3 -0.72
## 4 2.73
## 5 0.88
## 6 -1.24
W przypadku funkcji gather()
służącej do konwertowania szerokiej postaci danych do wąskiej zestaw argumentów jest następujący: 1) data
- ramka danych, 2) key
oraz value
- etykiety nowych kolumn z kluczem i wartościami, 3) ...
- ustalenie kolumn które mają zostać przekonwertowane według schematu dla paczek dplyr/tidyr
(tj. bez ’’, z możliwością stosowania :
dla kolumny początkowej i końcowej, itp.)
W naszym przypadku ramkę danych pl
chcemy skonwertować tak, aby zawierała 3 kolumny: rok
, miesiac
, temperatura
.
wynik <- gather(data=pl, key="miesiac", value="temperatura", I:XII)
head(wynik)
## rok miesiac temperatura
## 1 1971 I -2.96
## 2 1972 I -5.81
## 3 1973 I -1.67
## 4 1974 I 0.06
## 5 1975 I 2.97
## 6 1976 I -1.97
10.3 Sklejanie i rozszczepianie kolumn
Ostatnie 2 ciekawe funkcje z pakietu tidyr
to sklejanie ( unite()
) i rozszczepianie kolumn ( seperate()
). Ze względu na ograniczenia czasowe polecam zapoznanie się z tymi funkcjami indywidualnie
Pamiętaj o cheat-sheet’ie łączącym najważniejsze funkcje pakietów: dplyr i tidyr https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf