Boucle à travers les colonnes d'une data.table et de transformer ces colonnes

StackOverflow https://stackoverflow.com/questions/8374816

  •  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.

Était-ce utile?

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])
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top