R Language
Operatorzy rur (%>% i inni)
Szukaj…
Wprowadzenie
Operatory magrittr
, dostępne w magrittr
, dplyr
i innych pakietach R, przetwarzają obiekt danych przy użyciu sekwencji operacji, przekazując wynik jednego kroku jako dane wejściowe do następnego kroku za pomocą operatorów infix zamiast bardziej typowej metody zagnieżdżonej wywołania funkcji.
Zauważ, że zamierzonym celem operatorów potoków jest zwiększenie czytelności pisanego kodu przez człowieka. Uwagi dotyczące wydajności można znaleźć w sekcji Uwagi.
Składnia
lhs%>% rhs # składnia potoku dla
rhs(lhs)
lhs%>% rhs (a = 1) # składnia potoku dla
rhs(lhs, a = 1)
lhs%>% rhs (a = 1, b =.) # składnia potoku dla
rhs(a = 1, b = lhs)
lhs% <>% rhs # składnia potoku dla
lhs <- rhs(lhs)
lhs% $% rhs (a) # składnia potoku dla
with(lhs, rhs(lhs$a))
lhs% T>% rhs # składnia potoku dla
{ rhs(lhs); lhs }
Parametry
lhs | rhs |
---|---|
Wartość lub symbol zastępczy magrittr. | Wywołanie funkcji z wykorzystaniem semantyki magrittr |
Uwagi
Pakiety korzystające z %>%
Operator potoku jest zdefiniowany w pakiecie magrittr
, ale zyskał ogromną widoczność i popularność dzięki pakietowi dplyr
(który importuje definicję z magrittr
). Teraz jest częścią tidyverse
, która jest zbiorem pakietów, które „działają w harmonii, ponieważ mają wspólne reprezentacje danych i projekt interfejsu API” .
Pakiet magrittr
udostępnia również kilka odmian operatora potoku dla tych, którzy chcą większej elastyczności w orurowaniu, takich jak rura przypisania złożonego %<>%
, rura ekspozycyjna %$%
i operator tee %T>%
. Zapewnia także zestaw funkcji aliasowych do zastępowania typowych funkcji, które mają specjalną składnię ( +
, [
, [[
itd.)), Dzięki czemu można je łatwo używać w łańcuchu potoków.
Znajdowanie dokumentacji
Podobnie jak w przypadku dowolnego operatora infix (takiego jak +
, *
, ^
i &
%in%
), możesz znaleźć oficjalną dokumentację, jeśli umieścisz ją w cudzysłowie:? ?'%>%'
Lub help('%>%')
( zakładając, że załadowałeś pakiet, który dołącza pkg:magrittr
).
Skróty klawiszowe
W RStudio znajduje się specjalny skrót klawiszowy dla operatora potoku: Ctrl+Shift+M
( Windows i Linux ), Cmd+Shift+M
( Mac ).
Uwagi dotyczące wydajności
Chociaż operator potoku jest przydatny, należy pamiętać, że ma on negatywny wpływ na wydajność ze względu na ogólne koszty związane z jego użyciem. Korzystając z operatora potoku, weź pod uwagę następujące dwie rzeczy:
- Wydajność maszyny (pętle)
- Ocena (
object %>% rm()
nie usuwaobject
)
Podstawowe użycie i łączenie
Operator potoku, %>%
, służy do wstawienia argumentu do funkcji. Nie jest to podstawowa funkcja języka i może być używana tylko po dołączeniu pakietu, który ją udostępnia, takiego jak magrittr
. Operator potoku bierze lewą stronę (LHS) potoku i używa go jako pierwszego argumentu funkcji po prawej stronie (RHS) potoku. Na przykład:
library(magrittr)
1:10 %>% mean
# [1] 5.5
# is equivalent to
mean(1:10)
# [1] 5.5
Potoku można użyć do zastąpienia sekwencji wywołań funkcji. Wiele potoków pozwala nam odczytywać i zapisywać sekwencję od lewej do prawej, a nie od wewnątrz na zewnątrz. Załóżmy na przykład, że mamy years
zdefiniowane jako czynnik, ale chcemy przekonwertować je na liczbę. Aby zapobiec możliwej utracie informacji, najpierw konwertujemy na znaki, a następnie na liczby:
years <- factor(2008:2012)
# nesting
as.numeric(as.character(years))
# piping
years %>% as.character %>% as.numeric
Jeśli nie chcemy, aby LHS (lewa strona) był używany jako pierwszy argument na RHS (prawa strona), istnieją obejścia, takie jak nazywanie argumentów lub używanie .
aby wskazać, dokąd idzie potok wejściowy.
# example with grepl
# its syntax:
# grepl(pattern, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)
# note that the `substring` result is the *2nd* argument of grepl
grepl("Wo", substring("Hello World", 7, 11))
# piping while naming other arguments
"Hello World" %>% substring(7, 11) %>% grepl(pattern = "Wo")
# piping with .
"Hello World" %>% substring(7, 11) %>% grepl("Wo", .)
# piping with . and curly braces
"Hello World" %>% substring(7, 11) %>% { c(paste('Hi', .)) }
#[1] "Hi World"
#using LHS multiple times in argument with curly braces and .
"Hello World" %>% substring(7, 11) %>% { c(paste(. ,'Hi', .)) }
#[1] "World Hi World"
Sekwencje funkcjonalne
Biorąc pod uwagę sekwencję kroków, których używamy wielokrotnie, często przydatne jest przechowywanie go w funkcji. Rury umożliwiają zapisywanie takich funkcji w czytelnym formacie, rozpoczynając sekwencję kropką, jak w:
. %>% RHS
Jako przykład załóżmy, że mamy daty czynników i chcemy wyodrębnić rok:
library(magrittr) # needed to include the pipe operators
library(lubridate)
read_year <- . %>% as.character %>% as.Date %>% year
# Creating a dataset
df <- data.frame(now = "2015-11-11", before = "2012-01-01")
# now before
# 1 2015-11-11 2012-01-01
# Example 1: applying `read_year` to a single character-vector
df$now %>% read_year
# [1] 2015
# Example 2: applying `read_year` to all columns of `df`
df %>% lapply(read_year) %>% as.data.frame # implicit `lapply(df, read_year)
# now before
# 1 2015 2012
# Example 3: same as above using `mutate_all`
library(dplyr)
df %>% mutate_all(funs(read_year))
# if an older version of dplyr use `mutate_each`
# now before
# 1 2015 2012
Możemy przejrzeć skład funkcji, wpisując jej nazwę lub używając functions
:
read_year
# Functional sequence with the following components:
#
# 1. as.character(.)
# 2. as.Date(.)
# 3. year(.)
#
# Use 'functions' to extract the individual functions.
Możemy również uzyskać dostęp do każdej funkcji według jej pozycji w sekwencji:
read_year[[2]]
# function (.)
# as.Date(.)
Zasadniczo takie podejście może być przydatne, gdy jasność jest ważniejsza niż prędkość.
Przydział z% <>%
Pakiet magrittr
zawiera złożony operator magrittr
-operator %<>%
, który aktualizuje wartość, najpierw potokując ją do jednego lub więcej wyrażeń rhs
a następnie przypisując wynik. Eliminuje to konieczność dwukrotnego wpisywania nazwy obiektu (raz po każdej stronie operatora przypisania <-
). %<>%
musi być pierwszym operatorem infix w łańcuchu:
library(magrittr)
library(dplyr)
df <- mtcars
Zamiast pisać
df <- df %>% select(1:3) %>% filter(mpg > 20, cyl == 6)
lub
df %>% select(1:3) %>% filter(mpg > 20, cyl == 6) -> df
Operator przypisania złożonego zarówno potokuje, jak i ponownie przypisuje df
:
df %<>% select(1:3) %>% filter(mpg > 20, cyl == 6)
Ujawnianie treści za pomocą% $%
Operator potoku ekspozycyjnego, %$%
, wystawia nazwy kolumn jako symbole R w obiekcie po lewej stronie na wyrażenie po prawej stronie. Ten operator jest przydatny podczas data
strumieniowego do funkcji, które nie mają argumentu data
(w przeciwieństwie do, powiedzmy, lm
) i które nie biorą nazw data.frame i kolumn jako argumentów (większość głównych funkcji dplyr).
Operator potoku ekspozycyjnego %$%
pozwala użytkownikowi uniknąć zerwania potoku, gdy trzeba odwoływać się do nazw kolumn. Załóżmy na przykład, że chcesz przefiltrować ramkę danych, a następnie uruchomić test korelacji na dwóch kolumnach za pomocą cor.test
:
library(magrittr)
library(dplyr)
mtcars %>%
filter(wt > 2) %$%
cor.test(hp, mpg)
#>
#> Pearson's product-moment correlation
#>
#> data: hp and mpg
#> t = -5.9546, df = 26, p-value = 2.768e-06
#> alternative hypothesis: true correlation is not equal to 0
#> 95 percent confidence interval:
#> -0.8825498 -0.5393217
#> sample estimates:
#> cor
#> -0.7595673
Tutaj standardowa rura %>%
przepuszcza data.frame do filter()
, podczas gdy rura %$%
eksponuje nazwy kolumn na cor.test()
.
Rura ekspozycyjna działa jak wersja bazowa R with()
funkcjami with()
potokowanie, a te same obiekty po lewej stronie są akceptowane jako dane wejściowe.
Używanie potoku z dplyr i ggplot2
Operator %>%
może być również użyty do potokowania wyjścia dplyr do ggplot. Tworzy to ujednolicony potok analizy danych eksploracyjnych (EDA), który można łatwo dostosować. Ta metoda jest szybsza niż wewnętrzne agregowanie w ggplot i ma tę dodatkową zaletę, że pozwala uniknąć niepotrzebnych zmiennych pośrednich.
library(dplyr)
library(ggplot)
diamonds %>%
filter(depth > 60) %>%
group_by(cut) %>%
summarize(mean_price = mean(price)) %>%
ggplot(aes(x = cut, y = mean_price)) +
geom_bar(stat = "identity")
Tworzenie efektów ubocznych za pomocą% T>%
Niektóre funkcje w R wywołują efekt uboczny (np. Zapisywanie, drukowanie, drukowanie itp.) I nie zawsze zwracają znaczącą lub pożądaną wartość.
%T>%
(operator trójnik) umożliwia przesłanie wartości w funkcji ubocznym z produkcji zachowując pierwotne lhs
wartość nienaruszone. Innymi słowy: operator tee działa jak %>%
, z tym wyjątkiem, że zwracanymi wartościami jest sam lhs
, a nie wynik funkcji / wyrażenia rhs
.
Przykład: Utwórz, potokuj, pisz i zwracaj obiekt. Jeśli w tym przykładzie użyto %>%
zamiast %T>%
, to zmienna all_letters
zawierałaby NULL
zamiast wartości posortowanego obiektu.
all_letters <- c(letters, LETTERS) %>%
sort %T>%
write.csv(file = "all_letters.csv")
read.csv("all_letters.csv") %>% head()
# x
# 1 a
# 2 A
# 3 b
# 4 B
# 5 c
# 6 C
Ostrzeżenie: Potokowanie nienazwanego obiektu w celu save()
spowoduje utworzenie obiektu o nazwie .
po załadowaniu do obszaru roboczego za pomocą load()
. Możliwe jest jednak obejście za pomocą funkcji pomocniczej (którą można również zapisać jako funkcję anonimową).
all_letters <- c(letters, LETTERS) %>%
sort %T>%
save(file = "all_letters.RData")
load("all_letters.RData", e <- new.env())
get("all_letters", envir = e)
# Error in get("all_letters", envir = e) : object 'all_letters' not found
get(".", envir = e)
# [1] "a" "A" "b" "B" "c" "C" "d" "D" "e" "E" "f" "F" "g" "G" "h" "H" "i" "I" "j" "J"
# [21] "k" "K" "l" "L" "m" "M" "n" "N" "o" "O" "p" "P" "q" "Q" "r" "R" "s" "S" "t" "T"
# [41] "u" "U" "v" "V" "w" "W" "x" "X" "y" "Y" "z" "Z"
# Work-around
save2 <- function(. = ., name, file = stop("'file' must be specified")) {
assign(name, .)
call_save <- call("save", ... = name, file = file)
eval(call_save)
}
all_letters <- c(letters, LETTERS) %>%
sort %T>%
save2("all_letters", "all_letters.RData")