R Language
Rohroperatoren (%>% und andere)
Suche…
Einführung
Pipe-Operatoren, die in magrittr
, dplyr
und anderen R-Paketen verfügbar sind, verarbeiten ein Datenobjekt unter Verwendung einer Folge von Operationen, indem das Ergebnis eines Schritts als Eingabe für den nächsten Schritt unter Verwendung von Infix-Operatoren anstelle der üblicheren R-Methode von verschachtelten übergeben wird Funktionsaufrufe.
Beachten Sie, dass das Ziel der Pipe-Operatoren darin besteht, die Lesbarkeit von geschriebenem Code für den Menschen zu verbessern. Weitere Informationen zur Leistung finden Sie im Abschnitt Anmerkungen.
Syntax
lhs%>% rhs # Pipe-Syntax für
rhs(lhs)
lhs%>% rhs (a = 1) # Pipe-Syntax für
rhs(lhs, a = 1)
lhs%>% rhs (a = 1, b =.) #
rhs(a = 1, b = lhs)
fürrhs(a = 1, b = lhs)
lhs% <>% rhs # Pipe-Syntax für
lhs <- rhs(lhs)
lhs% $% rhs (a) # Pipe-Syntax für
with(lhs, rhs(lhs$a))
lhs% T>% rhs # Pipe-Syntax für
{ rhs(lhs); lhs }
Parameter
lhs | rhs |
---|---|
Ein Wert oder der Magrittr-Platzhalter. | Ein Funktionsaufruf unter Verwendung der Magrittr-Semantik |
Bemerkungen
Pakete, die %>%
Der Pipe-Operator ist im magrittr
Paket definiert, er gewann jedoch mit dem dplyr
Paket (das die Definition aus magrittr
) große Sichtbarkeit und Beliebtheit. Jetzt ist es Teil von tidyverse
, einer Sammlung von Paketen, die "harmonisch zusammenarbeiten, weil sie gemeinsame Datenrepräsentationen und API-Design verwenden" .
Das magrittr
Paket bietet auch mehrere Variationen des Pipe-Operators für diejenigen, die mehr Flexibilität beim Paspeln wünschen, wie z. B. die zusammengesetzte Zuweisungspipe %<>%
, die Expositionspipe %$%
und den T-Operator %T>%
. Es bietet auch eine Reihe von Alias-Funktionen, um gängige Funktionen mit einer speziellen Syntax ( +
, [
, [[
usw.]) zu ersetzen, sodass sie problemlos innerhalb einer Pipeline-Kette verwendet werden können.
Dokumentation finden
Wie bei jedem Infix-Operator (wie +
, *
, ^
, &
, %in%
) finden Sie die offizielle Dokumentation, wenn Sie sie in Anführungszeichen setzen:? ?'%>%'
Oder help('%>%')
( Angenommen, Sie haben ein Paket geladen, das pkg:magrittr
) pkg:magrittr
.
Hotkeys
In RStudio gibt es einen speziellen Hotkey für den Pipe-Operator: Ctrl+Shift+M
( Windows und Linux ), Cmd+Shift+M
( Mac ).
Überlegungen zur Leistung
Beachten Sie, dass der Pipe-Operator nützlich ist. Beachten Sie jedoch, dass die Leistung hauptsächlich durch den Overhead der Verwendung beeinträchtigt wird. Berücksichtigen Sie bei der Verwendung des Pipe-Operators die folgenden beiden Punkte sorgfältig:
- Maschinenleistung (Schleifen)
- Auswertung (
object %>% rm()
entferntobject
)
Grundlegende Verwendung und Verkettung
Der Pipe-Operator %>%
wird verwendet, um ein Argument in eine Funktion einzufügen. Es ist keine magrittr
der Sprache und kann nur verwendet werden, nachdem ein Paket, das es bereitstellt, wie z. B. magrittr
, magrittr
. Der Pipe-Operator nimmt die linke Seite (LHS) der Pipe und verwendet sie als erstes Argument der Funktion auf der rechten Seite (RHS) der Pipe. Zum Beispiel:
library(magrittr)
1:10 %>% mean
# [1] 5.5
# is equivalent to
mean(1:10)
# [1] 5.5
Die Pipe kann verwendet werden, um eine Folge von Funktionsaufrufen zu ersetzen. Mehrere Pipes ermöglichen das Lesen und Schreiben der Sequenz von links nach rechts und nicht von innen nach außen. Angenommen, wir haben years
als Faktor definiert, möchten diesen jedoch in eine Zahl umwandeln. Um möglichen Informationsverlust zu vermeiden, konvertieren wir zuerst in Zeichen und dann in Zahlen.
years <- factor(2008:2012)
# nesting
as.numeric(as.character(years))
# piping
years %>% as.character %>% as.numeric
Wenn wir nicht möchten, dass die LHS (linke Seite) als erstes Argument auf der rechten Seite (rechte Seite) verwendet wird, gibt es Abhilfemaßnahmen, z .
um anzugeben, wohin die Pipe-Eingabe geht.
# 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"
Funktionsabläufe
Bei einer Reihe von Schritten, die wir wiederholt verwenden, ist es oft praktisch, sie in einer Funktion zu speichern. Pipes ermöglichen das Speichern solcher Funktionen in einem lesbaren Format, indem eine Sequenz mit einem Punkt wie folgt gestartet wird:
. %>% RHS
Angenommen, wir haben Faktordaten und möchten das Jahr extrahieren:
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
Wir können die Zusammensetzung der Funktion überprüfen, indem Sie ihren Namen eingeben oder functions
:
read_year
# Functional sequence with the following components:
#
# 1. as.character(.)
# 2. as.Date(.)
# 3. year(.)
#
# Use 'functions' to extract the individual functions.
Wir können auf jede Funktion auch über ihre Position in der Reihenfolge zugreifen:
read_year[[2]]
# function (.)
# as.Date(.)
Im Allgemeinen kann dieser Ansatz nützlich sein, wenn Klarheit wichtiger ist als Geschwindigkeit.
Zuordnung mit% <>%
Das magrittr
Paket enthält einen zusammengesetzten Zuweisungs-Infix-Operator %<>%
, der einen Wert aktualisiert, indem er ihn zuerst in einen oder mehrere rhs
Ausdrücke rhs
und dann das Ergebnis zuweist. Dadurch müssen Sie den Objektnamen nicht zweimal eingeben (einmal auf jeder Seite des Zuweisungsoperators <-
). %<>%
muss der erste Infix-Operator in einer Kette sein:
library(magrittr)
library(dplyr)
df <- mtcars
Anstatt zu schreiben
df <- df %>% select(1:3) %>% filter(mpg > 20, cyl == 6)
oder
df %>% select(1:3) %>% filter(mpg > 20, cyl == 6) -> df
Der zusammengesetzte Zuweisungsoperator leitet df
sowohl weiter als auch neu:
df %<>% select(1:3) %>% filter(mpg > 20, cyl == 6)
Inhalte mit% $% verfügbar machen
Der Exposition-Pipe-Operator %$%
macht die Spaltennamen als R-Symbole im linken Objekt für den Ausdruck auf der rechten Seite verfügbar. Dieser Operator ist praktisch , wenn in Funktionen Rohrleitungen, die keine haben data
( im Gegensatz zu , sagen wir, Argument lm
) und nehmen Sie nicht eine data.frame und Spaltennamen als Argumente ( die meisten der wichtigsten dplyr Funktionen).
Mit dem Exposition-Pipeline-Operator %$%
kann ein Benutzer verhindern, dass eine Pipeline beschädigt wird, wenn auf Spaltennamen verwiesen werden muss. Angenommen, Sie möchten ein data.frame filtern und dann mit cor.test
einen Korrelationstest für zwei Spalten 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
Hier durchläuft die standardmäßige Pipe %>%
das data.frame an filter()
, während die Pipe %$%
die Spaltennamen für cor.test()
.
Die Expositionspipe funktioniert wie eine Pipe-Version der Basis R with()
Funktionen, und die gleichen Objekte auf der linken Seite werden als Eingaben akzeptiert.
Verwendung der Pipe mit Dplyr und ggplot2
Der Operator %>%
kann auch verwendet werden, um die Ausgabe von dplyr an ggplot zu übergeben. Dadurch wird eine EDA-Pipeline (Unified Exploratory Data Analysis) geschaffen, die leicht anpassbar ist. Diese Methode ist schneller als die Aggregation intern in ggplot und hat den zusätzlichen Vorteil, dass unnötige Zwischenvariablen vermieden werden.
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")
Nebeneffekte mit% T>% erstellen
Einige Funktionen in R erzeugen einen Nebeneffekt (dh Speichern, Drucken, Plotten usw.) und geben nicht immer einen sinnvollen oder gewünschten Wert zurück.
%T>%
(Abschlagoperator) können Sie einen Wert in eine Nebeneffektfunktion lhs
wobei der ursprüngliche lhs
Wert erhalten bleibt. Mit anderen Worten: Der Tee-Operator funktioniert wie %>%
, nur dass die Rückgabewerte lhs
selbst sind und nicht das Ergebnis der rhs
Funktion / des rhs
Ausdrucks.
Beispiel: Ein Objekt erstellen, übermitteln, schreiben und zurückgeben. Wenn in diesem Beispiel %>%
anstelle von %T>%
, enthält die Variable all_letters
NULL
und nicht den Wert des sortierten Objekts.
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
Warnung: Wenn Sie ein nicht benanntes Objekt an save()
weiterleiten, wird ein Objekt mit dem Namen erzeugt .
wenn mit load()
in den Arbeitsbereich geladen. Eine Problemumgehung mithilfe einer Hilfsfunktion ist jedoch möglich (die auch als anonyme Funktion inline geschrieben werden kann).
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")