Schleifen Sie die Spalten in einer Daten durch und transformieren Sie diese Spalten

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

  •  27-10-2019
  •  | 
  •  

Frage

Ich habe eine Daten.tabelle DT mit einer Spalte mit dem Namen RF und viele Spalten mit einer Unterstreichung _drin. Ich möchte all diese Spalten mit einer Unterstreichung durchlaufen und die subtrahieren RF Spalte daraus. Ich stecke jedoch fest. Es scheint, dass alles auf dem RHS der:= Operator in a data.table Funktioniert nicht mit dynamischen Variablen.

Hier ist mein DT und die gewünschte Ausgabe (hartcodiert):

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

Ich möchte jedoch, dass dies flexibler ist, dh in jeder Spalte mit "_" in seinem Namen durchlaufen und subtrahieren 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

Alle Hinweise, wie man das macht, wäre großartig.

Bearbeiten: Sobald ich die Frage gestellt habe, dachte ich mir: Warum arbeiten Sie mit dem zusammen := Der Bediener in erster Linie und sicherlich wurde mir klar, dass ich es nicht muss. Dies funktioniert und braucht keine Schleife:

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

Das tut mir leid. Ich lasse die Frage jedoch offen, weil ich immer noch daran interessiert bin, warum mein Ansatz mit dem := Der Bediener funktioniert nicht. Vielleicht kann mir jemand dort helfen.

War es hilfreich?

Lösung

Sie waren mit Ihrem zweiten Versuch auf dem richtigen Weg. Hier ist ein Ansatz, der verwendet substitute Um den Ausdruck zu bauen, der als das übergeben wird 'j' Argument 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

Sie können auch eher einen LHS -Ausdruck als ein Symbol verwenden:

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

Andere Tipps

Eine Problemumgehung, die ich leider entdeckt habe, nachdem ich die Frage veröffentlicht habe, lautet wie folgt:

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

Dies funktioniert auch in einer komplizierteren Einstellung, in der es zusätzliche Spalten gibt, die Sie aufbewahren möchten, aber mit zusätzlichen Aufwand:

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])

Aktualisiert, um sie zu verwenden set()+..; set ist mächtig (siehe Änderungen für früheren Versuch).

varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, ..varnames] - DT[, RF])
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top