2012-04-24 4 views
6

コードがあり、合計経過時間は約30秒です。次のコードは約27秒です。私はこれに問題のあるコードを狭め:なぜこれが遅いのですか? (DF行のループとスタンドアロンのベクトルの比較)

d$dis300[i] <- h 

だから私は、この他の部分に変更し、現在(予想通り)本当に速い取り組んでいます。

私の質問は、これが2番目のものに対して遅すぎる理由です。 DFは7500x18の周りにあるdatosは

はまずvarsは:(27秒経過)

d$dis300 <- 0 
for (i in 1:netot) { 
    h <- aaa[d$ent[i], d$dis[i]] 
    if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", d$ent[i], d$dis[i])) 
    d$dis300[i] <- h 
} 

第二:(0.2秒経過)

d$dis300 <- 0 
for (i in 1:netot) { 
    h <- aaa[d$ent[i], d$dis[i]] 
    if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", d$ent[i], d$dis[i])) 
    foo[i] <- h 
} 
d$foo <- foo 

あなたは、両方のは、 "同じ" ですが、見ることができます問題となるのは、単一のベクトルではなく、このDFです。

コメントは本当にありがとうございます。私は別の種類の言語から来て、これは私をしばらく運転した。少なくとも私には解決策がありますが、私はこの種の問題を未然に防ぐのが好きです。

お時間をありがとう、

+0

ちょうど27sec対30秒で、2間の速度の違いを明確にするために、あなたは、この劇的なスピードアップを検討しますか? – joran

+0

@のjoranの相対的なタイミングは、正しい(ととき、彼は間違っている:-)?)した場合、あなたはこれらの習慣や技術を採用することにより、多くの良いスピードアップを取得します:http://stackoverflow.com/questions/2908822/speed -up-the-loop-in-r/8474941#8474941 –

+0

@ gsk3毎日、私の妻によると、 – joran

答えて

10

理由はd$dis300[i] <- h$<-.data.frameを呼び出すことです。

`$<-.data.frame` 

あなたはfooが何であるかを言うことはありませんが、それはアトミックベクトルである場合、$<-機能はスピードのためにCで実装されています

あなたが見ることができるように、それはかなり複雑な機能です。

それでも、私は次のようにあなたがfooを宣言願っています:

foo <- numeric(netot) 

これはあなたがループ内の各割り当てのためのベクトルを再割り当てする必要がありませんようになります:*applyを使用して

foo <- 0 # BAD! 
system.time(for(i in 1:5e4) foo[i] <- 0) # 4.40 secs 
foo <- numeric(5e4) # Pre-allocate 
system.time(for(i in 1:5e4) foo[i] <- 0) # 0.09 secs 

家族の代わりにそれについて心配しないでください:

d$foo <- vapply(1:netot, function(i, aaa, ent, dis) { 
    h <- aaa[ent[i], dis[i]] 
    if (h == 0) writeLines(sprintf("ERROR. ent:%i dis:%i", ent[i], dis[i])) 
    h 
}, numeric(1), aaa=aaa, ent=d$ent, dis=d$dis) 

...ここでも私はextループ外にあるd$entd$disも少し改善するはずです。再現性のあるデータを提供していないので、自分では実行できません。しかし、ここで同様の例です:

d <- data.frame(x=1) 
system.time(vapply(1:1e6, function(i) d$x, numeric(1)))   # 3.20 secs 
system.time(vapply(1:1e6, function(i, x) x, numeric(1), x=d$x)) # 0.56 secs 

...しかし、最終的にはそれはすべての(あなたのエラー検出コードを禁じる)に還元することができるようだ。

d$foo <- aaa[cbind(d$ent, d$dis)] 
+4

3つのインターネットは、泥棒の中に隠された1ライナーを見るためのものです。 –

+0

+10ビール(ビールと>>のインターネット) –

+0

@JoshuaUlrich - 私はダース以上の票のためにそれらを交換することができますので、私は10Kに達する; - )... – Tommy

2

トミーのが最善の答えです。これはコメントとしては大きすぎるので、答えとして追加してください...

これは(joranがコメントとして、DFの全体の)あなたがコピーを見ることができますどのように自分自身である:

> DF = data.frame(a=1:3,b=4:6) 
> tracemem(DF) 
[1] "<0x0000000003104800" 
> for (i in 1:3) {DF$b[i] <- i; .Internal(inspect(DF))} 
tracemem[0000000003104800 -> 000000000396EAD8]: 
tracemem[000000000396EAD8 -> 000000000396E4F0]: $<-.data.frame $<- 
tracemem[000000000396E4F0 -> 000000000399CDC8]: $<-.data.frame $<- 
@000000000399CDC8 19 VECSXP g0c2 [OBJ,NAM(2),TR,ATT] (len=2, tl=0) 
    @000000000399CD90 13 INTSXP g0c2 [] (len=3, tl=0) 1,2,3 
    @000000000399CCE8 13 INTSXP g0c2 [] (len=3, tl=0) 1,5,6 
ATTRIB: # .. snip .. 

tracemem[000000000399CDC8 -> 000000000399CC40]: 
tracemem[000000000399CC40 -> 000000000399CAB8]: $<-.data.frame $<- 
tracemem[000000000399CAB8 -> 000000000399C9A0]: $<-.data.frame $<- 
@000000000399C9A0 19 VECSXP g0c2 [OBJ,NAM(2),TR,ATT] (len=2, tl=0) 
    @000000000399C968 13 INTSXP g0c2 [] (len=3, tl=0) 1,2,3 
    @000000000399C888 13 INTSXP g0c2 [] (len=3, tl=0) 1,2,6 
ATTRIB: # .. snip .. 

tracemem[000000000399C9A0 -> 000000000399C7E0]: 
tracemem[000000000399C7E0 -> 000000000399C700]: $<-.data.frame $<- 
tracemem[000000000399C700 -> 00000000039C78D8]: $<-.data.frame $<- 
@00000000039C78D8 19 VECSXP g0c2 [OBJ,NAM(2),TR,ATT] (len=2, tl=0) 
    @00000000039C78A0 13 INTSXP g0c2 [] (len=3, tl=0) 1,2,3 
    @0000000003E07890 13 INTSXP g0c2 [] (len=3, tl=0) 1,2,3 
ATTRIB: # .. snip .. 
> DF 
    a b 
1 1 1 
2 2 2 
3 3 3 

それらtracemem[]ラインのそれぞれは、全体のオブジェクトのコピーに対応しています。 列ベクトルの16進アドレスは、毎回bへの代入で変更されていないにもかかわらず変わることがわかります。

私の知る限りでは、Cコードに自分自身を落とすことなく、全くメモリのないコピーでdata.frameの項目を変更する(現在は)Rの唯一の方法は、両方のパッケージdata.tableに、:=オペレータとset()関数です。ここでは:=をスタックオーバーフローで使用して参照を割り当てることについて​​があります。

しかし、あなたも、すべてのループを必要としないとして、この場合にはトミーの1つのライナーは間違いなく最高です。

+0

このレッスンはマシューです。宜しくお願いします。 – notuo

関連する問題