Domanda

Ho un data.table DT con una colonna chiamata RF e molte colonne con sottolinea _dentro. Voglio passare attraverso tutte quelle colonne con una sottolineatura e sottrarre il RF colonna da esso. Tuttavia, sono bloccato. Sembra che tutto sull'RHS del:= operatore in a data.table non funziona con variabili dinamiche.

Ecco il mio DT e l'output desiderato (hardcoded):

library(data.table)
DT <- data.table(RF  = 1:10,
                 S_1 = 11:20,
                 S_2 = 21:30)
#Desired output
DT[ , S_1 := S_1 - RF]
DT[ , S_2 := S_2 - RF]
DT
      RF S_1 S_2
 [1,]  1  10  20
 [2,]  2  10  20
 [3,]  3  10  20
...

Tuttavia, voglio che questo sia più flessibile, cioè loop attraverso ogni colonna con "_" nel suo nome e sottrai RF:

#1. try: Does not work; Interestingly, the i on the LHS of := is interpreted as the column i, but on the RHS of
#:= it is interpreted as 2 and 3, respectively
for (i in grep("_", names(DT))){
  DT[ , i:= i - 1, with=FALSE]
}
DT
          RF  S_1 S_2
 [1,]  1   1   2
 [2,]  2   1   2
 [3,]  3   1   2
...

#2. try: Work with parse and eval
for (i in grep("_", names(DT), value=TRUE)){
  DT[ , eval(parse(text=i)):= eval(parse(text=i)) - RF]
}
#Error in eval(expr, envir, enclos) : object 'S_1' not found

Qualsiasi suggerimento su come farlo sarebbe fantastico.

EDIT: Non appena ho pubblicato la domanda, ho pensato a me stesso: perché stai lavorando con il := Operatore in primo luogo, e abbastanza sicuro, mi sono appena reso conto che non dovevo. Questo funziona e non ha bisogno di un ciclo:

DT[, grep("_", names(DT)), with=FALSE] - DT[, RF]

Scusa per quello. Tuttavia, lascio aperta la domanda perché sono ancora interessato al perché il mio approccio con il := L'operatore non funziona. Quindi forse qualcuno può aiutarmi lì.

È stato utile?

Soluzione

Eri sulla strada giusta con il tuo secondo tentativo. Ecco un approccio che usa substitute per costruire l'espressione che viene trasmessa come il 'j' argomento in DT[ , j ].

for (i in grep("_", names(DT), value=TRUE)){
    e <- substitute(X := X - RF, list(X = as.symbol(i)))
    DT[ , eval(e)]
}
DT
#     RF S_1 S_2
# [1,]  1  10  20
# [2,]  2  10  20
# [3,]  3  10  20
# [4,]  4  10  20
# [5,]  5  10  20

Potresti anche usare un'espressione LHS piuttosto che un simbolo:

for (i in grep("_", names(DT), value=TRUE))
    DT[, (i) := get(i)-RF]

Altri suggerimenti

Una soluzione alternativa che purtroppo ho scoperto dopo aver pubblicato la domanda è la seguente:

DT[, .SD, .SDcols = patterns('_')] - DT[, RF]

Questo funziona anche in un'impostazione più complicata in cui ci sono ulteriori colonne che si desidera conservare, ma con qualche sforzo extra:

library(data.table)
DT <- data.table(RF  = 1:10,
                 S_1 = 11:20,
                 S_2 = 21:30,
                 addCol = rnorm(10)) #Column that should not be subtracted by RF, but still kept in DT

DT <- cbind(DT[, .SD, .SDcols = patterns("_")] - DT[, RF], addCol = DT[, addCol])

Aggiornato all'uso set()+..; set è potente (vedi modifiche per il tentativo precedente).

varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, ..varnames] - DT[, RF])
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top