Cuggi attraverso colonne in un data. Tabella e trasforma quelle colonne
-
27-10-2019 - |
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ì.
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])