R Language
Pipe-operators (%>% en andere)
Zoeken…
Invoering
magrittr
, beschikbaar in magrittr
, dplyr
en andere R-pakketten, verwerken een data-object met een reeks bewerkingen door het resultaat van de ene stap als invoer voor de volgende stap door te geven met infix-operators in plaats van de meer typische R-methode van genest functie oproepen.
Merk op dat het beoogde doel van pijpexploitanten is om de leesbaarheid van geschreven code door mensen te verbeteren. Zie het gedeelte Opmerkingen voor prestatieoverwegingen.
Syntaxis
lhs%>% rhs # pijpsyntaxis voor
rhs(lhs)
lhs%>% rhs (a = 1) # pijpsyntaxis voor
rhs(lhs, a = 1)
lhs%>% rhs (a = 1, b =.) # syntaxis van de pijp voor
rhs(a = 1, b = lhs)
lhs% <>% rhs # pijpsyntaxis voor
lhs <- rhs(lhs)
lhs% $% rhs (a) # pipe-syntaxis voor
with(lhs, rhs(lhs$a))
lhs% T>% rhs # pijpsyntaxis voor
{ rhs(lhs); lhs }
parameters
lhs | rhs |
---|---|
Een waarde of de tijdelijke aanduiding voor magrittr. | Een functieaanroep met behulp van de semantiek van magrittr |
Opmerkingen
Pakketten die %>%
De magrittr
is gedefinieerd in het magrittr
pakket, maar het kreeg een enorme zichtbaarheid en populariteit met het dplyr
pakket (dat de definitie uit magrittr
). Nu maakt het deel uit van tidyverse
, een verzameling pakketten die "in harmonie werken omdat ze gemeenschappelijke gegevensrepresentaties en API-ontwerp delen" .
Het magrittr
pakket biedt ook verschillende variaties van de magrittr
voor degenen die meer flexibiliteit in leidingen willen, zoals de samengestelde toewijzingspijp %<>%
, de expositiepijp %$%
en de tee-operator %T>%
. Het biedt ook een reeks aliasfuncties ter vervanging van algemene functies met een speciale syntaxis ( +
, [
, [[
, enz.) Zodat ze gemakkelijk kunnen worden gebruikt in een reeks pijpen.
Documentatie zoeken
Zoals bij elke infix-operator (zoals +
, *
, ^
, &
, %in%
), kunt u de officiële documentatie vinden als u deze tussen aanhalingstekens plaatst ?'%>%'
Of help('%>%')
( ervan uitgaande dat u een pakket hebt geladen dat pkg:magrittr
hecht pkg:magrittr
).
sneltoetsen
Er is een speciale sneltoets in RStudio voor de pijpexploitant : Ctrl+Shift+M
( Windows & Linux ), Cmd+Shift+M
( Mac ).
Prestatieoverwegingen
Hoewel de pijpexploitant nuttig is, moet u zich ervan bewust zijn dat er een negatieve invloed is op de prestaties, voornamelijk vanwege de overhead van het gebruik ervan. Overweeg de volgende twee dingen zorgvuldig bij het gebruik van de buisoperator:
- Machineprestaties (lussen)
- Evaluatie (
object %>% rm()
verwijdert geenobject
)
Basisgebruik en ketting
De pijpexploitant, %>%
, wordt gebruikt om een argument in een functie in te voegen. Het is geen magrittr
van de taal en kan alleen worden gebruikt na het koppelen van een pakket dat dit biedt, zoals magrittr
. De pijpexploitant neemt de linkerkant (LHS) van de pijp en gebruikt deze als het eerste argument van de functie aan de rechterkant (RHS) van de pijp. Bijvoorbeeld:
library(magrittr)
1:10 %>% mean
# [1] 5.5
# is equivalent to
mean(1:10)
# [1] 5.5
De pijp kan worden gebruikt om een reeks functieaanroepen te vervangen. Met meerdere pijpen kunnen we de volgorde van links naar rechts lezen en schrijven, in plaats van van binnen naar buiten. Stel bijvoorbeeld dat we years
als een factor hebben gedefinieerd, maar deze willen omzetten in een cijfer. Om mogelijk informatieverlies te voorkomen, converteren we eerst naar karakter en vervolgens naar numeriek:
years <- factor(2008:2012)
# nesting
as.numeric(as.character(years))
# piping
years %>% as.character %>% as.numeric
Als we niet willen dat de LHS (linkerkant) wordt gebruikt als het eerste argument op de RHS (rechterkant), zijn er tijdelijke oplossingen, zoals het benoemen van de argumenten of het gebruik .
om aan te geven waar de leidinginvoer naartoe gaat.
# 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"
Functionele sequenties
Gezien een reeks stappen die we herhaaldelijk gebruiken, is het vaak handig om het in een functie op te slaan. Met pijpen kunnen dergelijke functies in een leesbaar formaat worden opgeslagen door een reeks met een punt te starten zoals in:
. %>% RHS
Stel bijvoorbeeld dat we factordata hebben en het jaar willen extraheren:
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
We kunnen de samenstelling van de functie bekijken door de naam te typen of functions
:
read_year
# Functional sequence with the following components:
#
# 1. as.character(.)
# 2. as.Date(.)
# 3. year(.)
#
# Use 'functions' to extract the individual functions.
We hebben ook toegang tot elke functie door zijn positie in de volgorde:
read_year[[2]]
# function (.)
# as.Date(.)
Over het algemeen kan deze benadering nuttig zijn wanneer duidelijkheid belangrijker is dan snelheid.
Opdracht met% <>%
Het magrittr
pakket bevat een samengestelde toewijzingsinfix-operator, %<>%
, die een waarde bijwerkt door deze eerst in een of meer rhs
expressies te rhs
en vervolgens het resultaat toe te wijzen. Dit elimineert de noodzaak om tweemaal een objectnaam te typen (eenmaal aan elke zijde van de toewijzingsoperator <-
). %<>%
moet de eerste infix-operator in een keten zijn:
library(magrittr)
library(dplyr)
df <- mtcars
In plaats van te schrijven
df <- df %>% select(1:3) %>% filter(mpg > 20, cyl == 6)
of
df %>% select(1:3) %>% filter(mpg > 20, cyl == 6) -> df
De samengestelde toewijzingsoperator zal zowel df
pijpen als opnieuw toewijzen:
df %<>% select(1:3) %>% filter(mpg > 20, cyl == 6)
Inhoud wordt weergegeven met% $%
De operator voor de expositiepijp, %$%
, stelt de kolomnamen als R-symbolen in het linkerobject aan de rechterexpressie bloot. Deze operator is handig wanneer u functies inschakelt die geen data
(in tegenstelling tot bijvoorbeeld lm
) en die geen data.frame en kolomnamen als argumenten gebruiken (de meeste van de belangrijkste dplyr-functies).
Met de expositiepijpexploitant %$%
kan een gebruiker voorkomen dat een pijplijn wordt verbroken wanneer naar kolomnamen moet worden verwezen. Stel bijvoorbeeld dat u een data.frame wilt filteren en vervolgens een correlatietest op twee kolommen met 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 geeft de standaard %>%
pipe het data.frame door aan filter()
, terwijl de %$%
pipe de kolomnamen blootstelt aan cor.test()
.
De expositiepijp werkt als een pijpversie van de basis R with()
functies, en dezelfde objecten aan de linkerkant worden geaccepteerd als invoer.
Gebruik van de pijp met dplyr en ggplot2
De operator %>%
kan ook worden gebruikt om de uitvoer van dplyr naar ggplot te leiden. Dit creëert een uniforme exploratory data analysis (EDA) -pijplijn die gemakkelijk kan worden aangepast. Deze methode is sneller dan de aggregaties intern uitvoeren in ggplot en heeft het extra voordeel dat onnodige tussenliggende variabelen worden vermeden.
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")
Bijwerkingen creëren met% T>%
Sommige functies in R produceren een bijwerking (bijv. Opslaan, afdrukken, plotten, enz.) En retourneren niet altijd een betekenisvolle of gewenste waarde.
%T>%
(tee-operator) stelt u in staat om een waarde door te sturen naar een bijwerking-producerende functie terwijl de oorspronkelijke lhs
waarde intact blijft. Met andere woorden: de tee-operator werkt als %>%
, behalve dat de retourwaarden lhs
zelf zijn en niet het resultaat van de rhs
functie / uitdrukking.
Voorbeeld: maak, pijp, schrijf en retourneer een object. Als %>%
in dit voorbeeld in plaats van %T>%
zou worden gebruikt, zou de variabele all_letters
NULL
bevatten in plaats van de waarde van het gesorteerde object.
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
Waarschuwing: als u een object zonder naam naar save()
stuurt, krijgt u een object met de naam .
wanneer geladen in de werkruimte met load()
. Er is echter een oplossing mogelijk met behulp van een helperfunctie (die ook inline kan worden geschreven als een anonieme functie).
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")