【问题标题】:Using dplyr mutate_at with custom function将 dplyr mutate_at 与自定义函数一起使用
【发布时间】:2018-09-20 09:23:04
【问题描述】:

我想从表中取出两个变量,然后将它们除以第三个变量,然后将这些计算添加为两个新列。 mutate_at 让我非常接近,但在自定义函数中,f 下面,我想访问数据集中的另一列。有什么建议或替代的整洁工具方法吗?

library(dplyr)
# this works fine but is NOT what I want
f <- function(fld){
  fld/5
}

# This IS what I want where wt is a field in the data
f <- function(fld){
  fld/wt
}

mutate_at(mtcars, .vars = vars(mpg, cyl), .funs = funs(xyz = f))

# This works but is pretty clumsy
f <- function(fld, dat) fld/dat$wt
mutate_at(mtcars, .vars = vars(mpg, cyl), .funs = funs(xyz = f(., mtcars)))

# This is closer but still it would be better if the function allowed the dataset to be submitted to the function without restating the name of the dataset

f <- function(fld, second){
  fld/second
}

mutate_at(mtcars, .vars = vars(mpg, cyl), .funs = funs(xyz = f(., wt)))

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    dplyr 1.0.6 的更新版本:

    mtcars %>% 
      mutate(across(c(mpg, cyl), ~ . / wt))
    

    或者这个,可能会更慢

    mtcars %>% 
      mutate(across(c(mpg, cyl), `/`, wt))
    

    上一个答案:

    library(tidyverse)
    f <- function(num, denom) num/denom
    
    mtcars %>% 
      mutate_at(vars(mpg, cyl), f, denom = quote(wt))
    

    虽然在这个特定示例中,不需要自定义函数。

    mtcars %>% 
      mutate_at(vars(mpg, cyl), `/`, quote(wt))
    

    【讨论】:

    • 我认为这个答案和问题中的例子一样笨拙。当然,你去掉了所有的 .funs=funs... 混乱,但这不是问题的重点。这只是解决问题中解决方案的另外两种方法:调用函数并将第二个参数传递给mutate()。问题的关键是找到一种方法来避免传递第二个参数。
    • 抱歉不清楚(以及对抗性语言)。必须提供分母,但可以在不将其作为函数参数的情况下这样做。我认为这是问题的意图,因为声明“这就是我想要的”,后面跟着一个只有一个参数的函数,并且因为问题已经包含两个工作解决方案,它们的功能与此答案相同但语法略有不同。我认为通过显示选项f &lt;- function(num) num/cur_data()$denom 可以改进这个答案。如果你不介意,我会添加它。
    【解决方案2】:

    也许是这样的?

    f <- function(fld,var){
        fld/var
    }
    
    mtcars %>%
        mutate_at(vars(mpg,cyl), .funs = funs(xyz = f(.,wt)))
    

    编辑(2020-08-24):

    从 2020 年第二学期开始,随着 dplyr 1.0.0 的推出,mutate_at 已被 mutateacross 函数组合所取代:

    mtcars %>%
        mutate(across(c(mpg, cyl), ~ f(.,wt), .names = "{col}_xyz"))
    

    【讨论】:

      【解决方案3】:

      为什么不简单

      mutate(mtcars, mpg2 = mpg / wt, cyl2 = cyl / wt)
      

      【讨论】:

      • 这适用于几个字段,但不灵活,例如 10 个字段会很麻烦。如果您改变了对后缀(“2”)的看法,则必须在几个地方等处进行更改。
      • 同意,我想我错过了你问题的症结
      【解决方案4】:

      有一个cur_data() 函数将有助于使mutate_at() 调用更加紧凑,因为您不必为函数指定第二个参数,该函数将应用于每一列:

      f <- function(fld){
        fld / cur_data()$wt
      }
      mutate_at(mtcars, .vars=vars(mpg, cyl), .funs=funs(xyz = f))
      

      补充说明:

      1. 如果您需要该函数引用分组变量,请使用cur_data_all()
      2. mutate_at 现在被 mutate(.data, across()) 取代,所以最好这样做
      mtcars %>% mutate(across(.cols=c(mpg, cyl), .fns=f, .names='{.col}_xyz'))
      

      【讨论】:

        猜你喜欢
        • 2020-01-27
        • 1970-01-01
        • 2020-04-11
        • 1970-01-01
        • 2020-06-23
        • 1970-01-01
        • 2021-07-20
        • 2020-07-08
        • 1970-01-01
        相关资源
        最近更新 更多