Variabili globali e locali in R


126

Sono un principiante per R, e sono abbastanza confuso con l'uso di variabili locali e globali in R.

Ho letto alcuni post su Internet che dicono se uso =o <-assegnerò la variabile nell'ambiente corrente e con <<-cui posso accedere a una variabile globale quando all'interno di una funzione.

Tuttavia, come ricordo in C ++, le variabili locali sorgono ogni volta che dichiari una variabile tra parentesi {}, quindi mi chiedo se questo è lo stesso per R? O è solo per le funzioni in R che abbiamo il concetto di variabili locali.

Ho fatto un piccolo esperimento, che sembra suggerire che solo le parentesi non sono sufficienti, sto sbagliando qualcosa?

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

Alcuni codici da eseguire in aggiunta a queste risposte:, globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env...
isomorfismi

@isomorphismes, Error: could not find function "%>%". È un'altra forma di incarico?
Aaron McDaid,

1
Discussione pertinente su R-help: cosa significa l'operatore "<< -"? .
Henrik,

1
@AaronMcDaid Ciao, scusa per non aver risposto prima! Questo viene da require(magrittr). È un modo per applicare le funzioni a destra ( x | f1 | f2 | f3) anziché a sinistra ( f3( f2( f1( x ) ) )).
isomorfismi

Risposte:


153

Le variabili dichiarate all'interno di una funzione sono locali per quella funzione. Per esempio:

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

ha pronunciato la seguente errore: Error: object 'bar' not found.

Se vuoi creare baruna variabile globale, dovresti fare:

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

In questo caso barè accessibile dall'esterno della funzione.

Tuttavia, a differenza di C, C ++ o di molti altri linguaggi, le parentesi non determinano l'ambito delle variabili. Ad esempio, nel seguente frammento di codice:

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

yrimane accessibile dopo la if-elsedichiarazione.

Come dici bene, puoi anche creare ambienti nidificati. Puoi dare un'occhiata a questi due link per capire come usarli:

  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

Ecco un piccolo esempio:

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

<- fa assegnazione nell'ambiente attuale.

Quando sei all'interno di una funzione, R crea un nuovo ambiente per te. Per impostazione predefinita include tutto, dall'ambiente in cui è stato creato, in modo da poter utilizzare anche quelle variabili, ma tutto ciò che si crea non verrà scritto nell'ambiente globale.

Nella maggior parte dei casi <<-assegnerai a variabili già presenti nell'ambiente globale o creerai una variabile nell'ambiente globale anche se sei all'interno di una funzione. Tuttavia, non è così semplice. Ciò che fa è controllare l'ambiente padre per una variabile con il nome di interesse. Se non lo trova nel tuo ambiente genitore, va al genitore dell'ambiente genitore (al momento della creazione della funzione) e guarda lì. Continua verso l'alto nell'ambiente globale e se non viene trovato nell'ambiente globale assegnerà la variabile nell'ambiente globale.

Questo potrebbe illustrare cosa sta succedendo.

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 prima volta che stampiamo una barra che non abbiamo ancora chiamato, fooquindi dovrebbe essere ancora globale - questo ha senso. La seconda volta che stampiamo è dentro fooprima di chiamare, bazquindi il valore "in foo" ha senso. Di seguito è dove vediamo cosa <<-sta effettivamente facendo. Il prossimo valore stampato è "in baz - prima di << -" anche se l'istruzione print viene dopo <<-. Questo perché <<-non guarda nell'ambiente attuale (a meno che tu non sia nell'ambiente globale nel qual caso si <<-comporta come <-). Quindi all'interno del bazvalore di bar rimane come "in baz - prima di << -". Una volta che chiamiamo bazla copia della barra al suo interno fooviene cambiata in "in baz" ma, come possiamo vedere, il globale barè invariato.barche è definito all'interno di fooè nell'ambiente padre quando l'abbiamo creato, bazquindi questa è la prima copia di barciò che <<-vede e quindi la copia a cui assegna. Quindi <<-non è solo l'assegnazione diretta all'ambiente globale.

<<-è complicato e non consiglierei di usarlo se puoi evitarlo. Se vuoi veramente assegnare all'ambiente globale puoi usare la funzione di assegnazione e dirlo esplicitamente che vuoi assegnare a livello globale.

Ora cambio la <<-in un'assegnazione e possiamo vedere quale effetto ha:

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"

Quindi entrambe le volte che stampiamo la barra all'interno del foovalore è "in pippo" anche dopo aver chiamato baz. Questo perché assignnon barho mai nemmeno considerato la copia di inside of foo perché gli abbiamo detto esattamente dove cercare. Tuttavia, questa volta il valore di bar nell'ambiente globale è stato modificato perché assegnato esplicitamente lì.

Ora hai anche chiesto informazioni sulla creazione di variabili locali e puoi farlo abbastanza facilmente anche senza creare una funzione ... Dobbiamo solo usare la localfunzione.

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

2

Un po 'di più sulla stessa linea

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

stamperà "1"

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Stampa "20"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.