2011-08-05 23 views
40

これは実際にRコードをデバッグする私の能力に挑戦しています。関数内でddplyでオブジェクトが見つかりません

私はddply()を使用して、連続して名前が付けられた異なる列に同じ機能を適用したいと思います。例えば。 a、b、c。これを行うには、列名を文字列として繰り返し渡し、関数が参照できるようにeval(parse(text=ColName))を使用します。私は別の答えからこのテクニックをつかんだ。

これは、別の機能の中にddply()を入れるまで、うまくいきます。ここではサンプルコードは次のとおりです。

# Required packages: 
library(plyr) 

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

a = c(1,2,3,4) 
b = c(0,0,1,1) 
c = c(5,6,7,8) 
df = data.frame(a,b,c) 
sv = c("b") 

#This works. 
ColName = "a" 
ddply(df, sv, summarize, 
     Ave = mean(eval(parse(text=ColName)), na.rm=TRUE) 
) 

#This doesn't work 
#Produces error: "Error in parse(text = NewColName) : object 'NewColName' not found" 
myFunction(df,sv) 

#Output in both cases should be 
# b Ave 
#1 0 1.5 
#2 1 3.5 

任意のアイデア? NewColNameは関数内でも定義されています!

私はこの質問の答えがloops-to-create-new-variables-in-ddplyだと思っていましたが、今日は十分な頭を叩いてしまいました。そして手を挙げて助けを求める時です。

答えて

14

ではありません。

myFunction <- function(x,y){ 
NewColName <- "a" 
z <- do.call("ddply",list(x, y, summarize, Ave = call("mean",as.symbol(NewColName),na.rm=TRUE))) 
return(z) 
} 

myFunction(d.f,sv) 
    b Ave 
1 0 1.5 
2 1 3.5 
3

環境に問題があるようです。グローバル割り当ては、問題を修正しますが、自分の魂を犠牲に:

library(plyr) 

a = c(1,2,3,4) 
b = c(0,0,1,1) 
c = c(5,6,7,8) 
d.f = data.frame(a,b,c) 
sv = c("b") 

ColName = "a" 
ddply(d.f, sv, summarize, 
     Ave = mean(eval(parse(text=ColName)), na.rm=TRUE) 
) 

myFunction <- function(x, y){ 
    NewColName <<- "a" 
    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

myFunction(x=d.f,y=sv) 

eval(1)parent.frameで募集しています。だからではなく、それが動作するはずのMyFunction外NewColNameを定義する場合:

rm(NewColName) 
NewColName <- "a" 
myFunction <- function(x, y){ 

    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 
myFunction(x=d.f,y=sv) 

以前の環境からmy.parseを引き出すためにgetを使用することにより、我々ははるかに近い来ることができるが、それでも世界のようcurenv合格する必要があります。

myFunction <- function(x, y){ 
    NewColName <- "a" 
    my.parse <- parse(text=NewColName) 
    print(my.parse) 
    curenv <<- environment() 
    print(curenv) 

    z = ddply(x, y, summarize, 
      Ave = mean(eval(get("my.parse" , envir=curenv)), na.rm=TRUE) 
    ) 
    return(z) 
} 

> myFunction(x=d.f,y=sv) 
expression(a) 
<environment: 0x0275a9b4> 
    b Ave 
1 0 1.5 
2 1 3.5 

私はddplyが、私が試したparent.frame()sys.frame()戦略のすべてが失敗した理由である、既に.GlobalEnvに評価していると思われます。

+0

私は解決策が@Hadley関数を必要とするかもしれないと思っています:-) –

+0

これらすべてを試すのに大変な努力をしました。グループヘッドバンギングは常に高く評価されています......私は自分の魂を保ちます –

9

Iがサイドステップする問題を単にsummarizeを使用しないことによって傾向がある様々な環境をナビゲートのインとアウトを占うのに十分なスマートされていない、summarizeまたはtransformか何かでddplyを組み合わせ、ときに私は時々このような問題に実行し、

明らか
myFunction <- function(x, y){ 
    NewColName <- "a" 
    z <- ddply(x, y, .fun = function(xx,col){ 
          c(Ave = mean(xx[,col],na.rm=TRUE))}, 
       NewColName) 
    return(z) 
} 

myFunction(df,sv) 

は、「手動で」このようなものをやってするコストがあり、それはしばしばddplysummarizeを組み合わせることから来るの評価の問題に対処するの頭痛を回避:代わりに、私自身の匿名関数を使用して。それはあなたがNewColNameはまだ表示されている環境での通話を構築するためにdo.callcallの組み合わせでこれを行うことができます...ハドレーは、溶液では表示されませんことを、当然のことながら、言うこと

+2

バグを修正するまで、これは私の推奨する回避策です。あなたの無名関数の中で 'transform'などを使うことができることに注意してください。 – hadley

+0

@joran私はあなたのソリューションを実装し、それは私のために働いた。私はなぜddplyでこのスコープの問題があるのか​​について好奇心旺盛でしたか?要約は新しいデータフレームを作成し、このcolNameにアクセスできないためですか? –

+0

@ user3801801これは、関数の引数で行われる非標準的な評価と関係がある。私は特定の問題を思い出させるためにソースコードに目を通す必要がありますが、基本的にはRがどこで引数を評価するかを知っています(つまり、現在のエンクロージャー、地球環境、の間に)。 – joran

4

この問題は、plyrパッケージ自体のコードにあります。要約機能には、eval(substitute(...),.data,parent.frame())という行があります。 parent.frame()はかなりファンキーで予期せぬものを行うことができることはよく知られています。 T

彼は@Jamesの解決策は非常に素晴らしい回避策です。しかし、私が覚えていれば、ハリー自身が以前に言ったように、plyrパッケージは機能内で使用するつもりはありませんでした。

申し訳ありませんが、私はここで間違っていました。しかし、現時点では、このような状況ではプライヤーパッケージが問題を引き起こすことは知られています。この質問へ

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = aggregate(x[NewColName],x[y],mean,na.rm=TRUE) 
    return(z) 
} 
> myFunction(df,sv) 
    b a 
1 0 1.5 
2 1 3.5 
+0

+1私の「要約」を解決し、問題の実際の説明を提供するため。 ;) – joran

+0

+1はparent.frame()の問題について説明する時間をとっています。関数が別の関数の中で使用できないのは、連続したコードを書く必要があるためです。たぶん@Hadleyさんがコメントできます。 –

+0

私は確かにplyrが関数内で使用されることを意図していないと主張したことはありません - 私はいつもこれは現在私が修正するための理解が不足しているバグだと言ってきました:( – hadley

22

今日のソリューションはhere(summarize)summarizeを作ることです。

したがって、私はあなたの問題のためのベース溶液を得ました。例えば

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = ddply(x, y, here(summarize), 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

here(f)

は、2012年12月に、現在のコンテキストをキャプチャplyrに追加されました。

+0

Brilliant!lubridateとplyrを一緒に使用する場合は、plyr :: here()を参照することをお勧めします(残念ながらここでは()を再定義しています)。 –

+0

詳細:https://github.com/hadley/plyr/問題/ 3 – Lennert

関連する問題