Boucle à travers les colonnes d'une data.table et de transformer ces colonnes
-
27-10-2019 - |
Question
J'ai un DT
data.table avec une colonne nommée RF
et de colonnes avec un soulignement _
in il. Je veux faire une boucle à travers toutes les colonnes avec un
soulignement et soustraire la colonne RF
de celui-ci. Cependant, je suis coincé. Il semble que tout sur la partie droite de la
opérateur :=
dans un data.table
ne fonctionne pas avec des variables dynamiques.
Voici mon DT
et la sortie désirée (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
...
Cependant, je veux que ce soit plus souple, à savoir une boucle à travers chaque colonne avec « _ » en son nom et Soustraire 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
Les conseils comment faire ce serait génial.
EDIT: Dès que je posté la question, je me suis dit: Pourquoi travaillez-vous avec l'opérateur :=
en premier lieu, et bien sûr, je viens de réaliser que je n'ai pas. Cela fonctionne et n'a pas besoin d'une boucle:
DT[, grep("_", names(DT)), with=FALSE] - DT[, RF]
Désolé pour cela. Cependant, je laisse la question ouverte parce que je suis toujours intéressé pourquoi mon approche avec l'opérateur :=
ne fonctionne pas. Alors peut-être que quelqu'un peut me aider.
La solution
Vous étiez sur la bonne voie avec votre deuxième tentative. Voici une approche qui utilise substitute
pour construire l'expression qui est passé en tant que l'argument 'j'
dans 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
Vous pouvez également utiliser une expression LHS plutôt qu'un symbole:
for (i in grep("_", names(DT), value=TRUE))
DT[, (i) := get(i)-RF]
Autres conseils
Une solution que je malheureusement découvert après avoir posté la question est la suivante:
DT[, .SD, .SDcols = patterns('_')] - DT[, RF]
Cela fonctionne aussi dans un cadre plus compliqué dans lequel il y a des colonnes supplémentaires que vous souhaitez conserver, mais avec un peu d'effort supplémentaire:
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])
Mise à jour à l'utilisation set()
+ ..
; set
est puissant (voir les modifications pour tentative précédente).
varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, ..varnames] - DT[, RF])