1

I am looking for a way to multiply several columns of a data.table by several other columns in the same DT. Another post focused on the way to multiply many columns by a specific column in the same DT Multiply many columns by a specific other column in R with data.table?. My question broadens this prior question.

Starting with this DT:

DT <- data.table(x1 = 1:5L, y1 = 6:10L, x2 = 11:15L, y2 = 16:20L)

   x1 y1 x2 y2
1:  1  6 11 16
2:  2  7 12 17
3:  3  8 13 18
4:  4  9 14 19
5:  5 10 15 20

I want to multiply z1 = x1 * y1, and z2 = x2 * y2 to obtain

   x1 y1 x2 y2 z1  z2
1:  1  6 11 16  6 176
2:  2  7 12 17 14 204
3:  3  8 13 18 24 234
4:  4  9 14 19 36 266
5:  5 10 15 20 50 300

Here is a brute force way of building the desired DT:

DT2[, ':='(z1 = x1 * y1, z2 = x2 * y2]

Certainly there must be an elegant way to do this.

Henrik
  • 65,555
  • 14
  • 143
  • 159
flemingcra
  • 41
  • 3

2 Answers2

4

Probably a matter of taste, but you could use Map and build some lists to feed it.

DT[, c("z1", "z2") := Map("*", list(x1, x2), list(y1, y2))]

Expanding to many variables combine with mget and ls, do

DT[, c("z1", "z2") := Map("*", mget(ls(pattern="x")), mget(ls(pattern="y")))]

Both of these return the desired result

DT
   x1 y1 x2 y2 z1  z2
1:  1  6 11 16  6 176
2:  2  7 12 17 14 204
3:  3  8 13 18 24 234
4:  4  9 14 19 36 266
5:  5 10 15 20 50 300

I'll just mention that mget and ls with patterns can be used to return lists of objects that exist in a particular environment. ls searches the parent environment by default, which is the environment of the data.table in which it was called. So in the instance that you have an object named x3 that exists outside of the data.table, you needn't worry: that object is ignored.

lmo
  • 37,904
  • 9
  • 56
  • 69
0

I found this answer R data.table calculate new columns in lapply by searching tags "data.table" + "calculated-columns". By extension the answer to my question would be:

DT <- data.table(x1 = 1:5L, y1 = 6:10L, x2 = 11:15L, y2 = 16:20L)
FUN <- function(ndx, DT) {DT[, paste("z", ndx, sep = "") := get(paste("x", ndx, sep = "")) *  get(paste("y", ndx, sep = ""))]}
lapply(1:2, FUN, DT)

DT
x1 y1 x2 y2 z1  z2
1:  1  6 11 16  6 176
2:  2  7 12 17 14 204
3:  3  8 13 18 24 234
4:  4  9 14 19 36 266
5:  5 10 15 20 50 300

Although this is obviously an answer, it's perhaps understandable how I couldn't find it because I think the title lacks specificity. That said, is there a more straightforward way to approach the question raised here?

flemingcra
  • 41
  • 3