Dean MacGregor - 1 year ago 80
R Question

# How to apply same function to every specified column in a data.table

I have a data.table and I wish to perform the same calculation on certain specified columns. The names of these columns are given in a character vector. In this particular example, I'd like to multiply all these columns by -1.

Some toy data and a vector specifying relevant columns:

``````library(data.table)
dt <- data.table(a = 1:3, b = 1:3, d = 1:3)
cols <- c("a", "b")
``````

Right now I'm doing it this way, looping over the character vector:

``````for (col in 1:length(cols)) {
dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))]
}
``````

Is there a way to do this directly without the for loop?

This seems to work:

``````dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols]
``````

The result is

``````    a  b d
1: -1 -1 1
2: -2 -2 2
3: -3 -3 3
``````

There are a few tricks here:

• Because there are parentheses in `(cols) :=`, the result is assigned to the columns specified in `cols`, instead of to some new variable named "cols".
• `.SDcols` tells the call that we're only looking at those columns, and allows us to use `.SD`, the `S`ubset of the `D`ata associated with those columns.
• `lapply(.SD, ...)` operates on `.SD`, which is a list of columns (like all data.frames and data.tables). `lapply` returns a list, so in the end `j` looks like `cols := list(...)`.

EDIT: Here's another way that is probably faster, as @Arun mentioned:

``````for (j in cols) set(dt, j = j, value = -dt[[j]])
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download