如何纯粹在 base R ('base pipe') 中进行管道传输?
How to pipe purely in base R ('base pipe')?
有没有一种方法可以在 base R 中进行管道传输,而无需定义您自己的函数(即某些东西 'out of the box'),并且无需加载任何外部包?
也就是说,magrittr 管道的一些(基础 R)替代品 %>%
。可能在即将发布的 R (?)
版本中
此功能在 R 4.0.3 中是否可用。如果不是,它是在哪个 R 版本中找到的,如果是,这是如何实现的?
您可以使用 bizarro pipe (also this),它只是对现有语法的巧妙使用,不需要函数或包。例如
mtcars ->.;
transform(., mpg = 2 * mpg) ->.; # change units
lm(mpg ~., .) ->.;
coef(.)
其中 ->.;
看起来有点像管道。
截至撰写此答案时,R (4.0.3) 的发行版不包含管道运算符。
但是,正如 useR! 2020 keynote 中所述,基础 |>
运算符正在开发中。
来自 R-devel daily source 2020-12-15 的 pipeOp
手册页:
A pipe expression passes, or pipes, the result of the lhs
expression to the rhs
expression.
If the rhs
expression is a call, then the lhs
is
inserted as the first argument in the call. So x |> f(y)
is
interpreted as f(x, y)
. To avoid ambiguities, functions in
rhs
calls may not be syntactically special, such as +
or
if
.
If the rhs
expression is a function
expression, then the
function is called with the lhs
value as its argument. This is
useful when the lhs
needs to be passed as an argument other than
the first in the rhs
call.
此运算符何时会进入发布版本,或者它是否会在发布之前发生更改,都是未知数。
在 R |>
中用作管道运算符。 (自 4.1.0 起)
左侧表达式 lhs 作为 第一个自由参数 插入到右侧表达式的调用中rhs.
mtcars |> head() # same as head(mtcars)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
mtcars |> head(2) # same as head(mtcars, 2)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
也可以在 rhs 调用中使用带有占位符 _
的 命名参数 来指定lhs 待插入。占位符只能在 rhs 上出现 一次。 (自 4.2.0 起)
mtcars |> lm(mpg ~ disp, data = _)
#mtcars |> lm(mpg ~ disp, _) #Error: pipe placeholder can only be used as a named argument
#Call:
#lm(formula = mpg ~ disp, data = mtcars)
#
#Coefficients:
#(Intercept) disp
# 29.59985 -0.04122
或者在“一”之前明确命名参数:
mtcars |> lm(formula = mpg ~ disp)
如果占位符被多次使用或在任何位置用作命名或未命名参数或用于禁用函数:使用(匿名)函数.
mtcars |> (\(.) .[.$cyl == 6,])()
#mtcars ->.; .[.$cyl == 6,] # Alternative using bizarro pipe
#local(mtcars ->.; .[.$cyl == 6,]) # Without overwriting and keeping .
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
mtcars |> (\(.) lm(mpg ~ disp, .))()
#Call:
#lm(formula = mpg ~ disp, data = .)
#
#Coefficients:
#(Intercept) disp
# 29.59985 -0.04122
1:3 |> setNames(object = _, nm = _)
#Error in setNames(object = "_", nm = "_") :
# pipe placeholder may only appear once
1:3 |> (\(.) setNames(., .))()
#1 2 3
#1 2 3
1:3 |> list() |> setNames(".") |> with(setNames(., .))
#1 2 3
#1 2 3
#The same but over a function
._ <- \(data, expr, ...) {
eval(substitute(expr), list(. = data), enclos = parent.frame())
}
1:3 |> ._(setNames(., .))
#1 2 3
#1 2 3
部分函数为disabled.
mtcars |> `$`(cyl)
#Error: function '$' not supported in RHS call of a pipe
但有些仍然可以通过将它们放在制动器中来调用,通过函数调用它们::
,在函数中调用它或在函数中定义一个link。
mtcars |> (`$`)(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> base::`$`(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> (\(.) .$cyl)()
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
fun <- `$`
mtcars |> fun(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
写成 x |> f(y)
的表达式被解析为 f(x, y)
。虽然管道中的代码是按顺序编写的,但适用于评估的常规 R 语义。因此,只有在 rhs 表达式中首次使用 时,管道表达式才会 求值。
-1 |> sqrt() |> (\(x) 0)()
#[1] 0
. <- -1
. <- sqrt(.)
#Warning message:
#In sqrt(.) : NaNs produced
(\(x) 0)(.)
#[1] 0
x <- data.frame(a=0)
f1 <- \(x) {message("IN 1"); x$b <- 1; message("OUT 1"); x}
f2 <- \(x) {message("IN 2"); x$c <- 2; message("OUT 2"); x}
x|> f1() |> f2()
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
f2(f1(x))
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
. <- x
. <- f1(.)
#IN 1
#OUT 1
f2(.)
#IN 2
#OUT 2
# a b c
#1 0 1 2
有没有一种方法可以在 base R 中进行管道传输,而无需定义您自己的函数(即某些东西 'out of the box'),并且无需加载任何外部包?
也就是说,magrittr 管道的一些(基础 R)替代品 %>%
。可能在即将发布的 R (?)
此功能在 R 4.0.3 中是否可用。如果不是,它是在哪个 R 版本中找到的,如果是,这是如何实现的?
您可以使用 bizarro pipe (also this),它只是对现有语法的巧妙使用,不需要函数或包。例如
mtcars ->.;
transform(., mpg = 2 * mpg) ->.; # change units
lm(mpg ~., .) ->.;
coef(.)
其中 ->.;
看起来有点像管道。
截至撰写此答案时,R (4.0.3) 的发行版不包含管道运算符。
但是,正如 useR! 2020 keynote 中所述,基础 |>
运算符正在开发中。
来自 R-devel daily source 2020-12-15 的 pipeOp
手册页:
A pipe expression passes, or pipes, the result of the
lhs
expression to therhs
expression.
If the
rhs
expression is a call, then thelhs
is inserted as the first argument in the call. Sox |> f(y)
is interpreted asf(x, y)
. To avoid ambiguities, functions inrhs
calls may not be syntactically special, such as+
orif
.
If the
rhs
expression is afunction
expression, then the function is called with thelhs
value as its argument. This is useful when thelhs
needs to be passed as an argument other than the first in therhs
call.
此运算符何时会进入发布版本,或者它是否会在发布之前发生更改,都是未知数。
在 R |>
中用作管道运算符。 (自 4.1.0 起)
左侧表达式 lhs 作为 第一个自由参数 插入到右侧表达式的调用中rhs.
mtcars |> head() # same as head(mtcars)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
mtcars |> head(2) # same as head(mtcars, 2)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
也可以在 rhs 调用中使用带有占位符 _
的 命名参数 来指定lhs 待插入。占位符只能在 rhs 上出现 一次。 (自 4.2.0 起)
mtcars |> lm(mpg ~ disp, data = _)
#mtcars |> lm(mpg ~ disp, _) #Error: pipe placeholder can only be used as a named argument
#Call:
#lm(formula = mpg ~ disp, data = mtcars)
#
#Coefficients:
#(Intercept) disp
# 29.59985 -0.04122
或者在“一”之前明确命名参数:
mtcars |> lm(formula = mpg ~ disp)
如果占位符被多次使用或在任何位置用作命名或未命名参数或用于禁用函数:使用(匿名)函数.
mtcars |> (\(.) .[.$cyl == 6,])()
#mtcars ->.; .[.$cyl == 6,] # Alternative using bizarro pipe
#local(mtcars ->.; .[.$cyl == 6,]) # Without overwriting and keeping .
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
mtcars |> (\(.) lm(mpg ~ disp, .))()
#Call:
#lm(formula = mpg ~ disp, data = .)
#
#Coefficients:
#(Intercept) disp
# 29.59985 -0.04122
1:3 |> setNames(object = _, nm = _)
#Error in setNames(object = "_", nm = "_") :
# pipe placeholder may only appear once
1:3 |> (\(.) setNames(., .))()
#1 2 3
#1 2 3
1:3 |> list() |> setNames(".") |> with(setNames(., .))
#1 2 3
#1 2 3
#The same but over a function
._ <- \(data, expr, ...) {
eval(substitute(expr), list(. = data), enclos = parent.frame())
}
1:3 |> ._(setNames(., .))
#1 2 3
#1 2 3
部分函数为disabled.
mtcars |> `$`(cyl)
#Error: function '$' not supported in RHS call of a pipe
但有些仍然可以通过将它们放在制动器中来调用,通过函数调用它们::
,在函数中调用它或在函数中定义一个link。
mtcars |> (`$`)(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> base::`$`(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> (\(.) .$cyl)()
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
fun <- `$`
mtcars |> fun(cyl)
# [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
写成 x |> f(y)
的表达式被解析为 f(x, y)
。虽然管道中的代码是按顺序编写的,但适用于评估的常规 R 语义。因此,只有在 rhs 表达式中首次使用 时,管道表达式才会 求值。
-1 |> sqrt() |> (\(x) 0)()
#[1] 0
. <- -1
. <- sqrt(.)
#Warning message:
#In sqrt(.) : NaNs produced
(\(x) 0)(.)
#[1] 0
x <- data.frame(a=0)
f1 <- \(x) {message("IN 1"); x$b <- 1; message("OUT 1"); x}
f2 <- \(x) {message("IN 2"); x$c <- 2; message("OUT 2"); x}
x|> f1() |> f2()
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
f2(f1(x))
#IN 2
#IN 1
#OUT 1
#OUT 2
# a b c
#1 0 1 2
. <- x
. <- f1(.)
#IN 1
#OUT 1
f2(.)
#IN 2
#OUT 2
# a b c
#1 0 1 2