【问题标题】:R Function to write 3 calculated columns to a data.tableR函数将3个计算列写入data.table
【发布时间】:2017-06-06 12:53:19
【问题描述】:

这可能已经得到解答,但无法完全找到我正在寻找的答案。我正在尝试将计算 3 个变量的函数的输出写入 data.table。

目前我正在复制该函数三次(使用三个不同的名称),每次都返回一个不同的变量。这需要更多时间,因为它运行三次。我明白 可能有更好的方法来做到这一点,使用列表或一些独特的data.table 命令。

非常感谢您提供的任何意见以简化此过程。下面是我如何一次调用一个变量的示例。

示例

  fn_1 <- function(a, b, c, d){
    
    for (i in 1:b) { col_1[i] = calculation }
    for (i in 1:c) { col_2[i] = calculation }
    for (i in 1:d) { col_3[i] = calculation }

    return(col_1)
  }
  
  data[ ,column_1 := fn_1(a,b,c,d) ,by= .(e,f) ]


  fn_2 <- function(a, b, c, d){
    
    for (i in 1:b) { col_1[i] = calculation }
    for (i in 1:c) { col_2[i] = calculation }
    for (i in 1:d) { col_3[i] = calculation }

    return(col_2)
  }
  
  data[ ,column_2 := fn_2(a,b,c,d) ,by= .(e,f) ]

【问题讨论】:

  • 请展示一个可重现的小例子
  • 一般建议:使用返回 3(或 n)个输出列表的函数,并将其分配给向量中的 3(n)个新列,如 data[, c("a","b","c") := fun_w_3_outputs(...)]
  • 这样,函数定义内部的for循环使用表示col_1col_2col_3的计算结果可能有不同长度的b、@ 987654329@, 和d, resp. 这是有意的吗?

标签: r function data.table


【解决方案1】:

OP 已用data.table 标记了该问题。 docendo discimus' comment 正在显示要遵循的方向。

创建示例数据

library(data.table)   # CRAN version 1.10.4 used

n <- 10L
DT <- data.table(
  a = 1:n, b = (n:1)^2, c = -(1:n), d = 2 * (1:n) - n/2,
  e = rep(LETTERS[1:2], length.out = n), 
  f = rep(LETTERS[3:4], each = n/2, length.out = n))
DT  
#     a   b   c  d e f
# 1:  1 100  -1 -3 A C
# 2:  2  81  -2 -1 B C
# 3:  3  64  -3  1 A C
# 4:  4  49  -4  3 B C
# 5:  5  36  -5  5 A C
# 6:  6  25  -6  7 B D
# 7:  7  16  -7  9 A D
# 8:  8   9  -8 11 B D
# 9:  9   4  -9 13 A D
#10: 10   1 -10 15 B D

定义函数

fn <- function(p, q, r, s) {
  list(X1 = p + mean(q) + r + s,
       Y2 = p * q + r * s,
       Z3 = p * q - r * s)
}

该函数接受 4 个参数并返回一个包含 3 个命名向量的列表。请注意,与 OP 的方法相比,函数内部的计算不需要使用 for 循环。

对data.table应用函数

请注意,当应用该函数时,OP 希望对列 ef 进行分组。

第一个变体创建一个新的 data.table。默认情况下,使用fn 中定义的列表元素的名称:

DT[, fn(a, b, c, d), .(e, f)]
#    e f       X1   Y2  Z3
# 1: A C 63.66667  103  97
# 2: A C 67.66667  189 195
# 3: A C 71.66667  155 205
# 4: B C 64.00000  164 160
# 5: B C 68.00000  184 208
# 6: B D 18.66667  108 192
# 7: B D 22.66667  -16 160
# 8: B D 26.66667 -140 160
# 9: A D 19.00000   49 175
#10: A D 23.00000  -81 153

第二个变体更新DT 通过引用。新列的名称已明确说明。

DT[, c("x", "y", "z") := fn(a, b, c, d), .(e, f)]

DT
#     a   b   c  d e f        x    y   z
# 1:  1 100  -1 -3 A C 63.66667  103  97
# 2:  2  81  -2 -1 B C 64.00000  164 160
# 3:  3  64  -3  1 A C 67.66667  189 195
# 4:  4  49  -4  3 B C 68.00000  184 208
# 5:  5  36  -5  5 A C 71.66667  155 205
# 6:  6  25  -6  7 B D 18.66667  108 192
# 7:  7  16  -7  9 A D 19.00000   49 175
# 8:  8   9  -8 11 B D 22.66667  -16 160
# 9:  9   4  -9 13 A D 23.00000  -81 153
#10: 10   1 -10 15 B D 26.66667 -140 160

【讨论】:

    【解决方案2】:

    您在second circle of hell 中。要解决问题,请预先分配您要添加的内容。

    data <- data.table(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9))
    

    然后,创建一个向量化函数来进行计算,该函数返回整列以追加。

    calculation <- Vectorize(function(x) mean(c(x, 3)))
    

    根据这个新函数编写 fn,并返回要添加的整个列块,然后将其与 data 绑定以一次添加所有列。每次把所有的计算都做完,然后只返回一部分,非常的慢。

    fn <- function(b, c, d) {
      toBeAdded <- data.table(matrix(nrow = nrow(data), ncol = 3))
      toBeAdded[ , 1] <- calculation(b)
      toBeAdded[ , 2] <- calculation(b)
      toBeAdded[ , 3] <- calculation(b)
      toBeAdded
    }
    
    data <- cbind(data, fn(data[1,], data[2,], data[3,]))
    

    【讨论】:

      【解决方案3】:

      根据@docendodiscimus 和@ConCave 的输入回答我自己的问题,我这样解决了。感谢大家的意见!

        fn_1 <- function(a, b, c, d){
      
          for (i in 1:b) { col_1[i] = calculation }
          for (i in 1:c) { col_2[i] = calculation }
          for (i in 1:d) { col_3[i] = calculation }
      
            df = data.table(col_1, col_2, col_3)
            return(df)
        }
      
        data[,c("column_1","column_2","column_3"):= fn_1(a,b,c,d) ,by= .(e,f)]
      

      【讨论】:

        【解决方案4】:

        它必须是 data.table 吗?如果没有,那么你可以在dplyr中使用mutate

        a <- c(1,2,2,1,2,3,4,2)
        b <- c(3,3,2,3,5,4,3,2)
        c <- c(9,9,8,7,8,9,8,7)
        d <- c(0,1,1,0,1,1,0,1)
        
        have <- data.frame(a,b,c,d)
        
        want <- 
          have %>% 
          mutate(abc = a+ b + c,
                 db = d * b,
                 aa = 2 * a)
        

        【讨论】:

        • 或者你可以像transform(have, abc = a+ b + c, db = d * b, aa = 2 * a)一样使用来自基本R的transform而不加载不必要的包。
        猜你喜欢
        • 1970-01-01
        • 2016-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-13
        • 1970-01-01
        相关资源
        最近更新 更多