【问题标题】:What is the use case for `dplyr::select`?`dplyr::select` 的用例是什么?
【发布时间】:2017-09-27 20:18:31
【问题描述】:

我通常非常喜欢整个 tidyverse 范式并广泛使用它。

但我根本不明白dplyr 中的select。它比简单地选择列更有用吗

my_df[,cols_of_interest]

?

“vanilla”R 方法看起来要简单得多,也更加健壮。我可以将cols_of_interest 作为变量,如上所述,或者我可以输入文字名称。尝试使用变量,然后使用select_,然后尝试与lazyeval 可能解释我的意图的整个方式发生争执,这似乎很疯狂。

是否存在程序化案例,其中select 比简单的my_df[,cols_of_interest] 更有优势? (这些天我很少写任何代码“一次”,所以任何不是编程的东西都不是特别有用。)

目前,我发现自己经常做以下事情:

new_df <- (old_df %>%
    filter_(paste0("`",col_name, "`=='",col_val,"'")))[cols_to_keep] 

这有点难看,但至少它有效,不像任何尝试执行的那样

new_df <- old_df %>%
    filter_(paste0("`",col_name, "`=='",col_val,"'")) %>%
    select_(cols_to_keep)

彻底失败了。

我可以举一个明确的例子,但这有点没抓住重点。 select over 的用例是什么,只需选择 my_df[,cols_of_interest]

【问题讨论】:

  • 它主要是 pipable。它还使用 NSE(非常适合交互式会话),可用于选择性地重命名,并具有一组不错的帮助函数,例如 num_range。它还可以与 dplyr 的各种后端(各种 SQL 风格、sparklyr、multidplyr)透明地工作。仅供参考,verb_ 版本在即将发布的版本中被弃用,转而支持rlang syntax
  • my_df[,cols_of_interest] 的等价物是my_df %&gt;% select(one_of(cols_of_interest))
  • ...或mtcars %&gt;% select_(.dots = c('mpg', 'hp')) 使用当前版本或mtcars %&gt;% select(!!!rlang::syms(c('mpg', 'wt'))) 使用0.6
  • 一个可能的编程优势是select 总是返回一个data.frame,如果df 是一个普通的data.frame 而... 是一个单一变量,df[ , ...] 就不会。没有逗号的子集(例如mtcars['wt'])实际上更安全,虽然一开始可能不太直观。
  • 我同意你的观点,“动词”可能会失控。我想一个好处是能够在选择列时重命名它。基础会更难。 select(mtcars, miles=mpg, am:carb) 和一系列行的冒号运算符非常酷。

标签: r dplyr tidyverse


【解决方案1】:

我仍然不确定select(或select_)的用例,除非您希望将单个列保留为数据框类型而不是被强制转换成向量。

但是,为了部分回答我自己的问题,我至少想出了 tidyverse 友好的方式来做我想做的事情,以编程方式。

> mt_dt <- as_tibble(mtcars)
> expr1 <- quote(cyl == 8)
> cols_oi <- c("mpg", "cyl")
> mt_dt %>% filter_(.dots=expr1) %>% select_(.dots=cols_oi)

(This returns only the mpg & cyl columns, only when the cyl == 8.)

看来在您可能希望以编程方式有效使用tidyverse 的任何情况下,我们都会使用.dots。然而,正如上面的例子所示,它的用法并不明显:有时你应该提供一个未计算的表达式,就像你从 quotesubstitute 得到的那样,有时你应该提供一个简单的字符串,就像你在任何标准的例子中提供的那样表达式是一流的。虽然我找不到关于 dots 的详细文档,但对 this non-standard documentation 的多次重读帮助很大。

【讨论】:

    【解决方案2】:

    select 用于交互式会话,将select_ 用于“程序化”目的...

    library(dplyr)
    
    iris %>% select(Sepal.Width, Petal.Width)
    
    cols_of_interest <- c("Sepal.Width", "Petal.Width")
    iris %>% select_(.dots = cols_of_interest)
    

    补充说明...

    另外,请注意以下两行相同...

    iris %>% select_("Sepal.Width", "Petal.Width")
    iris %>% select_(c("Sepal.Width", "Petal.Width"))
    

    这就是为什么它不像你期望的那样工作..

    iris %>% select_(cols_of_interest)
    

    select_ 可以处理字符串,但是如果你给它一个包含多个字符串的向量,它不知道如何处理它(在这种情况下,它只获取第一个元素并忽略其余元素)。在第一个示例中,您将两个单独的字符串传递给两个单独的参数,而在第二个(和第三个)中,您将一个双元素向量传递给一个参数。

    【讨论】:

    • 谢谢,CJ。我挣扎的部分原因是我通常处于程序化模式,这与tidyverse 的大部分内容不符。但我的部分斗争实际上是我用错了。我不明白应该如何使用.dots
    • 我添加了一些说明
    【解决方案3】:

    我不能单独给出使用 select 的充分理由,但在 dplyr 的其余部分的上下文中并与 magrittr 结合使用它允许类似

    x %>% filter(col1 == "foo")
        %>% select(col2, col3)
        %>% mutate(col4 = f(col2, col3))
    

    通过一系列操作提供了非常好的一致语法。

    【讨论】:

    • 嗨@shians 是的,我了解基本用例。但是在您给出的示例中,它不是程序化的。即,col2col3 必须是列的实际名称,而不是字符串变量。我很少在那个“只写一次”的世界里工作了。而且,也许我错了,但我觉得更少的 R 用户也在使用“一次编写”交互模式。
    • @MikeWilliamson 这是一个糟糕的假设;如果这里的问题是任何指标,那么 R 的交互方式比编程方式要多得多。当然,代码会被回收,但如果数据格式足够标准化,则不需要使用不同的方法来重新运行对新数据的分析。此外,如果您愿意,您可以直接使用“实际名称”(各种类型的真正语言对象)进行编程。
    猜你喜欢
    • 2020-08-29
    • 2022-01-23
    • 2018-02-15
    • 2021-12-25
    • 2010-10-09
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多