我应该使用 %$% 而不是 %>% 吗?

20

最近我发现了%$%管道运算符,但是我不明白它与%>% 的区别,并且它能否完全代替它。


使用%$%的动机

  • 在许多情况下,运算符%$%可以替代%>%
mtcars %>% summary()
mtcars %$% summary(.)
mtcars %>% head(10)
mtcars %$% head(.,10)
  • 显然,%$%%>% 更易用:
mtcars %>% plot(.$hp, .$mpg) # Does not work
mtcars %$% plot(hp, mpg)     # Works
  • 隐式填充内置数据参数:
mtcars %>% lm(mpg ~ hp, data = .)
mtcars %$% lm(mpg ~ hp)
  • 由于在键盘上,%$相邻,所以插入%$%比插入%>%更方便。

文档

我们可以在它们各自的帮助页面中找到以下信息。

(?magrittr::`%>%`):

Description:

     Pipe an object forward into a function or call expression.

Usage:

     lhs %>% rhs
(?magrittr::`%$%`):
Description:

     Expose the names in ‘lhs’ to the ‘rhs’ expression. This is useful
     when functions do not have a built-in data argument.

Usage:

     lhs %$% rhs

我无法理解两个管道操作符之间的区别。 将对象传输暴露名称有什么区别?但是,在%$%的右侧,我们可以使用.获取管道对象,对吗?


我应该开始使用%$%而不是%>%吗?这样做可能会遇到哪些问题?


2
你可以随心所欲地使用编程语言,而在你展示的例子中,%$% 特别强大。但是你会发现,如果使用例如“dplyr”或“tidyr”等包,相对于你的特定示例,%$% 的用处要少得多,因为这些包(以及其他类似的包)在 LHS 上下文中执行自己的名称查找。 - Konrad Rudolph
3
关于键盘快捷方式的方便性,我要指出如果你正在使用RStudio,可以使用Cmd+Shift+M或Ctrl+Shift+M(取决于你的操作系统)来插入"%>%"。 - jdobres
2
最简单的方法是使用内置管道符号 |>,因为它不依赖于任何包。 - Grzegorz Sapijaszko
有趣的是,我相当确定过去 %$% 的代码应该是 '%$%' <- with,现在我们可以使用点号,你建议的用法在我看来并不荒谬。只是不寻常,因为大多数用户使用 %>%。还有几个注释,你可以在 Studio 中使用 ctrl + shift + M 来节省打字时间,在你的 lm 示例中,数据参数没有被隐式填充,它是缺失的,但是 mpg 和 hp 在本地环境中作为独立对象被找到,所以不需要它。 - moodymudskipper
2个回答

11

除了提供的评论之外:

%$%(也称为Exposition pipe)与%>%之间的区别:

这是本文https://towardsdatascience.com/3-lesser-known-pipe-operators-in-tidyverse-111d3411803a的简要概述。

“使用 %$% 或 %>% 的关键差异在于所使用函数的参数类型。”

使用 %$% 而不是 %>% 的一个优点,在于我们可以避免在没有数据作为参数的函数中重复输入数据框名称。

例如,lm() 有一个数据参数。在这种情况下,我们可以交替使用 %>% 和 %$%

但对于像 cor() 这样没有数据参数的函数:

mtcars %>% cor(disp, mpg) # Will give an Error
cor(mtcars$disp, mtcars$mpg)

等同于

mtcars %$% cor(disp, mpg)

请注意,要使用%$%管道运算符,您需要加载library(magrittr)

更新:在OP的评论中: 无论哪个管道都允许我们将机器或计算机语言转换为更易读的人类语言。

ggplot2很特别。 ggplot2在内部不一致。 ggplot1比ggplot2具有更整洁的API。

管道可以与ggplot1一起使用: library(ggplot1) mtcars %>% ggplot(list( x= mpg, y = wt)) %>% ggpoint() %>% ggsave("mtcars.pdf", width= 8 height = 6)

在2016年,Wick Hadley说: 如果我10年前发现了这个管道,ggplot2就不会存在! https://www.youtube.com/watch?v=K-ss_ag2k9E&list=LL&index=9


1
你能解释一下数据参数的“魔法”是如何工作的吗?为什么在ggplot%$%不起作用,它也有一个data参数?%$%只对基本的R函数有用吗? - Gorka
1
请看我的更新。我认为我可以回答ggplot问题。 - TarJae

11

不,你不应该经常使用%$%。这就像使用with()函数一样,即在评估RHS时公开LHS的组件部分。但是它仅在左侧的值具有列表或数据帧等名称时才起作用,因此你不能总是使用它。例如:


library(magrittr)
x <- 1:10
x %>% mean()
#> [1] 5.5
x %$% mean()
#> Error in eval(substitute(expr), data, enclos = parent.frame()): numeric 'envir' arg not of length one

reprex包 (v2.0.1.9000)于2022年2月6日创建

x %$% mean(.)也会出现类似的错误。

即使左侧有名称,它也不会自动将.参数放在第一位置。例如,

mtcars %>% nrow()
#> [1] 32
mtcars %$% nrow()
#> Error in nrow(): argument "x" is missing, with no default

reprex 包 (v2.0.1.9000) 于 2022-02-06 创建

在这种情况下,mtcars %$% nrow(.) 可以工作,因为mtcars有名称。

您所提到的示例涉及.$hp.$mpg,它展示了magrittr管道的奇怪之处。因为点号“.”只用在表达式中,而不是作为单独的参数使用,所以它既作为第一个参数传递,也被传递到这些表达式中。您可以使用花括号避免这种情况,例如:

mtcars %>% {plot(.$hp, .$mpg)}

1
好的观点!%$%并不总是适用的。现在我明白了管道运算符%$%为什么要以那种方式表示,实际上它非常有帮助:%$%只能与可以使用$的对象一起使用。 - Gorka
然而,当可以使用“%$%”时,为什么应该避免使用它?为什么暴露组件部分是一种不良实践?我认为这更像是一个特性:我们可以优先访问名称(即我们避免“.$”),但如果需要,我们也可以使用“.”获取父对象。 - Gorka
1
当您想要访问组件部分时,这并不是一种不好的做法。唯一的负面影响是它并不真正符合“管道”范例,即对象在通过调用时被多次修改。 - user2554330
虽然有点晚了,关于“由于%和$在键盘上相邻,插入%$%更方便”的问题,有一个小的反对意见是自R~4.2以来,包含基本R管道的使用通常可以通过CTRL+SHIT+M快速访问,而且不需要加载任何软件包。 - dez93_2000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接