19

環境を保存するときに、理解できない動作が発生します。以下のコードは、問題を示しています。far-too-big.RData2 つのファイル ( 、およびright-size.RData) は同じサイズであり、含まれる環境が空であるため非常に小さいと 予想していました。

実際、far-too-big.RDataは と同じサイズになりbigfile.RDataます。

WinXP 5.1 SP3 で 2.14.1 と 2.15.2 を使用しても同じ結果が得られます。なぜこれが起こっているのか誰でも説明できますか?

と の両方が、新しい R セッションに読み込まれると、何も含まれていないように見えますfar-too-big.RDataright-size.RDataつまり、character(0)に応答して返されls()ます。ただし、保存を include に切り替えて結果をテキスト エディタで開くと、 にデータが含まれているascii=TRUEことがわかります。far-too-big.RDatabigfile.RData

a <- matrix(runif(1000000, 0, 1), ncol=1000)
save(a, file="bigfile.RData")
fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    save(test, file="far-too-big.RData")
    test1 <- new.env(parent=globalenv())
    save(test1, file="right-size.RData")
}
fn()
4

2 に答える 2

16

これは私の専門分野ではありませんが、環境はこのように機能すると信じています。

  • どの環境も、親環境のすべてを継承します。
  • すべての関数呼び出しは、独自の環境を作成します。

あなたの場合の上記の結果は次のとおりです。

  1. 実行するfn()と、独自のローカル環境 (緑) が作成されます。デフォルトの親はglobalenv()(灰色) です。
  2. test内に環境 (赤)を作成すると、デフォルトでの環境 (緑) になります。したがって、オブジェクトが含まれます。fn()fn()testa
  3. 環境test1(青) を作成し、その親がの環境globalenv()から分離されfn()、オブジェクトを継承しないことを明示的に述べている場合a

したがって、保存するときtestに、 object の (やや非表示の) コピーも保存しますatest1オブジェクトが含まれていないため、保存時には発生しませんa

ここに画像の説明を入力

アップデート

どうやら、これは私が信じていたよりも複雑なトピックです。@joris-maysの回答を引用しているだけかもしれませんが、最後に試してみたいと思います。

私にとって、環境の最も直感的な視覚化はツリー構造です。以下を参照してください。各ノードは環境であり、矢印はそれぞれの囲んでいる環境を指しています (親と同じであると信じたいのですが、それはフレームを処理し、世界の私のコーナーを超えています)。特定の環境は、ツリーを下に移動してアクセスできるすべてのオブジェクトを囲み、ツリーを上に移動してアクセスできるすべてのオブジェクトにアクセスできます。環境を保存すると、環境に囲まれており、環境からアクセスできるすべてのオブジェクトと環境が保存されているように見えます (ただし、 は例外ですglobalenv())。

ただし、お持ち帰りのメッセージは、Joris が既に述べたとおりです。オブジェクトをリストとして保存すれば、心配する必要はありません。

ここに画像の説明を入力

詳細を知りたい場合は、Norman Matloff の優れた本the art of R programmingをお勧めします。一次データ分析ではなく、R でのソフトウェア開発を対象としており、かなりのプログラミング経験があることを前提としています。私はまだ環境の部分を完全に消化していないことを認めなければなりませんが、本の残りの部分は非常によく書かれており、教育的であるため、これもそうであると思います.

于 2012-12-17T13:55:50.167 に答える
9

実際には、@Backlin が示すのとは逆です。親環境は、他の環境を囲む環境です。したがって、定義した場合、 を囲む環境testは のローカル環境でfnあり、 を囲む環境test1はグローバル環境です。次のようになります。

ここに画像の説明を入力

環境は、関数に渡されたときや代入で使用されたときにコピーされないという意味で、R の他のオブジェクトとは異なる動作をします。環境オブジェクト自体は、次へのポインタで内部的に構成されています。

  • フレーム (値を含むペアリスト)
  • 囲んでいる環境 (上で説明したように)
  • ハッシュ テーブル (環境がハッシュされていない場合はリストまたは NULL)

環境にポインターが含まれているという事実は、すべての違いを生みます。環境を扱うのはそれほど簡単ではなく、実際には非常にトリッキーです。以下のコードを見てください。

> test <- new.env()
> test$a <- 1
> test2 <- test
> test2$a <- 2
> test$a
[1] 2

したがって、からコピーしたのはポインターだけtestですtest2。の値を変更すると、 の値test2も変更さtestれます。(実際には、その値を一度だけ変更しますがtesttest2両方を同じフレームに向けます)。

環境を保存しようとすると、R はフレーム、ハッシュ テーブル、および囲んでいる環境の値を取得して保存するしかありません。エンクロージング環境はそれ自体が環境であるため、R はグローバル環境に到達するまで、すべてのエンクロージング環境も保存します。グローバル環境は内部コードで特別な方法で扱われるため、(幸いなことに) ファイルには保存されません。

囲んでいる環境と親フレームの違いに注意してください: 関数の定義が少し異なるとします:

a <- matrix(runif(1000000, 0, 1), ncol=1000)
save(a, file="bigfile.RData")
fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    save(test, file="far-too-big.RData")
    test1 <- new.env(parent=globalenv())
    save(test1, file="right-size.RData")
}

fn2 <- function(){
    z <- matrix(runif(1000000,0,1),ncol=1000)
    fn()
}
fn2()

現在、次の状況があります。

ここに画像の説明を入力

ファイル "far-too-big.RData" には行列 a と行列 z の両方が含まれていると思われるかもしれませんが、そうではありません。行列 a のみが含まれます。これは、 を囲む環境fnがグローバル環境であるためです。の親フレームfnの環境ですfn2が、 によって作成された環境オブジェクトfnにはグローバル環境へのポインタが含まれています。

一方、次のようにすると:

fn <- function() {
    load("bigfile.RData")
    test <- new.env()
    test$b <- a
    test2 <- new.env(parent=test)
    save(test2, file="far-too-big.RData")
}

test2は 2 つの環境 (testと の環境fun) に含まれるようになり、両方の環境もファイルに保存されます。したがって、次のような状況になります。

ここに画像の説明を入力

これに関係なく、私は個人的に環境を環境として保存することを避けています。私の意見では、環境をリストとして保存することは、99.9% のケースでより良い選択です:

fn2 <- function(){
    load("bigfile.RData")
    test <- new.env()
    test$x <- "something"
    test$fn <- ls
    testlist <- as.list(test)
    save(testlist, file="right-size.RData")
}
fn2()

環境にする必要がある場合は、ロード時に元に戻すことができます。

load("right-size.RData")
test <- as.environment(testlist)
于 2012-12-18T15:24:37.777 に答える