0

I am attempting to use this question and answer (R data.table using lapply on functions defined outside) to assist me in answering my own previously asked question (operations (+, -, /, *) on unequal-sized data.table).

I am including a modified example below:

library(data.table)

constants <- data.table(252.164401, 3785.412, 453.59237)

input1a <- data.table(ID = c(37, 45, 900), a1 = c(1, 2, 3), a2 = c(43, 320, 
390), 
b1 = c(-0.94, 2.2, -1.223), b2 = c(2.32, 4.54, 7.21), c1 = c(1, 2, 3), 
c2 = c(-0.94, 2.2, -1.223))
setkey(input1a, ID)

dput(input1a)
structure(list(ID = c(37, 45, 900), a1 = c(1, 2, 3), a2 = c(43, 320, 390),
b1 = c(-0.94, 2.2, -1.223), b2 = c(2.32, 4.54, 7.21), c1 = c(1, 2, 3), 
c2 = c(-0.94, 2.2, -1.223)), .Names = c("ID", "a1", "a2", "b1", "b2", "c1", 
"c2"), row.names = c(NA, -3L), class = c("data.table", "data.frame"), 
.internal.selfref = <pointer: 0x39c3f38>, sorted = "ID")

# input1a
#     ID  a1  a2       b1     b2  c1      c2
# 1:  37  1   43   -0.940   2.32   1  -0.940
# 2:  45  2  320    2.200   4.54   2   2.200
# 3: 900  3  390   -1.223   7.21   3  -1.223

Based on the error message below, what needs to be changed in the next 2 lines so that both arguments "b" and "c" can be found?

fun <- function(a, b, c, wherea=parent.frame(),whereb=parent.frame(),
wherec=parent.frame()) {
return(get(a,wherea) - constants$constants[2] * (get(b, whereb) - 
get(c, wherec)))
}

input1a[, lapply(c('a1', 'a2', 'b1', 'b2', 'c1', 'c2'), fun, wherea=.SD,
whereb=.SD, wherec=.SD), by = key(input1a)]

# Error in get(b, whereb) : argument "b" is missing, with no default

This is what I would like to have for input1a:

# input1a
#     ID        V1            V2
# 1:  37   7344.699    -12297.44
# 2:  45  -755.0824    -8537.864
# 3: 900   15988.79    -31532.38

Thank you.


UPDATE

Based on the answer by eddi and the correction by Biogeek (constants$V2 rather than constants$constants[2]), this if the code that I am using to solve the simplified example above.

fun <- function(a, b, c) a - constants$V2 * (b - c)

input1a[, lapply(1:2, function(i) fun(get(paste0('a', i)),
                                  get(paste0('b', i)),
                                  get(paste0('c', i)))),
by = ID]

#     ID         V1           V2
# 1:  37  7344.6993   -12297.443
# 2:  45  -755.0824    -8537.864
# 3: 900 15988.7949   -31532.379
Community
  • 1
  • 1
iembry
  • 962
  • 1
  • 7
  • 23

2 Answers2

2

Your function has to have arguments a, b and c, yet you're only passing it a. Thus the error.

I don't understand why you're doing the get within the function, and I would instead do:

# whatever function
fun = function(a, b, c) a + b + c

# evaluate inside the data.table, *then* pass it to your function
input1a[, lapply(1:2, function(i) fun(get(paste0('a', i)),
                                      get(paste0('b', i)),
                                      get(paste0('c', i)))),
          by = ID]

Should be obvious how to change to do get within the function if you so desire.

eddi
  • 49,088
  • 6
  • 104
  • 155
1

I would keep it simple:

fun <- function(a1, a2, b1, b2, c1, c2) {
    res1 = (a1 - constants$V2 * (b1 - c1))
    res2 = (a2 - constants$V2 * (b2 - c2))
    return(list(res1, res2))
}
# no get or apply function

input1a[, fun(a1, a2, b1, b2, c1, c2), by=ID]

input1a
    ID         V1         V2
1:  37  7344.6993 -12297.443
2:  45  -755.0824  -8537.864
3: 900 15988.7949 -31532.379
dpflieger
  • 41
  • 4
  • Thank you for your suggested code, but in my actual case I have sets of 12 columns that I am manipulating so I would rather use eddi's code. – iembry Aug 14 '14 at 15:42