varias transformar tablas leyendas graficos graficas estadistica español comandos r function environment-variables with-statement assign

transformar - En R, ¿cómo hacer que las variables dentro de una función estén disponibles para la función de nivel inferior dentro de esta función?(Con, adjuntar, entorno)



transformar variables en r (3)

Actualización 2 @G. Grothendieck publicó dos enfoques. El segundo es cambiar el entorno de la función dentro de una función. Esto resuelve mi problema de demasiadas repeticiones de codificación. No estoy seguro de si este es un buen método para pasar la verificación de CRAN al convertir mis scripts en un paquete. Voy a actualizar de nuevo cuando tenga algunas conclusiones.

Actualizar

Estoy tratando de pasar muchas variables de argumento de entrada a f2 y no quiero indexar cada variable dentro de la función como env$c, env$d, env$calls , es por eso que intenté usar with en f5 y f6 ( una f2 modificada). Sin embargo, assign no funciona con dentro de {} , mover assign fuera with hará el trabajo, pero en mi caso real tengo algunas assign dentro de las expresiones with que no sé cómo sacarlas de la función with fácilmente.

Aquí hay un ejemplo:

## In the <environment: R_GlobalEnv> a <- 1 b <- 2 f1 <- function(){ c <- 3 d <- 4 f2 <- function(P){ assign("calls", calls+1, inherits=TRUE) print(calls) return(P+c+d) } calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f2(P=0) c <- c+1 d <- d+1 } return(v) } f1()

La función f2 está dentro de f1 , cuando se llama a f2 , busca las calls,c,d variables calls,c,d en el entorno de environment(f1) . Esto es lo que quería.

Sin embargo, cuando quiero usar f2 también en las otras funciones, definiré esta función en el entorno global, en cambio, la llamaré f4 .

f4 <- function(P){ assign("calls", calls+1, inherits=TRUE) print(calls) return(P+c+d) }

Esto no funcionará, porque buscará las calls,c,d en el entorno global en lugar de dentro de una función donde se llama la función. Por ejemplo:

f3 <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f4(P=0) ## or replace here with f5(P=0) c <- c+1 d <- d+1 } return(v) } f3()

La forma segura debe ser definir calls,c,d en los argumentos de entrada de f4 y luego pasar estos parámetros a f4 . Sin embargo, en mi caso, hay demasiadas variables para pasar a esta función f4 y sería mejor que pueda pasarlo como entorno y decirle a f4 que no mire en el entorno global ( environment(f4) ), solo busque Dentro del environment cuando se llama f3 .

La forma en que lo resuelvo ahora es usar el entorno como una lista y usar la función with .

f5 <- function(P,liste){ with(liste,{ assign("calls", calls+1, inherits=TRUE) print(calls) return(P+c+d) } ) } f3 <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f5(P=0,as.list(environment())) ## or replace here with f5(P=0) c <- c+1 d <- d+1 } return(v) } f3()

Sin embargo, ahora assign("calls", calls+1, inherits=TRUE) no funciona como debería ya que assign no modifica el objeto original. Las calls variables están conectadas a una función de optimización donde la función objetivo es f5 . Esa es la razón por la que utilizo assign lugar de pasar calls como argumentos de entrada. El uso de attach tampoco es claro para mí. Aquí está mi manera de corregir el problema de assign :

