“Çok çekirdekli” kullanmak için R komut dosyamı nasıl optimize edebilirim?


15

4 CPU'lu bir Ubuntu-Lucid PC'de GNU R kullanıyorum. 4 CPU'nun tümünü kullanmak için "r-cran-multicore" paketini kurdum. Paketin el kitabında anladığım pratik örnekler bulunmadığından, 4 CPU'nun tamamını kullanmak için komut dosyamı nasıl optimize edeceğime dair tavsiyeye ihtiyacım var.

Veri setim, 50.000 satır ve 1600 sütun içeren bir data.frame (P1 olarak adlandırılır). Her satır için, maximun, sum ve mean'ı hesaplamak istiyorum. Betiğim aşağıdaki gibi görünüyor:

p1max <- 0
p1mean <- 0
p1sum <-0
plength <- length(P1[,1])
for(i in 1:plength){
   p1max <- c(p1max, max(P1[i,]))
   p1mean <- c(p1mean, mean(P1[i,]))
   p1sum <- c(p1sum, sum(P1[i,]))
}

Herkes bana 4 CPU kullanmak için komut dosyasını değiştirmek ve çalıştırmak için söyleyebilir misiniz?


Yukarıdaki programda bir hata var: satır "için (i 1'de: tam)" olmalıdır
Simon Byrne

haklısın, teşekkürler!
Produnis

1
bu StackOverflow'a ait değil mi?
R_Coholic

1
Bu StackOverflow'a ait. Burada hiç istatistik sorusu yok. Sadece genel bir programlama sorusu.
JD Long

Yanıtlar:


11

Foreach ve doMC kullanın . Ayrıntılı açıklama burada bulunabilir . Senaryonuz çok az değişecek, satır

