0

I would like to apply a function to a data table which has more than 1 arguments.

Assume:

dt<-as.data.table(matrix(c(201,202,201,201,202,202,4,6,9,2,4,5,6,9,7,3,2,1), nrow = 6, ncol = 3, byrow = FALSE))

    V1 V2 V3
1: 201  4  6
2: 202  6  9
3: 201  9  7
4: 201  2  3
5: 202  4  2
6: 202  5  1

I would like to apply a function with 3 arguments. For the sake of simplicity let's take a sum of them.

Obviously solution is not dt[,sum:=V1+V2+V3]

If I would pass 2nd and 3rd arguments in following way, it does not work.

dt[,sum:=lapply(V1,function(x,y,z) x+y+z,y=V2,z=V3)]

What is the proper way of applying a function with more than 1 arguments?

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
Erdem Akkas
  • 2,062
  • 10
  • 15
  • These are not same as my question is not about taking rowsums. My question was to apply function with more than one arguments. – Erdem Akkas Jan 18 '17 at 10:19

2 Answers2

4

mapply() lets you loop over multiple vectors as arguments, using the corresponding position of the arguments with each other.

dt[,sum:=mapply(function(x,y,z) x+y+z, V1, V2, V3)]

   V1 V2 V3 sum
1: 201  4  6 211
2: 202  6  9 217
3: 201  9  7 217
4: 201  2  3 206
5: 202  4  2 208
6: 202  5  1 208
LAP
  • 6,605
  • 2
  • 15
  • 28
3

We can use Reduce with +

dt[, Sum := Reduce(`+`, .SD)]
dt
#    V1 V2 V3 Sum
#1: 201  4  6 211
#2: 202  6  9 217
#3: 201  9  7 217
#4: 201  2  3 206
#5: 202  4  2 208
#6: 202  5  1 208

If there are multiple arguments, one option is Map with do.call. Create the function of interest ('f1'), then specify the columns that will go as argument in .SDcols, use do.call with Map as argument, specify the function 'f1', unlist the output and assign (:=) it to 'Sum'

f1 <- function(x, y, z)  x + y + z    
dt[, Sum := unlist(do.call(Map, c(f=f1, unname(.SD)))), .SDcols = V1:V3]
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 2
    This only works in the sum case, if you want to apply a function with 3 arguments instead of reducing with an associative two argument function this will not work. – snaut Jan 18 '17 at 08:30
  • @snaut It also works with `*` i.e. `dt[, Reduce(`*`, .SD)]` – akrun Jan 18 '17 at 08:31
  • Sorry `+` was too specific, `*` is an associative, two argument operation thoug. – snaut Jan 18 '17 at 08:33
  • 2
    @snaut I added another version of `mapply` for the case you mentioned – akrun Jan 18 '17 at 08:39