如何纯粹在 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