2012-04-24 16 views
6

Bir kod parçam var ve toplam geçen süre yaklaşık 30 saniyedir, aşağıdaki kod 27 saniyedir.Bu neden bu kadar yavaş? (bir DF satırında tek başına bir vektörle döngü)

d$dis300[i] <- h 

yüzden bu diğer parçasına değiştirmek ve şimdi gerçekten hızlı (beklendiği gibi) çalışıyor: Ben buna teşkil eden kodu daralmış.

Sorum şu ki, bu neden ikinciye karşı çok yavaş. DF 7500x18 etrafında datos

İlk vars: (27 sn geçen)

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 
} 

İkincisi: (0.2 sn geçen)

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 

Sen hem "aynı" ama görebilirsiniz Birinin kırılması tek bir vektör yerine bu DF'ye sahip.

Herhangi bir yorum gerçekten takdir edilmektedir. Başka bir dil türünden geldim ve bu bir süreliğine beni deli ediyordu. En azından bir çözümüm var ama gelecekte bu tür sorunları önlemeyi seviyorum.

Zaman ayırdığınız için teşekkürler,

+0

Sadece açıklamak gerekirse, ikisi arasındaki hız farkı 30sec vs 27sec, ve bunun çarpıcı bir hız olduğunu düşünüyor musunuz? – joran

+0

@ Joran göreceli zamanlamaları doğru (ve ne zaman o yanlış olduğunu :-)?), Bu alışkanlıkları ve teknikleri benimseyerek çok daha iyi hız-up döneriz: http://stackoverflow.com/questions/2908822/speed -up-the-döngü-işlem-in-r/8474941 # 8474941 –

+0

@ gsk3 Günlük, karıma göre. – joran

cevap

10

nedeni d$dis300[i] <- h$<-.data.frame çağırır olmasıdır.

`$<-.data.frame` 

Sen foo ne demiyorum, ama atom vektör ise, $<- fonksiyon hızı için C uygulanır:

Gördüğünüz gibi oldukça karmaşık fonksiyon.

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 

*apply kullanma:

foo <- numeric(netot) 

Bu döngü içinde her bir ödev vektör yeniden tahsis gerekmez sağlayacaktır: Hala

, ben aşağıdaki gibi foo beyan umut Bunun yerine aileniz bunun için endişelenmeyin:

... burada da ext Döngünün dışında bir şeyler geliştiren d$ent ve d$dis iletildi. Tekrarlanabilir veriler vermediğinden, bunu kendim yürütemiyorum. Ama burada da benzer bir örnek:

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 

... ama nihayet hepsi (sizin hata algılama kodunu engelleme) indirgenebilir görünüyor:

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

+3 Morass'ta gizli olan tek lineli görmek için internets. –

+0

+10 bira (ve biralar >> internets) –

+0

@JoshuaUlrich - Onları bir düzine daha fazla oy kullanabilir miyim, böylece 10k'a ulaşırım; -) ... – Tommy

2

Tommy en iyi cevaptır. Bu yorum için çok büyüktü, bu yüzden cevap olarak ekledi ...

Bu (Joran yorumladı olarak, DF tamamının) kendiniz kopyalarını görebilirsiniz nasıl:

> 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 

bu tracemem[] hatlarının her biri

bütün nesnenin bir kopyasını karşılık gelir. değil b için atama yoluyla modifed rağmen Sen de her seferinde değişen a sütun vektörü altıgen adreslerini görebilirsiniz.

AFAIK, C kodu kendiniz içine düşürmeden, R tek yol (şu anda) hiç bir bellek hiçbir kopyasıyla birlikte bir data.frame bir öğeyi değiştirmeye olduğunu := operatörü ve set() fonksiyon, hem pakette data.table içinde. Yığın Taşması Üzerine := kullanarak referans ile atama hakkında 17 questions vardır.

Fakat bu durumda Tommy'nin bir astarı kesinlikle en iyisi, çünkü bir döngüye bile ihtiyacınız yok.

+0

Bu ders için teşekkürler Matthew. Saygılarımla. – notuo

İlgili konular