R函数将3个计算列写入data.table

时间:2017-06-06 12:53:20

标签: r function data.table

这可能已经得到了解答,但找不到我想要的答案。我试图写一个函数的输出,计算3个变量到data.table。

目前我正在复制该函数三次(使用三个不同的名称),每次都返回一个不同的变量。这需要花费更多的时间,因为它运行三次。我明白 可能有更好的方法,使用list或一些独特的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) ]

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

你在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对其进行cbind以一次添加所有列。每次进行所有计算都非常慢,然后只返回一部分。

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,]))

答案 2 :(得分:1)

根据@docendodiscimus&amp;的输入回答我自己的问题@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)]

答案 3 :(得分:0)

它必须是data.table吗?如果没有,那么您可以在mutate

中使用dplyr
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)