Ich habe Probleme bei der Refactoring dplyr in einer Weise, die nicht-Standard-Bewertung erhält. Sagen wir, ich möchte eine Funktion erstellen, die immer auswählt und umbenennt.Programmierung mit dplyr und lazyeval
library(lazyeval)
library(dplyr)
df <- data.frame(a = c(1,2,3), f = c(4,5,6), lm = c(7, 8 , 9))
select_happy<- function(df, col){
col <- lazy(col)
fo <- interp(~x, x=col)
select_(df, happy=fo)
}
f <- function(){
print('foo')
}
select_happy()
geschrieben nach der Antwort auf diesen Beitrag Refactor R code when library functions use non-standard evaluation. select_happy()
arbeitet mit Spaltennamen, die entweder nicht definiert oder in der globalen Umgebung definiert sind. Es treten jedoch Probleme auf, wenn ein Spaltenname auch der Name einer Funktion in einem anderen Namespace ist.
select_happy(df, a)
# happy
# 1 1
# 2 2
# 3 3
select_happy(df, f)
# happy
# 1 4
# 2 5
# 3 6
select_happy(df, lm)
# Error in eval(expr, envir, enclos) (from #4) : object 'datafile' not found
environment(f)
# <environment: R_GlobalEnv>
environment(lm)
# <environment: namespace:stats>
Aufruf lazy()
auf f und lm zeigt einen Unterschied in dem faulen Objekt, in dem die Funktionsdefinition für lm wird in dem faulen Objekt erscheinen und für f es ist nur der Name der Funktion.
substitute
scheint mit lm zu arbeiten.
select_happy<- function(df, col){
col <- substitute(col) # <- substitute() instead of lazy()
fo <- interp(~x, x=col)
select_(df, happy=fo)
}
select_happy(df, lm)
# happy
# 1 7
# 2 8
# 3 9
Doch nach the vignette on lazyeval
Lesen scheint es, dass lazy
als überlegen Ersatz für substitute
dienen sollte. Darüber hinaus funktioniert die reguläre select
Funktion gut.
select(df, happy=lm)
# happy
# 1 7
# 2 8
# 3 9
Meine Frage ist, wie kann ich select_happy()
so schreiben, dass es in allen Wegen, die funktioniert select()
tun? Es fällt mir schwer, mich in die Scoping- und Nicht-Standard-Evaluierung zu vertiefen. Allgemeiner ausgedrückt: Was wäre eine solide Strategie für die Programmierung mit dplyr, die diese und andere Probleme vermeiden könnte?
bearbeiten
testete ich docendo discimus-Lösung aus und es funktionierte großartig, aber ich würde es gerne wissen, ob ein Weg, um Argumente zu verwenden, anstatt Punkte, für die Funktion. Ich denke, es ist auch wichtig, interp()
verwenden zu können, da Sie möglicherweise Eingaben in eine kompliziertere Formel eingeben möchten, wie in dem Beitrag, mit dem ich früher verlinkt habe. Ich denke, dass der Kern des Problems auf die Tatsache zurückzuführen ist, dass lazy_dots()
den Ausdruck anders erfasst als lazy()
. Ich würde gerne verstehen, warum sie sich anders verhalten, und wie man lazy()
verwendet, um die gleiche Funktionalität wie lazy_dots()
zu erhalten.
g <- function(...){
lazy_dots(...)
}
h <- function(x){
lazy(x)
}
g(lm)[[1]]
# <lazy>
# expr: lm
# env: <environment: R_GlobalEnv>
h(lm)
# <lazy>
# expr: function (formula, data, subset, weights, na.action, method = "qr", ...
# env: <environment: R_GlobalEnv>
Auch .follow__symbols
-FALSE
für lazy()
zu ändern, so dass es die gleiche wie lazy_dots()
ist nicht funktioniert.
lazy
# function (expr, env = parent.frame(), .follow_symbols = TRUE)
# {
# .Call(make_lazy, quote(expr), environment(), .follow_symbols)
# }
# <environment: namespace:lazyeval>
lazy_dots
# function (..., .follow_symbols = FALSE)
# {
# if (nargs() == 0)
# return(structure(list(), class = "lazy_dots"))
# .Call(make_lazy_dots, environment(), .follow_symbols)
# }
# <environment: namespace:lazyeval>
h2 <- function(x){
lazy(x, .follow_symbols=FALSE)
}
h2(lm)
# <lazy>
# expr: x
# env: <environment: 0xe4a42a8>
Ich fühle mich nur irgendwie fest, was zu tun ist.
@Henrik das ist, was ich wollte! Es wird jedoch immer noch ein Fehler ausgegeben, und insgesamt ist das Problem das gleiche. Ich habe die Frage aktualisiert, um die Korrektur widerzuspiegeln. –