【问题标题】:using mutate_at from dplyr使用 dplyr 中的 mutate_at
【发布时间】:2018-01-19 22:24:54
【问题描述】:

我有一个包含 5 列的数据框,我想生成 4 个额外的列,给出最后 4 列和第一列之间的差异。 我尝试了以下方法,但这不起作用:

library(tidyverse)
df <- as.tibble(data.frame(A = c(1,2), B = c(3,4), C = c(4,5), D = c(2,3), E = c(4,5)))
r_diff <- function(x,y){
  z = y - x
  return(z)
}
vars_to_process <- c("B","C","D","E")
df %>% mutate_at(.cols=vars_to_process, .funs =r_diff(.,df[,1])) %>% head()

谢谢 伦格

【问题讨论】:

  • 您的 r_diff 函数是(带有反转参数)"-" 函数,您可以这样使用:"-"(5, 4)
  • 如果将事物转换为矩阵,则可以用“-”从其余列中减去第 1 列。可能快 10 倍或 100 倍。

标签: r dplyr


【解决方案1】:

这是最简单的方法。

df %>% 
   mutate_at(.vars = vars(B:E),
             .funs = list(~ . - A))

.vars 参数允许您以与在 select() 中指定列相同的方式指定列,前提是您将该规范放在函数 vars() 中。

.funs 参数接受在调用list() 中动态定义的匿名函数。并且您可以在定义此匿名函数时引用数据框中的列(在本例中为 A)(请参阅 this Stackoverflow question)。

此外,随着 dplyr 1.0.0 的发布,您现在可以简单地执行以下操作:

df %>%
   mutate(across(B:E, ~ . - A))

【讨论】:

    【解决方案2】:

    这是使用基本 R 代码的更快解决方案。策略是转换为矩阵,从所需列中减去第一列,重新构建为数据框。请注意,这只会返回修改后的列 - 如果 vars_to_process 中有列 not 它们不会出现在输出中,但您的测试集中没有这些列,所以我假设它们不存在。

    所以,尽可能在函数中写东西:

    bsr = function(df,vars_to_process){
        m = as.matrix(df)
        data.frame(
             A = m[, 1],
                 m[, 1] - m[, vars_to_process])}
    

    制作一些测试数据:

    > df = data.frame(matrix(runif(5*1000), ncol=5))
    > names(df)=LETTERS[1:5]
    > dft = as.tibble(df)
    > head(dft)
    # A tibble: 6 x 5
              A          B         C         D         E
          <dbl>      <dbl>     <dbl>     <dbl>     <dbl>
    1 0.2609174 0.07857624 0.2727817 0.8498004 0.3403234
    2 0.3644744 0.95810657 0.8183856 0.2958133 0.4752349
    3 0.6042914 0.98793218 0.7547003 0.9596591 0.5354045
    4 0.4000441 0.61403331 0.9018804 0.3838347 0.3266855
    5 0.6767012 0.11984219 0.9181570 0.5988404 0.6058629
    

    与tidyverse版本对比:

    akr = function(df,vars_to_process){
       df %>% mutate_at(vars_to_process, funs(r_diff(.,df[[1]])))
       }
    

    勾选bsrakr同意:

    > head(bsr(dft, vars_to_process))
              A          B           C           D           E
    1 0.2609174  0.1823412 -0.01186432 -0.58888295 -0.07940594
    2 0.3644744 -0.5936322 -0.45391119  0.06866108 -0.11076050
    3 0.6042914 -0.3836408 -0.15040892 -0.35536765  0.06888696
    4 0.4000441 -0.2139892 -0.50183635  0.01620939  0.07335861
    
    > head(akr(dft, vars_to_process))
    # A tibble: 6 x 5
              A          B           C           D           E
          <dbl>      <dbl>       <dbl>       <dbl>       <dbl>
    1 0.2609174  0.1823412 -0.01186432 -0.58888295 -0.07940594
    2 0.3644744 -0.5936322 -0.45391119  0.06866108 -0.11076050
    3 0.6042914 -0.3836408 -0.15040892 -0.35536765  0.06888696
    4 0.4000441 -0.2139892 -0.50183635  0.01620939  0.07335861
    

    好的,除了 akr 返回一个 tribble 但 nm。基准:

    > microbenchmark(bsr(dft, vars_to_process),akr(dft, vars_to_process))
    Unit: microseconds
                          expr      min        lq      mean   median       uq
     bsr(dft, vars_to_process)  362.117  388.7215  488.9309  446.123  521.776
     akr(dft, vars_to_process) 8070.391 8365.4230 9853.5239 8673.692 9335.613
    

    Base R 版本快 26 倍。我还认为,从另一组列中减去一列比应用 mutator 函数更整洁,但只要你将你所做的事情包装在一个函数中,那么内脏有多混乱并不重要。

    【讨论】:

      【解决方案3】:

      我们需要使用[[ 对列进行子集化,因为[ 仍然是data.frame

      df %>% 
         mutate_at(vars_to_process, funs(r_diff(.,df[[1]]))) 
      # A tibble: 2 x 5
      #     A     B     C     D     E
      #  <dbl> <dbl> <dbl> <dbl> <dbl>
      #1     1    -2    -3    -1    -3
      #2     2    -2    -3    -1    -3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-05
        • 1970-01-01
        • 2019-09-24
        相关资源
        最近更新 更多