f7 <- function(P,calls,liste){ ##calls <<- calls+1 ##browser() assign("calls", calls+1, inherits=TRUE,envir = sys.frame(-1)) print(calls) with(liste,{ print(paste(''with the listed envrionment, calls='',calls)) return(P+c+d) } ) } ######## ################## f8 <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ ##browser() ##v[i] <- f4(P=0) ## or replace here with f5(P=0) v[i] <- f7(P=0,calls,liste=as.list(environment())) c <- c+1 d <- d+1 } f7(P=0,calls,liste=as.list(environment())) print(paste(''final call number'',calls)) return(v) } f8()

No estoy seguro de cómo se debe hacer esto en R. ¿Estoy en la dirección correcta, especialmente al pasar por el control CRAN? ¿Alguien tiene algunos consejos sobre esto?


En general, diría que cualquier variable que sea necesaria dentro de una función debe transmitirse a través de sus argumentos. Además, si su valor se necesita más adelante, se lo devolverá de la función. No hacer esto puede conducir rápidamente a resultados extraños, por ejemplo, si hay varias funciones que definen una variable x , cuál debe usarse. Si la cantidad de variables es mayor, creará una estructura de datos personalizada, por ejemplo, colocándolas en una lista con nombre.


También se podría usar una función que redefine otras funciones en el entorno especificado.

test_var <- "global" get_test_var <- function(){ return(test_var) } some_function <- function(){ test_var <- "local" return(get_test_var()) } some_function() # Returns "global". Not what we want here... # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ some_function2 <- function(){ test_var <- "local" # define function locally get_test_var2 <- function(){ return(test_var) } return(get_test_var2()) } some_function2() # Returns "local", but ''get_test_var2'' can''t be used in other places. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ add_function_to_envir <- function(my_function_name, to_envir) { script_text <- capture.output(eval(parse(text = my_function_name))) script_text[1] <- paste0(my_function_name, " <- ", script_text[1]) eval(parse(text = script_text), envir = to_envir) } some_function3 <- function(){ test_var <- "local" add_function_to_envir("get_test_var", environment()) return(get_test_var()) } some_function3() # Returns "local" and we can use ''get_test_var'' from anywhere.

Aquí add_function_to_envir(my_function_name, to_envir) captura el script de la función, lo analiza y lo reevalúa en el nuevo entorno.

Nota: el nombre de la función para my_function_name debe estar entre comillas.


(1) Entorno de la persona que llama. Puede pasar explícitamente el entorno padre e indexarlo. Prueba esto:

f2a <- function(P, env = parent.frame()) { env$calls <- env$calls + 1 print(env$calls) return(P + env$c + env$d) } a <- 1 b <- 2 # same as f1 except f2 removed and call to f2 replaced with call to f2a f1a <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f2a(P=0) c <- c+1 d <- d+1 } return(v) } f1a()

(2) Restablecer el entorno de la función llamada es restablecer el entorno de f2b en f1b como se muestra aquí:

f2b <- function(P) { calls <<- calls + 1 print(calls) return(P + c + d) } a <- 1 b <- 2 # same as f1 except f2 removed, call to f2 replaced with call to f2b # and line marked ## at the beginning is new f1b <- function(){ environment(f2b) <- environment() ## c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f2b(P=0) c <- c+1 d <- d+1 } return(v) } f1b()

(3) Macro usando eval.parent (sustituto (...)) Otro enfoque es definir una construcción de tipo macro que inyecta efectivamente el cuerpo de f2c en línea en f1c1 . Aquí f2c es lo mismo que f2b excepto por las calls <- calls + 1 line (no <<- needed) y el eval.parent(substitute({...})) todo el cuerpo en eval.parent(substitute({...})) . f1c es lo mismo que f1a excepto que la llamada a f2a se reemplaza con una llamada a f2c .

f2c <- function(P) eval.parent(substitute({ calls <- calls + 1 print(calls) return(P + c + d) })) a <- 1 b <- 2 f1c <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f2c(P=0) c <- c+1 d <- d+1 } return(v) } f1c()

(4) defmacro Esto es casi lo mismo que la última solución, excepto que usa defmacro en el paquete gtools para definir la macro en lugar de hacerlo nosotros mismos. (También vea el paquete Rcmdr para otra versión de defmacro). Debido a la forma en que funciona defmacro , también debemos pasar calls pero como es una macro y no una función, esto solo le dice que sustituya las calls y no es lo mismo que pasar calls a un función.

library(gtools) f2d <- defmacro(P, calls, expr = { calls <- calls + 1 print(calls) return(P + c + d) }) a <- 1 b <- 2 f1d <- function(){ c <- 3 d <- 4 calls <- 0 v <- vector() for(i in 1:10){ v[i] <- f2d(P=0, calls) c <- c+1 d <- d+1 } return(v) } f1d()