Variáveis ​​globais e locais em R


126

Sou iniciante em R e estou bastante confuso com o uso de variáveis ​​locais e globais em R.

Li algumas postagens na internet que dizem se eu uso =ou <-atribuirei a variável no ambiente atual e, com <<-isso, posso acessar uma variável global quando dentro de uma função.

No entanto, como eu lembro em C ++, variáveis ​​locais surgem sempre que você declara uma variável entre colchetes {}, então, eu estou querendo saber se isso é o mesmo para R? Ou é apenas para funções em R que temos o conceito de variáveis ​​locais.

Fiz um pequeno experimento, que parece sugerir que apenas colchetes não são suficientes. Estou entendendo algo errado?

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4

Algum código a ser executado além dessas respostas: globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env,…
isomorfismos

@isomorphismes Error: could not find function "%>%",. Essa é outra forma de atribuição?
Aaron McDaid

1
Encadeamento relevante na R-help: O que significa o operador "<< -"? .
Henrik

1
@AaronMcDaid Oi, desculpe por não responder mais cedo! Isso é de require(magrittr). É uma maneira de aplicar funções à direita ( x | f1 | f2 | f3) em vez de à esquerda ( f3( f2( f1( x ) ) )).
isomorphismes

Respostas:


153

Variáveis ​​declaradas dentro de uma função são locais para essa função. Por exemplo:

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

dá o seguinte erro: Error: object 'bar' not found.

Se você deseja criar baruma variável global, faça:

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

Nesse caso, baré acessível de fora da função.

No entanto, diferentemente de C, C ++ ou de muitas outras linguagens, os colchetes não determinam o escopo das variáveis. Por exemplo, no seguinte trecho de código:

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

ypermanece acessível após a if-elsedeclaração.

Como você bem diz, também é possível criar ambientes aninhados. Você pode dar uma olhada nesses dois links para entender como usá-los:

  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

Aqui você tem um pequeno exemplo:

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

136

<- faz atribuição no ambiente atual.

Quando você está dentro de uma função, R cria um novo ambiente para você. Por padrão, inclui tudo, desde o ambiente em que foi criado, para que você possa usar essas variáveis ​​também, mas qualquer coisa nova que você criar não será gravada no ambiente global.

Na maioria dos casos <<-, atribuirá a variáveis ​​que já estão no ambiente global ou criará uma variável no ambiente global, mesmo se você estiver dentro de uma função. No entanto, não é tão simples assim. O que ele faz é verificar no ambiente pai uma variável com o nome de interesse. Se ele não o encontrar no ambiente pai, ele será direcionado ao pai do ambiente pai (no momento em que a função foi criada) e procurado lá. Ele continua ascendendo ao ambiente global e, se não for encontrado no ambiente global, atribuirá a variável ao ambiente global.

Isso pode ilustrar o que está acontecendo.

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"

A primeira vez que imprimimos barra, ainda não ligamos, fooportanto ainda deve ser global - isso faz sentido. Na segunda vez em que imprimimos, fooantes de chamar baz, o valor "in foo" faz sentido. A seguir, é onde vemos o que <<-realmente está fazendo. O próximo valor impresso é "in baz - before << -", mesmo que a instrução print venha após o <<-. Isso ocorre porque <<-não parece no ambiente atual (a menos que você esteja no ambiente global, caso em que <<-atua como <-). Portanto, dentro do bazvalor da barra permanece como "in baz - before << -". Depois que chamamos baza cópia da barra dentro de fooé alterada para "in baz", mas como podemos ver, o global barpermanece inalterado.barque é definido dentro de fooestá no ambiente pai quando criamos, bazportanto esta é a primeira cópia do barque <<-vê e, portanto, a cópia à qual ele atribui. Portanto, <<-não é apenas atribuir diretamente ao ambiente global.

<<-é complicado e eu não recomendaria usá-lo se você puder evitá-lo. Se você realmente deseja atribuir ao ambiente global, pode usar a função de atribuição e informar explicitamente que deseja atribuir globalmente.

Agora eu mudo <<-para uma declaração de atribuição e podemos ver qual efeito isso tem:

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"

Portanto, nas duas vezes em que imprimimos a barra dentro do foovalor, "in foo", mesmo após a chamada baz. Isso ocorre porque assignnunca consideramos a cópia de bardentro de foo porque dissemos exatamente onde procurar. No entanto, desta vez, o valor da barra no ambiente global foi alterado porque atribuímos explicitamente lá.

Agora você também perguntou sobre a criação de variáveis ​​locais e pode fazer isso com bastante facilidade, sem criar uma função ... Só precisamos usar a localfunção.

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

2

Um pouco mais na mesma linha

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

irá imprimir "1"

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Irá imprimir "20"

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.