【问题标题】:Self defined function with dplyr functions won't accept argument values [duplicate]具有 dplyr 函数的自定义函数不接受参数值 [重复]
【发布时间】:2018-08-10 12:26:05
【问题描述】:

我正在尝试使用 dplyr 的 mutate_at 从另一个相应的数字列 (A2) 中减去一个数字列的值 (A1),我有多个列和几个数据框我想为此做(BCDE..., df1:df99) 所以我想写一个函数。

df1 <- df1 %>% mutate_at(.vars = vars(A1), .funs = funs(remainder = .-A2))

工作正常,但是当我尝试编写一个函数来执行此操作时:

REMAINDER <- function(df, numer, denom){ df <- df %>% mutate_at(.vars = vars(numer), .funs = funs(remainder = .-denom)) return(df) }

带参数df1 &lt;- REMAINDER(df1, A1, A2)

我收到错误Error in mutate_impl(.data, dots) : Evaluation error: non-numeric argument to binary operator.

我不明白,因为我只是手动调用了没有函数的代码行,而且我的列是数字的。

【问题讨论】:

    标签: r function dplyr


    【解决方案1】:

    小插图Programming with dplyr 非常详细地解释了该怎么做:

    library(dplyr)
    REMAINDER <- function(df, numer, denom) {
      numer <- enquo(numer)
      denom <- enquo(denom)
      df %>% mutate_at(.vars = vars(!! numer), .funs = funs(remainder = . - !! denom))
    }
    
    df1 <- data_frame(A1 = 11:13, A2 = 3:1, B1 = 21:23, B2 = 8:6)
    
    REMAINDER(df1, A1, A2)
    
    # A tibble: 3 x 5
         A1    A2    B1    B2 remainder
      <int> <int> <int> <int>     <int>
    1    11     3    21     8         8
    2    12     2    22     7        10
    3    13     1    23     6        12
    
    REMAINDER(df1, B1, B2)
    
    # A tibble: 3 x 5
         A1    A2    B1    B2 remainder
      <int> <int> <int> <int>     <int>
    1    11     3    21     8        13
    2    12     2    22     7        15
    3    13     1    23     6        17
    

    命名结果列

    OP 想要更新df1,他也想将此操作应用于其他列。

    不幸的是,当前定义的REMAINDER() 函数将覆盖结果列:

    df1
    
    # A tibble: 3 x 4
         A1    A2    B1    B2
      <int> <int> <int> <int>
    1    11     3    21     8
    2    12     2    22     7
    3    13     1    23     6
    
    df1 <- REMAINDER(df1, A1, A2)
    df1
    
    # A tibble: 3 x 5
         A1    A2    B1    B2 remainder
      <int> <int> <int> <int>     <int>
    1    11     3    21     8         8
    2    12     2    22     7        10
    3    13     1    23     6        12
    
    df1 <- REMAINDER(df1, B1, B2)
    df1
    
    # A tibble: 3 x 5
         A1    A2    B1    B2 remainder
      <int> <int> <int> <int>     <int>
    1    11     3    21     8        13
    2    12     2    22     7        15
    3    13     1    23     6        17
    

    可以修改函数,以便单独命名结果列:

    REMAINDER <- function(df, numer, denom) {
      numer <- enquo(numer)
      denom <- enquo(denom)
      result_name <- paste0("remainder_", quo_name(numer), "_", quo_name(denom))
      df %>% mutate_at(.vars = vars(!! numer),
                       .funs = funs(!! result_name := . - !! denom))
    }
    

    现在,在不同的列上调用REMAINDER() 两次并在每次调用后替换df1,我们得到

    df1 <- REMAINDER(df1, A1, A2)
    df1 <- REMAINDER(df1, B1, B2)
    df1
    
    # A tibble: 3 x 6
         A1    A2    B1    B2 remainder_A1_A2 remainder_B1_B2
      <int> <int> <int> <int>           <int>           <int>
    1    11     3    21     8               8              13
    2    12     2    22     7              10              15
    3    13     1    23     6              12              17
    

    【讨论】:

      【解决方案2】:

      我使用this suggestion 来减去数据框列表中的列对。我的示例在两个数据框中的每一个中只有 3 对列,它可以处理更多的列和数据框。

      dt <- data.table(A1 = round(runif(3),1), A2 = round(runif(3),1),
                       B1 = round(runif(3),1), B2 = round(runif(3),1),
                       C1 =round(runif(3),1), C2 =round(runif(3),1))
      
      dt = list(dt,dt+dt)
      
      lapply(seq_along(dt), function(z) {
        dt[[z]][, lapply(1:(ncol(.SD)/2), function(x) (.SD[[2*x-1]] - .SD[[2*x]]))]
      })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-01
        • 2018-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多