2016-08-10 5 views
1

これは、質問と密接に関連しています。How do I pass ``...`` to a new environment in R?異なる環境で評価された関数を返す副詞関数を書くにはどうすればよいですか?

スレッドhereです。

私の究極の目標は、機能していすることができることです。

  • は機能上で動作し、機能
  • を返すreturn関数は、その親
  • として.GlobalEnvで新しい環境を作成します新しい環境内の引数関数を評価します。
  • そして、以下で説明するセーブサイズの問題を解決します。

lm(およびggplotなどの他のオブジェクト)が呼び出し環境を保存してしまうことがあります。この環境には、無関係な情報が含まれることがよくあります。目標は、この問題を解決する便利なラッパーを用意することです。証明するために:

tmp_fun_Bill <- function(){ 
    iris_big <- lapply(1:10000, function(x) iris) 
    env <- new.env(parent = globalenv()) 
    with(env, lm(Sepal.Length ~ Sepal.Width, data = iris)) 
} 

out <- tmp_fun_Bill() 
object.size(out) 
# 48008 
saveSize(out) 
# 4478 - this works! 

私は機能を(のようなpurrr::safely)を返し、これらの機能の一つにビルのアプローチを一般化したいと思います:

saveSize <- function (object) { 
    tf <- tempfile(fileext = ".RData") 
    on.exit(unlink(tf)) 
    save(object, file = tf) 
    file.size(tf) 
} 

tmp_fun <- function(){ 
    iris_big <- lapply(1:10000, function(x) iris) 
    lm(Sepal.Length ~ Sepal.Width, data = iris) 
} 

out <- tmp_fun() 
object.size(out) 
# 48008 
saveSize(out) 
# 1002448 - Far too large as it contains iris_big. 

ビル・ダンラップが働くこのソリューションを提案しています。 @MrFlickからの助けを借りて

私の最高の試み、:

in_new_env <- function(.f){ 
    function(...) { 
    params <- list(...) 
    env <- new.env(parent = globalenv()) 
    # Change the environment of any formula objects 
    params <- lapply(params, function(x) {if (inherits("x","formula")) {environment(x)<-env}; x}) 
    assign(".params.", params, envir = env) 
    env$.f <- .f 
    evalq(do.call(".f", .params.), envir=env) 
    } 
} 

tmp_fun_me <- function(){ 
    iris_big <- lapply(1:10000, function(x) iris) 
    in_new_env(lm)(Sepal.Length ~ Sepal.Width, data = iris) 
} 

out <- tmp_fun_me() 
object.size(out) 
# 48008 
saveSize(out) 
# 1002448 - too big again 

は、誰かが間違ってここに何が起こっているかを指摘することはできますか?

+0

私にはタイプミスがありました。それは 'params < - lapply(params、function(x){if(inherits(x、" formula ")){環境(x)< - env}; x})'だったはずですが、問題。これは実際に式が作成される場所に来る。 – MrFlick

答えて

1

問題は実際には、数式が現在の環境を把握していることです。ここで

dropenv <- function(x) { 
    env <- new.env(parent = globalenv()) 
    if (inherits(x,"formula")) { 
     environment(x)<-env 
    } 
    x 
} 

tmp_fun_drop <- function(){ 
    iris_big <- lapply(1:10000, function(x) iris) 
    lm(dropenv(Sepal.Length ~ Sepal.Width), data = iris) 
} 

を空の環境への式のための環境を設定します機能だ。しかし、これはevaulatingとlm()機能への式引数を解析する必要があります。今in_new_envによって返される関数は、最初のパラメータは式になり、その式のための環境をクリアすることを前提としていここ

in_new_env <- function(.f){ 
    function(formula, ...) { 
    formula <- dropenv(formula) 
    .f(formula, ...) 
    } 
} 

tmp_fun_drop <- function(){ 
    iris_big <- lapply(1:10000, function(x) iris) 
    in_new_env(lm)(Sepal.Length ~ Sepal.Width, data = iris) 
} 

を呼び出して、ご希望の方法のための可能な回避策です。

関連する問題