for(i in 1:plength){

olarak değiştirilmeli

foreach(i=1:plength) %dopar% { 

Bu paketleri kullanan çoklu görev komut dosyalarının önkoşulları

library(foreach)
library(doMC)
registerDoMC()

Dikkat notu. Belgelere göre bunu GUI'de kullanamazsınız.

Sorununuza gelince, gerçekten çoklu görevlere mi ihtiyacınız var? Veri çerçeveniz yaklaşık 1,2 GB RAM alır, bu nedenle belleğinize sığmalıdır. Uygula'yı kullanabilirsiniz:

p1smry <- apply(P1,1,summary)

Sonuç, her satırın özetini içeren bir matris olacaktır.

Ayrıca işlevi kullanabilirsiniz çekirdekli pakette bulunan mclapply . Sonra komut dosyanız şöyle görünebilir:

loopfun <- function(i) {
     summary(P1[i,])
}

res <- mclapply(1:nrow(P1),loopfun)

Bu, i-th öğesinin i-th satırının özeti olacağı listeyi döndürür. Sapply kullanarak matrise dönüştürebilirsiniz

mres <- sapply(res,function(x)x)

çok teşekkür ederim. Haklısın, "uygula" ile script optimize edilebilir. Mesajımı almak için senaryomu minimal örnek olarak kullandım ... Teşekkürler, cevabınız tam olarak aradığım şeydi !!
Produnis

15

Birden fazla çekirdeğin nasıl kullanılacağına dair zaten bir cevabınız var, ancak asıl sorun döngülerinizi yazma şekliniz. Sonuç vektörünüzü / nesnenizi bir döngünün her yinelemesinde asla uzatmayın . Bunu yaparsanız, R'yi sonuç vektörünüzü / nesneyi kopyalamaya ve her şeyin zaman alacağı şekilde genişletmeye zorlarsınız. Bunun yerine, döngüye başlamadan önce yeterli depolama alanını önceden konumlandırın ve ilerledikçe doldurun. İşte bir örnek:

set.seed(1)
p1 <- matrix(rnorm(10000), ncol=100)
system.time({
p1max <- p1mean <- p1sum <- numeric(length = 100)
for(i in seq_along(p1max)){
   p1max[i] <- max(p1[i,])
   p1mean[i] <- mean(p1[i,])
   p1sum[i ]<- sum(p1[i,])
}
})

   user  system elapsed 
  0.005   0.000   0.005

Veya bunları şu yollarla yapabilirsiniz apply():

system.time({
p1max2 <- apply(p1, 1, max)
p1mean2 <- apply(p1, 1, mean)
p1sum2 <- apply(p1, 1, sum)
})
   user  system elapsed 
  0.007   0.000   0.006 

Ama bunun hiçbir hızlı düzgün ve bazen yavaş döngü işini halletmek.

Bununla birlikte, her zaman vectorized kod arayışında olun. Sen kullanarak satır toplamlarını ve araçları yapabilir rowSums()ve rowMeans()daha hızlı döngü veya ikisinden de hangi applysürümleri:

system.time({
p1max3 <- apply(p1, 1, max)
p1mean3 <- rowMeans(p1)
p1sum3 <- rowSums(p1)
})

   user  system elapsed 
  0.001   0.000   0.002 

Bahis yapan bir adam olsaydım, dövmekten bahsettiğim üçüncü yaklaşıma param olurdu foreach() , matrisinizdeki bir hız testinde veya diğer çok çekirdekli seçeneklerden çünkü farklı işlemcilerin çekirdeğini oluşturan ayrı işlemler.

Güncelleme: @shabbychef'in yorumunu takiben, toplamları bir kez yapmak ve ortalamanın hesaplanmasında tekrar kullanmak daha hızlı mı?

system.time({
    p1max4 <- apply(p1, 1, max)
    p1sum4 <- rowSums(p1)
    p1mean4 <- p1sum4 / ncol(p1)
    })

   user  system elapsed 
  0.002   0.000   0.002

Bu test çalışmasında değil, ama bu kapsamlı olmaktan uzak ...


FWIW, Matlab, önceden konumlandırma ve vektörleri genişletme ile ilgili aynı sorunlara sahip ve klasik bir 'blooper' kodudur. Bahsinize ek olarak rowSums, satır araçlarını hesaplamak için sonuçlarını kullanmak daha hızlıdır ( örneğin, Na veya NaN ile ilgili bir şey eksik olmadıkça ). Üçüncü yaklaşımınızdaki kod, her sütunu iki kez toplar .
shabbychef

@shabbychef şaşıracaksınız (düzenlenen cevabıma bakın). Evet toplamlar kavramsal iki kez hesaplanır ancak rowSumsve rowMeansyüksek derlenmiş kodu ve ne sadece bir kez toplamları hesaplarken kazanç optimize edilmiştir, biz yorumlanır kodda ortalama hesaplama yaparken yine kaybederler.
Monica'yı eski durumuna getirin. G. Simpson

@Gavin Simpson: o kadar hızlı değil: yerine system.time({ for (iii in c(1:1000)) { p1max3 <- apply(p1, 1, max) p1mean3 <- rowMeans(p1) p1sum3 <- rowSums(p1) } })ve benzer şekilde deneyin system.time({ for (iii in c(1:1000)) { p1max4 <- apply(p1, 1, max) p1sum4 <- rowSums(p1) p1mean4 <- p1sum4 / ncol(p1) } }); toplamı yeniden hesaplamayan sürüm bilgisayarımda 1.368 saniye sürüyor; 1.396 alır. yine, kapsamlı olmaktan uzak, ama daha zorlayıcı ...
shabbychef

@shabbychef zorlayıcı olan ya da olmayan şey hakkında farklı fikirlere sahip olmalıyız ;-) Aslında, daha titiz simülasyonlarınız benim ana noktamı güçlendiriyor , verimli ve optimize edilmiş derlenmiş kodda uygulanması rowMeansve yenilmesi rowSumszor olacaklar.
Monica'yı eski durumuna getirin. G. Simpson

@Gavin Simpson. Aslında, örneğimle ilgili sorun, çoğu zaman maksimum kısmı hesaplamak için uygulama bölümünde alınmış olmasıdır. Gibi c tabanlı vektörize bir fonksiyonun rowMean, genel amaçlı bir R aracıyla yenilmesi zor olacağını kabul ediyorum *apply. Ancak, bunun 10000 sayılarını toplamak için daha hızlı olduğunu göstermektedir görünüyor iki kez aracılığı rowMeanile rowSumyerine sadece bir kez ve kullanım R'ın yerleşik bölümü operatörü daha. R'nin bazı verimlilik sorunları olduğunu biliyorum ( örneğin , kıvırcık parantezlerin parantez konusuna karşı son keşfi), ancak bu çılgınca görünüyor.
shabbychef

1

Göz at kar ve kar yağışı paketlerine . Bunlarla birçok örnek ...

R ve paralellik hakkında bilgi edinmek yerine bu kodu hızlandırmak istiyorsanız, bunu yapmalısınız.

P1 = matrix(rnorm(1000), ncol=10, nrow=10
apply(P1, 1, max)
apply(P1, 1, mean)
apply(P1, 1, sum)

Lütfen
senaryomu

2
Bunlar sadece döngüyü senden saklıyor. @Produnis koduyla ilgili asıl sorun, sonuç vektörleri döngünün her yinelemesinde genişletildiği için zorunlu kopyalamanın devam etmesidir.
Monica'yı eski durumuna getirin. G. Simpson

kar yağışı paketi "kek" demek gibi Gavin çözümünü genişletebilirsiniz. Paket, çoklu kodlama yapmak için değiştirilmiş çok sayıda uygulama işlevine sahiptir. Uygula işlevi için, sfApply kullanırsınız (<uygulandığı gibi tablolar>). Kar yağışı da iyi belgelenmiştir. Bunu çok çekirdekli bir işlemcide gerçekleştirmek için ekstra bir yazılıma gerek olmadığını belirtmeliyim. SfLapply örneği için stackoverflow.com/questions/4164960/… adresine bakın .
Roman Luštrik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.