Rのグローバル変数とローカル変数


126

私はRの初心者であり、Rでのローカル変数とグローバル変数の使用法とはかなり混乱しています。

現在の環境で変数を使用する=<-、変数を割り当てるか、および<<-関数内でグローバル変数にアクセスできるかについて、インターネット上のいくつかの投稿を読みました。

ただし、C ++で覚えている{}ように、角かっこ内で変数を宣言するたびにローカル変数が発生するので、これはRでも同じですか?または、ローカル変数の概念があるのは、Rの関数だけです。

ブラケットだけでは不十分だと思われる小さな実験を行いましたが、何か問題が発生していますか?

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

これらの回答に加えて実行するいくつかのコード:globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env、…
同型

@isomorphismes 、Error: could not find function "%>%". それは別の割り当て形式ですか?
Aaron McDaid

1
R-helpの関連するスレッド:「<<-」演算子の意味は?
Henrik

1
@AaronMcDaidこんにちは。からrequire(magrittr)です。これは、左側(x | f1 | f2 | f3)ではなく右側()に関数を適用する方法ですf3( f2( f1( x ) ) )
同型

回答:


153

関数内で宣言された変数は、その関数に対してローカルです。例えば:

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

次のエラーが発生します:Error: object 'bar' not found

barグローバル変数を作成する場合は、次のようにする必要があります。

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

この場合bar、関数の外部からアクセスできます。

ただし、C、C ++または他の多くの言語とは異なり、ブラケットは変数のスコープを決定しません。たとえば、次のコードスニペットでは、

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

yif-elseステートメントの後もアクセス可能なままです。

よく言うように、ネストされた環境を作成することもできます。これらの使用方法を理解するには、次の2つのリンクをご覧ください。

  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

ここに小さな例があります:

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

<- 現在の環境で割り当てを行います。

関数の内部にいるとき、Rは新しい環境を作成します。デフォルトでは、作成された環境のすべてが含まれているため、これらの変数も使用できますが、新しく作成したものはグローバル環境に書き込まれません。

ほとんどの場合<<-、関数内にいる場合でも、グローバル環境にすでにある変数に割り当てたり、グローバル環境に変数を作成したりします。ただし、それほど簡単ではありません。これは、対象の名前を持つ変数の親環境をチェックします。親環境でそれが見つからない場合は、(関数が作成された時点で)親環境の親に移動し、そこを調べます。それはグローバル環境に上向きに続き、それがグローバル環境で見つからない場合、グローバル環境で変数を割り当てます。

これは何が起こっているのかを示しているかもしれません。

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"

初めてバーを印刷するときはfooまだ呼び出していないので、まだグローバルである必要があります-これは理にかなっています。2回目に印刷するときは、foo呼び出し前の内部にあるbazため、 "in foo"という値は意味があります。以下は、<<-実際に何が行われているのかを示しています。次に出力される値は、 "in baz-before <<-"ですが、printステートメントが<<-。これは、<<-が現在の環境を調べないためです(グローバル環境にいる場合<<-は、のように動作します<-)。したがってbaz、barの値の内部は「in baz-before <<-」のままです。baz内部のバーのコピーを呼び出すと、foo「in baz」に変更されますが、ご覧のとおり、グローバルbarは変更されていません。bar内部で定義されているのfooは、作成時に親環境にあるbazので、これは、表示される最初のコピー、barつまり<<-割り当てられるコピーです。つまり<<-、単にグローバル環境に直接割り当てるだけではありません。

<<-トリッキーなので、回避できる場合は使用しないことをお勧めします。本当にグローバル環境に割り当てたい場合は、関数assignを使用して、グローバルに割り当てることを明示的に伝えることができます。

ここで<<-、assignステートメントに変更すると、どのような影響があるかがわかります。

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"

したがって、どちらfooの場合も、を呼び出しbazた後でも、値の内部にあるbar は「in foo」です。これは、foo assignbar内部のコピーさえ考慮していないためです。ただし、今回は明示的に割り当てたため、グローバル環境でのbarの値が変更されました。

ここで、ローカル変数の作成についても質問しました。関数を作成しなくても、かなり簡単にローカル変数を作成できます...関数を使用するだけですlocal

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

2

同じ線に沿ってもう少し

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

「1」を出力します

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

「20」を印刷します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.