Jak pracować z potokami?

Przetwarzanie danych składa się najczęściej z wielu kroków. Wykonujemy operację A, później B, później C itp.

Ważne jest aby patrząc na kod R było łatwo zrozumieć jakie operacje są wykonywane.

Potoki to mechanizm wprowadzony niedawno do R, ale który szybko zdobył wielu zwolenników, ponieważ bardzo ułatwia pracę z przetwarzaniem danych.

Problem cebulki

Aby przedstawić potoki, rozpatrzmy najpierw taką serię czterech instrukcji.

library(dplyr)
library(PogromcyDanych)

# tylko volkswagen
tylkoVolkswagen <- filter(auta2012, 
                          Marka == "Volkswagen")
# posortowane
posortowaneVolkswagen <- arrange(tylkoVolkswagen, 
                                 Cena.w.PLN)
# tylko Golf VI
tylkoGolfIV <- filter(posortowaneVolkswagen, 
                      Model == "Golf", Wersja == "IV")
# tylko z małym przebiegiem
tylkoMalyPrzebieg <- filter(tylkoGolfIV, 
                            Przebieg.w.km < 50000)

W języku R można wynik jednej funkcji bezpośrednio przekazać jako argument kolejnej funkcji. Z tego powodu, aby skrócić zapis często stosuje się zapis ,,na wielką cebulkę''.

Mało czytelny, choć często spotykany zapis.

tylkoMalyPrzebieg <- 
  filter(
    filter(
      arrange(
        filter(
          auta2012, 
          Marka == "Volkswagen"), 
        Cena.w.PLN), 
      Model == "Golf", Wersja == "IV"), 
    Przebieg.w.km < 50000)

Taką cebulkę czyta się od środka na zewnątrz. Najpierw wykonywane jest filtrowanie, później sortowanie, później jeszcze dwa razy sortowanie.

Jednak taki zapis nie jest czytelny. Nazwy funkcji znajdują się z jednej strony a pozostałe argumenty po prawej stronie. Przy dłuższych cebulkach łatwo się pomylić, które argumenty są do których funkcji.

Jak działa operator potoku?

Rozwiązaniem problemu cebulki jest stosowanie specjalnego operatora do przetwarzania potokowego %>%. Ten operator pochodzi z pakietu magrittr (cytując z jego dokumentacji: to be pronounced with a sophisticated french accent) i jest dostępny po włączeniu pakietu dplyr.

Instrukcja a %>% f(b) jest równoważna instrukcjif(a, b).

Można też opisać go następująco: Operator przekazuje lewą stronę jako pierwszy argument funkcji wskazanej z prawej strony.

Potoki w akcji

Cebulka, którą powyżej opisaliśmy powyżej może być zapisana równoważnie w następujący, znacznie bardziej czytelny, sposób.

Dla takich potoków, dodatkowo można zastosować operator przypisania -> dzięki czemu kolejność czytania takiego potoku jest konsekwentnie od lewej do prawej.

auta2012 %>%                                    # weź dane o autach
  filter(Marka == "Volkswagen") %>%             # pozostaw tylko Volkswageny
  arrange(Cena.w.PLN) %>%                       # posortuj malejąco po cenie
  filter(Model == "Golf", Wersja == "IV") %>%   # pozostaw tylko Golfy VI
  filter(Przebieg.w.km < 50000) ->              # pozostaw tylko auta o małym przebiegu
  tylkoMalyPrzebieg

head(tylkoMalyPrzebieg[,1:9])
##   Cena Waluta Cena.w.PLN Brutto.netto  KM  kW      Marka Model Wersja
## 1 4800    PLN       4800       brutto 150 110 Volkswagen  Golf     IV
## 2 7500    PLN       7500       brutto  75  55 Volkswagen  Golf     IV
## 3 8000    PLN       8000       brutto 100  74 Volkswagen  Golf     IV
## 4 8300    PLN       8300       brutto  NA  NA Volkswagen  Golf     IV
## 5 8500    PLN       8500       brutto  75  55 Volkswagen  Golf     IV
## 6 8500    PLN       8500       brutto 100  74 Volkswagen  Golf     IV

Funkcje z pakietu dplyr są tak zdefiniowane by pierwszym argumentem był zawsze zbiór danych. Przez to domyślne zachowanie operatora %>% pozwala na taki skrótowy zapis.

Dla funkcji, które zbiór danych przyjmują jako drugi lub kolejny argument można miejsce gdzie należy wstawić lewą stronę operatora %>% wskazać symbolem ..

W poniższym przykładzie zbiór danych iris zostanie wstawiony do jako argument data= ponieważ to miejsce wskazuje symbol ..

iris %>%
  lm(Sepal.Length~Species, data=.) %>%
  coef

Wynikiem funkcji lm() jest model liniowy. Również on może być przekazany operatorem %>% dalej.

Na powyższym przykładzie jest on przekazany do funkcji coef(). Jeżeli jest to jedyny argument tej funkcji, to można pominąć nawiasy, operatora %>% i tak będzie wiedział że należy tę funkcję wywołać.