mlegge
mlegge

Reputation: 6913

Operations on data table with variable column name

I am trying to perform operations on a data.table's column that is passed as a variable.

Here is a toy example:

library(data.table)
set.seed(2)
DT <- data.table(replicate(3, runif(4)))
> DT
          V1        V2        V3
1: 0.1848823 0.9438393 0.4680185
2: 0.7023740 0.9434750 0.5499837
3: 0.5733263 0.1291590 0.5526741
4: 0.1680519 0.8334488 0.2388948

Say the column of interest is passed as the value of a variable:

> print(target.column <- sample(colnames(DT), 1))
[1] "V3"

So I would like to perform some operation on column V3, say, flooring the value at 0.5 for simplicity. I have successfully made this work by using the dreaded paste, parse and eval:

> eval(parse(text = paste0("DT[", target.column, " < 0.5, ", target.column, " := 0.5, ]")))
          V1        V2        V3
1: 0.1848823 0.9438393 0.5000000
2: 0.7023740 0.9434750 0.5499837
3: 0.5733263 0.1291590 0.5526741
4: 0.1680519 0.8334488 0.5000000

But have been unsuccessful in my other attempts:

> DT[eval(target.column) < 0.5, eval(target.column) := 0.5, ]
          V1        V2        V3
1: 0.1848823 0.9438393 0.4680185
2: 0.7023740 0.9434750 0.5499837
3: 0.5733263 0.1291590 0.5526741
4: 0.1680519 0.8334488 0.2388948
> DT[as.name(target.column) < 0.5, as.name(target.column) := 0.5, ]
          V1        V2        V3
1: 0.1848823 0.9438393 0.4680185
2: 0.7023740 0.9434750 0.5499837
3: 0.5733263 0.1291590 0.5526741
4: 0.1680519 0.8334488 0.2388948
> DT[deparse(substitute(target.column)) < 0.5, deparse(substitute(target.column)) := 0.5, ]
          V1        V2        V3
1: 0.1848823 0.9438393 0.4680185
2: 0.7023740 0.9434750 0.5499837
3: 0.5733263 0.1291590 0.5526741
4: 0.1680519 0.8334488 0.2388948

I have looked for solutions on SO and the ol' interweb have not been able to find anything useful... is there a "data.table" way to do this?

Upvotes: 0

Views: 245

Answers (2)

akrun
akrun

Reputation: 886938

A modification of your code will be to use eval(as.symbol( or eval(as.name(

 DT[ eval(as.symbol(target.column)) < .5, (target.column):= .5][]
 #         V1        V2        V3
 #1: 0.1848823 0.9438393 0.5000000
 #2: 0.7023740 0.9434750 0.5499837
 #3: 0.5733263 0.1291590 0.5526741
 #4: 0.1680519 0.8334488 0.5000000

Upvotes: 1

Frank
Frank

Reputation: 66819

You can use

DT[ get(target.column) < .5, (target.column) := .5]

which gives the desired result.

Upvotes: 4

Related Questions