2012-06-05 29 views
89

Jestem nowicjuszem na badania i jestem bardzo mylić z wykorzystaniem zmiennych lokalnych i globalnych w R.globalne i lokalne zmienne w R

czytałem kilka postów na temat internetu, które mówią, jeśli mogę użyć = lub <- Przydzielę zmienną w bieżącym środowisku, a dzięki <<- mogę uzyskać dostęp do zmiennej globalnej, gdy znajduje się ona wewnątrz funkcji.

Jednak, jak pamiętam, w C++ zmienne lokalne powstają za każdym razem, gdy zadeklarujesz zmienną wewnątrz nawiasów {}, więc zastanawiam się, czy to samo dla R? Czy jest to po prostu dla funkcje w R, że mamy pojęcie zmiennych lokalnych.

Zrobiłem mały eksperyment, który wydaje się sugerować, że tylko nawiasy to za mało, czy otrzymuję coś niewłaściwego?

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

Kod do uruchomienia oprócz tych odpowiedzi: 'globalenv(); globalenv()%>% parent.env; globalenv()%>% parent.env%>% parent.env', ... – isomorphismes

+0

@isomorphismes, 'Błąd: nie można znaleźć funkcji"%>% "'. Czy to inna forma przydziału? –

+1

Odpowiedni wątek na R-help: [** Co oznacza operator "<< -"? **] (http://r.789695.n4.nabble.com/What-does-the-quot-lt- lt-quot-operator-mean-td3466657.html). – Henrik

Odpowiedz

105

Zmienne zadeklarowane w funkcji są lokalne dla tej funkcji. Na przykład:

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

podaje następujący błąd: Error: object 'bar' not found.

Jeśli chcesz, aby bar zmienną globalną, należy zrobić:

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

W tym przypadku bar jest dostępny z zewnątrz funkcji.

Jednak w przeciwieństwie do C, C++ lub wielu innych języków nawiasy nie określają zakresu zmiennych. Na przykład w poniższym fragmencie kodu:

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

y pozostaje dostępny po oświadczeniu if-else.

Jak dobrze się mówi, można również tworzyć środowiska zagnieżdżone. Można spojrzeć na te dwa linki do zrozumienia w jaki sposób z nich korzystać:

  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

Tutaj masz mały przykład:

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 
+0

W twoim drugim przykładzie będziesz musiał wywołać funkcję foo() przed próbą uzyskania dostępu do paska. Ale "<< -" nie jest tak proste, jak poprowadzisz OP do uwierzenia. – Dason

+0

@Dason rzeczywiście :) Zapomniałem połączenia do funkcji ... – betabandido

+0

Zmodyfikowałem mój komentarz, aby było jasne, co mam na myśli. – Dason

99

<- robi zadanie w obecnym środowisku.

Gdy znajdujesz się w funkcji R tworzy dla ciebie nowe środowisko. Domyślnie zawiera wszystko ze środowiska, w którym został utworzony, więc możesz używać tych zmiennych, ale wszystko, co stworzysz, nie zostanie zapisane w środowisku globalnym.

W większości przypadków <<- przypisze zmienne znajdujące się już w środowisku globalnym lub utworzy zmienną w środowisku globalnym, nawet jeśli znajdujesz się w funkcji. Jednak nie jest to aż tak proste. To, co robi, sprawdza środowisko nadrzędne dla zmiennej o nazwie zainteresowania. Jeśli nie znajduje się w środowisku macierzystym, przechodzi do rodzica środowiska macierzystego (w momencie utworzenia funkcji) i tam się znajduje.Ciągnie się w górę do globalnego środowiska i jeśli nie zostanie znalezione w środowisku globalnym, przydzieli zmienną w środowisku globalnym.

To może zilustrować, co się dzieje.

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" 

Pierwszy raz wydrukować poprzeczkę nie nazwali foo jeszcze tak powinno być nadal globalny - to ma sens. Drugi raz wydrukujemy go wewnątrz foo przed wywołaniem baz, więc wartość "w foo" ma sens. Poniżej znajduje się, co widzimy, co faktycznie robi <<-. Następna drukowana wartość to "in baz - before < < -" nawet jeśli instrukcja print pochodzi od <<-. Dzieje się tak, ponieważ <<- nie wygląda w bieżącym środowisku (chyba że znajdujesz się w środowisku globalnym, w którym to przypadku <<- działa tak jak <-). Więc wewnątrz baz wartość paska pozostaje jako "w baz - przed < < -". Po wywołaniu baz kopia paska wewnątrz foo zostaje zmieniona na "w bazie", ale jak widać globalna bar pozostaje niezmieniona. Dzieje się tak dlatego, że kopia bar zdefiniowana wewnątrz foo znajduje się w środowisku nadrzędnym, gdy utworzyliśmy baz, więc jest to pierwsza kopia bar, którą widzi <<-, a tym samym kopia, do której przydzieli. Tak więc <<- nie jest bezpośrednio przypisywane do środowiska globalnego.

<<- jest skomplikowany i nie polecałbym go używać, jeśli można tego uniknąć. Jeśli naprawdę chcesz przypisać do środowiska globalnego, możesz użyć funkcji przypisania i wyraźnie powiedzieć, że chcesz ją przypisać globalnie.

Teraz mogę zmienić <<- do przypisać oświadczenia i możemy zobaczyć, jaki efekt, który ma:

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" 

Więc oba razy drukujemy bar wewnątrz foo wartość jest „w foo”, nawet po wywołaniu baz. To dlatego, że assign nigdy nie brała pod uwagę kopii bar wewnątrz foo, ponieważ powiedzieliśmy mu dokładnie, gdzie szukać. Jednak tym razem wartość słupka w środowisku globalnym została zmieniona, ponieważ została tam wyraźnie przypisana.

Teraz zapytałeś także o tworzenie zmiennych lokalnych i możesz to zrobić całkiem łatwo bez tworzenia funkcji ... Musimy tylko użyć funkcji local.

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