Dans R data.table, comment transmettre des paramètres variables à une expression ?
-
12-12-2019 - |
Question
Je suis coincé avec un petit problème R avec data.table
.Votre aide est très appréciée.Comment puis-je faire cela:
getResult <- function(dt, expr, gby) {
e <- substitute(expr)
b <- substitute(gby)
return(dt[,eval(e),by=b])
}
v1 <- "Sepal.Length"
v2 <- "Species"
dt <- data.table(iris)
rDT <- getResult(dt, sum(v1, na.rm=TRUE), v2)
J'obtiens l'erreur suivante :
Erreur dans sum(v1, na.rm = TRUE) :«Type» invalide (caractère) de l'argument
Maintenant, les deux v1
et v2
être transmis par un autre programme en tant que variable de caractère, donc je ne peux pas faire ça v1<- quote(Sepal.Length)
ce qui semble fonctionner.
La solution
Une alternative à la réponse de Flodel dans les commentaires pourrait être
e <- parse(text = paste0("sum(", v1, ", na.rm = TRUE)"))
b <- parse(text = v2)
rDT2 <- dt[, eval(e), by = eval(b)]
# b V1
# [1,] setosa 250.3
# [2,] versicolor 296.8
# [3,] virginica 329.4
MODIFIER:
Et pour mettre cela en fonction,
getResult <- function(dt, expr, gby){
return(dt[, eval(expr), by = eval(gby)])
}
(dtR <- getResult(dt = dt, expr = e, gby = b))
# gives the same result as above
EDIT de Matthieu :Il y a une raison subtile pour laquelle paste0
et eval
\ quote
les méthodes peuvent être plus rapides que get
dans certains cas aussi.L'une des raisons pour lesquelles le regroupement peut être rapide est que data.table
inspecte j
pour voir quelles colonnes il utilise, puis sous-ensembles uniquement les colonnes utilisées (FAQ 1.12 et 3.1).Il utilise base::all.vars(j)
pour faire ça.Lors de l'utilisation get()
dans j
la colonne utilisée est masquée all.vars
et data.table
revient à sous-définir toutes les colonnes juste au cas où le j
l'expression en a besoin (un peu comme lorsque le .SD
le symbole est utilisé dans j
, Pour qui .SDcols
a été ajouté pour résoudre).Si toutes les colonnes sont utilisées de toute façon, cela ne fait aucune différence, mais si DT
c'est-à-dire 1e7x100 puis un groupe j=sum(V1)
devrait être beaucoup plus rapide qu'un groupe j=sum(get("V1"))
pour cette raison.Au moins, c'est ce qui est censé se produire, et si ce n'est pas le cas, il s'agit peut-être d'un bug.Si par contre de nombreuses requêtes sont construites dynamiquement et répétées, alors le temps nécessaire pour paste0
et parse
pourrait y entrer.Tout dépend vraiment.Paramètre verbose=TRUE
devrait imprimer un message indiquant quelles colonnes ont été détectées comme étant utilisées par j
, pour que cela puisse être vérifié.