Sto riscontrando problemi nel refactoring di dplyr in modo da preservare la valutazione non standard. Diciamo che voglio creare una funzione che seleziona e rinomina sempre.Programmazione con dplyr e 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()
è scritto in base alla risposta a questo post Refactor R code when library functions use non-standard evaluation. select_happy()
funziona su nomi di colonna non definiti o definiti nell'ambiente globale. Tuttavia, si imbatte in problemi quando il nome di una colonna è anche il nome di una funzione in un altro spazio dei nomi.
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>
Calling lazy()
sul fe lm mostra una differenza nell'oggetto pigri, in cui la definizione di funzione per lm sta comparendo nell'oggetto pigri, e per f è proprio il nome della funzione.
lazy(f)
# <lazy>
# expr: f
# env: <environment: R_GlobalEnv>
lazy(lm)
# <lazy>
# expr: function (formula, data, subset, weights, na.action, method = "qr", ...
# env: <environment: R_GlobalEnv>
substitute
sembra funzionare con lm.
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
Tuttavia, dopo aver letto the vignette on lazyeval
sembra che lazy
dovrebbe servire come un sostituto superiore per substitute
. Inoltre, la normale funzione select
funziona perfettamente.
select(df, happy=lm)
# happy
# 1 7
# 2 8
# 3 9
mia domanda è come posso scrivere select_happy()
in modo che funzioni in tutti i modi che select()
fa? Sto attraversando un periodo difficile che gira la testa sulla valutazione dell'ambito e non standard. Più in generale, quale sarebbe una solida strategia per programmare con dplyr che potrebbe evitare questi e altri problemi?
Modifica
Ho provato la soluzione docendo di discimus e ha funzionato grande, ma mi piacerebbe sapere se c'è un modo per utilizzare argomenti, piuttosto che i punti, per la funzione. Penso che sia anche importante poter usare interp()
perché potresti voler inserire l'input in una formula più complicata, come nel post che ho inserito in precedenza. Penso che il nocciolo del problema sia dovuto al fatto che lazy_dots()
sta acquisendo l'espressione in modo diverso da lazy()
. Vorrei capire perché si comportano in modo diverso e come utilizzare lazy()
per ottenere la stessa funzionalità di lazy_dots()
.
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>
anche cambiando .follow__symbols
-FALSE
per lazy()
in modo che sia lo stesso che lazy_dots()
non funziona.
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>
Mi sento davvero un po 'bloccato su cosa fare.
@Henrik questo è quello che volevo dire! Emette comunque un errore, e nel complesso il problema è lo stesso. Ho aggiornato la domanda per riflettere la correzione. –