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

  1. Wczytaj plik do środowiska R i nazwij go dane.
  2. Zapoznaj się z jego strukturą za pomocą funkcji: summary() i str()
  3. 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

  1. Sprawdź co się stanie jeśli odwrócisz kolejnosć argumentów key i value?
  2. Za pomocą funkcji group_by() oraz summarise() 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