Variables globales y locales en R

126

Soy un novato en R, y estoy bastante confundido con el uso de variables locales y globales en R.

Leí algunas publicaciones en Internet que dicen si uso =o <-asignaré la variable en el entorno actual, y con ella <<-puedo acceder a una variable global cuando estoy dentro de una función.

Sin embargo, como recuerdo en C ++, las variables locales surgen cada vez que declara una variable entre paréntesis {}, por lo que me pregunto si esto es lo mismo para R. ¿O es solo para las funciones en R que tenemos el concepto de variables locales?

Hice un pequeño experimento, que parece sugerir que solo los corchetes no son suficientes, ¿me equivoco?

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4
Vokram
fuente
Algún código para ejecutar además de estas respuestas:, globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env...
isomorphismes
@isomorphismes, Error: could not find function "%>%". ¿Es esa otra forma de asignación?
Aaron McDaid
1
Tema relevante en R-help: ¿Qué significa el operador "<< -"? .
Henrik
1
@AaronMcDaid Hola, lo siento por no responder antes. Es decir, de require(magrittr). Es una forma de aplicar funciones a la derecha ( x | f1 | f2 | f3) en lugar de a la izquierda ( f3( f2( f1( x ) ) )).
isomorfismos el

Respuestas:

153

Las variables declaradas dentro de una función son locales para esa función. Por ejemplo:

foo <- function() {
    bar <- 1
}
foo()
bar

da el error siguiente: Error: object 'bar' not found.

Si desea hacer baruna variable global, debe hacer:

foo <- function() {
    bar <<- 1
}
foo()
bar

En este caso bares accesible desde fuera de la función.

Sin embargo, a diferencia de C, C ++ o muchos otros lenguajes, los corchetes no determinan el alcance de las variables. Por ejemplo, en el siguiente fragmento de código:

if (x > 10) {
    y <- 0
}
else {
    y <- 1
}

ypermanece accesible después de la if-elsedeclaración.

Como bien dices, también puedes crear entornos anidados. Puede echar un vistazo a estos dos enlaces para comprender cómo usarlos:

  1. http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
  2. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

Aquí tienes un pequeño ejemplo:

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found
betabandido
fuente
136

<- realiza tareas en el entorno actual.

Cuando estás dentro de una función, R crea un nuevo entorno para ti. Por defecto, incluye todo desde el entorno en el que se creó para que pueda usar esas variables también, pero cualquier cosa nueva que cree no se escribirá en el entorno global.

En la mayoría de los casos, <<-se asignará a variables que ya están en el entorno global o creará una variable en el entorno global, incluso si está dentro de una función. Sin embargo, no es tan sencillo como eso. Lo que hace es verificar el entorno primario para una variable con el nombre de interés. Si no lo encuentra en su entorno principal, va al principal del entorno principal (en el momento en que se creó la función) y mira allí. Continúa hacia arriba al entorno global y, si no se encuentra en el entorno global, asignará la variable en el entorno global.

Esto podría ilustrar lo que está sucediendo.

bar <- "global"
foo <- function(){
    bar <- "in foo"
    baz <- function(){
        bar <- "in baz - before <<-"
        bar <<- "in baz - after <<-"
        print(bar)
    }
    print(bar)
    baz()
    print(bar)
}
> bar
[1] "global"
> foo()
[1] "in foo"
[1] "in baz - before <<-"
[1] "in baz - after <<-"
> bar
[1] "global"

La primera vez que imprimimos la barra no hemos llamado footodavía, por lo que aún debería ser global, esto tiene sentido. La segunda vez que imprimimos está dentro de fooantes de llamar, bazpor lo que el valor "in foo" tiene sentido. Lo siguiente es donde vemos lo <<-que realmente está haciendo. El siguiente valor impreso es "en baz - antes << -" aunque la declaración de impresión viene después de <<-. Esto se debe a <<-que no se ve en el entorno actual (a menos que esté en el entorno global, en cuyo caso <<-actúa como tal <-). Entonces, dentro del bazvalor de la barra permanece como "en baz - antes de << -". Una vez que llamamos a bazla copia de la barra dentro de foose cambia a "in baz", pero como podemos ver, el global no barha cambiado.barque se define dentro de fooestá en el entorno principal cuando creamos, bazpor lo que esta es la primera copia de lo barque <<-ve y, por lo tanto, la copia a la que se asigna. Entonces, <<-no es solo asignar directamente al entorno global.

<<-es complicado y no recomendaría usarlo si puedes evitarlo. Si realmente desea asignar al entorno global, puede usar la función de asignación y decirle explícitamente que desea asignar globalmente.

Ahora cambio el <<-a una declaración de asignación y podemos ver qué efecto tiene:

bar <- "global"
foo <- function(){
    bar <- "in foo"   
    baz <- function(){
        assign("bar", "in baz", envir = .GlobalEnv)
    }
    print(bar)
    baz()
    print(bar)
}
bar
#[1] "global"
foo()
#[1] "in foo"
#[1] "in foo"
bar
#[1] "in baz"

Entonces, las dos veces que imprimimos la barra dentro del foovalor está "in foo" incluso después de llamar baz. Esto se debe a que assignnunca consideró la copia del barinterior de foo porque le dijimos exactamente dónde buscar. Sin embargo, esta vez el valor de la barra en el entorno global cambió porque lo asignamos explícitamente allí.

Ahora también preguntó sobre la creación de variables locales y puede hacerlo con bastante facilidad sin crear una función ... Solo necesitamos usar la localfunción.

bar <- "global"
# local will create a new environment for us to play in
local({
    bar <- "local"
    print(bar)
})
#[1] "local"
bar
#[1] "global"
Razón
fuente
2

Un poco más en la misma línea

attrs <- {}

attrs.a <- 1

f <- function(d) {
    attrs.a <- d
}

f(20)
print(attrs.a)

imprimirá "1"

attrs <- {}

attrs.a <- 1

f <- function(d) {
   attrs.a <<- d
}

f(20)
print(attrs.a)

Imprimirá "20"

Semántica
fuente