2009-07-23 17 views
7

मान लीजिए मैं का उपयोग कर अनुकरण कैसा प्रदर्शन करते हैं function निम्नलिखित:आर में बड़े लूप लटका?

fn1 <- function(N) { 
    res <- c() 
    for (i in 1:N) { 
    x <- rnorm(2) 
    res <- c(res, x[2]-x[1]) 
    } 
    res 
} 

बहुत बड़ी N के लिए, गणना लटका दिखाई देता है। क्या ऐसा करने के बेहतर तरीके हैं?

(से प्रेरित होकर: https://stat.ethz.ch/pipermail/r-help/2008-February/155591.html)

उत्तर

2

आर में छोरों के लिए बेहद धीमी गति से कर रहे हैं, लेकिन यहाँ एक और मुद्दा है। परिणाम वेक्टर, res को प्रीलोकेट करना बहुत तेज है, बल्कि प्रत्येक पुनरावृत्ति पर res को जोड़ने के लिए।

नीचे हम उपरोक्त संस्करण की गति को एक ऐसे संस्करण के साथ तुलना कर सकते हैं जो बस एक वेक्टर, res, लंबाई एन के साथ शुरू होता है और लूप के दौरान ith तत्व को बदलता है।

fn1 <- function(N) { 
    res <- c() 
    for (i in 1:N) { 
    x <- rnorm(2) 
    res <- c(res,x[2]-x[1]) 
    } 
    res 
} 
fn2 <- function(N) { 
    res <- rep(0,N) 
    for (i in 1:N) { 
    x <- rnorm(2) 
    res[i] <- x[2]-x[1] 
    } 
    res 
} 
> N <- 50000 
> system.time(res1 <- fn1(N)) 
    user system elapsed 
    6.568 0.256 6.826 
> system.time(res2 <- fn2(N)) 
    user system elapsed 
    0.452 0.004 0.496 

इसके अलावा, Sharpie points out के रूप में, हम इस थोड़ा तेज apply (या उसके रिश्तेदारों, sapply और lapply) की तरह आर कार्यों का उपयोग करके कर सकते हैं।

fn3 <- function(N) { 
    sapply(1:N, function(i){ x <- rnorm(2); return(x[2] - x[1]) }) 
} 
> system.time(res3 <- fn3(N)) 
    user system elapsed 
    0.397 0.004 0.397 
+0

उस आर सूची धागे में दूसरे उत्तर में क्या गलत है: res <- rnorm (10^6) -रनोर्म (10^6)? – ars

+0

@ars: आप बिल्कुल सही हैं - यह सबसे तेज़ समाधान देता है (परिमाण के क्रम से)। सबसे अच्छी सलाह होगी 1. उन कार्यों का उपयोग करें जो स्वाभाविक रूप से वैक्टरों पर काम करते हैं (जैसे आरएनओआर करता है); 2. उसमें विफल होने पर, * लागू फ़ंक्शन का उपयोग करें; 3. उसमें विफल होना, प्रीलोकेशन के साथ लूप के लिए उपयोग करें। –

9

छोरों की दक्षता लागू कार्य करता है जो अनिवार्य रूप से उन के माध्यम से पाशन से एक बार नहीं बल्कि कम से डेटा के पूरे वैक्टर की प्रक्रिया के उपयोग के माध्यम आर में काफी बढ़ाया जा सकता है।

# A vector of two random numbers is generated 
x <- rnorm(2) 

# The difference between those numbers is calculated 
x[2] - x[1] 

इस मामले उचित समारोह sapply() होगा में: पाश ऊपर दिखाए गए के लिए, वहाँ दो बुनियादी आपरेशन प्रत्येक यात्रा के दौरान हो रहा है। sapply() इस तरह के पाश बयान 1:N द्वारा उत्पन्न वेक्टर के रूप में वस्तुओं, की एक सूची पर चल रही है और परिणाम का एक वेक्टर रिटर्न:

sapply(1:N, function(i){ x <- rnorm(2); return(x[2] - x[1]) }) 

ध्यान दें कि सूचकांक मूल्य i समारोह कॉल के दौरान उपलब्ध है और क्रमिक मूल्यों पर ले जाता है 1 और N के बीच, हालांकि इस मामले में इसकी आवश्यकता नहीं है।

पहचानने जहां applyfor से अधिक इस्तेमाल किया जा सकता एक बहुत ही मूल्यवान समानांतर गणना के लिए कई अनुसंधान पुस्तकालयों apply कार्यों के माध्यम से प्लग-एंड-प्ले में चलाना प्रदान कुशलता-है की आदत में हो रही है। apply का उपयोग अक्सर शून्य कोड के पुन: प्रयोजन के साथ मल्टीकोर सिस्टम पर महत्वपूर्ण प्रदर्शन वृद्धि तक पहुंच की अनुमति दे सकता है।

2

कभी-कभी लूप की आवश्यकता नहीं होती है।

res <- rnorm(N)-rnorm(N) 
4

chris_dubois के जवाब देने के लिए मेरी टिप्पणी पर विस्तार, यहाँ है: चूंकि rnorm आईआईडी नमूना (सैद्धांतिक) देता है, तो आप एक ही परिणाम (नमूना X-Y जहां एक्स और वाई एन (0,1) कर रहे हैं) करने से प्राप्त होगा कुछ समय जानकारी: कि एक ही जवाब से fn3 साथ

> system.time(res <- rnorm(50000) - rnorm(50000)) 
user system elapsed 
0.06 0.00 0.06 

कंट्रास्ट इस:

> system.time(res3 <- fn3(50000)) 
user system elapsed 
1.33 0.01 1.36 

पहली बात यह है कि सूचना के लिए मेरी गोद है शीर्ष chris_dubois की मशीन से धीमा है।:)

दूसरा, और अधिक महत्वपूर्ण बात यह है कि यहां पर लागू वेक्टर दृष्टिकोण, तीव्रता का क्रम है। (रिची कपास ने एक ही जवाब में टिप्पणी में भी बताया)।

यह मैं अंतिम बात करने के लिए लाता है: यह एक मिथक है कि apply और उसके दोस्तों को बहुत तेजी से आर में for छोरों वे उसी क्रम सबसे मापन में मैंने देखा है पर हैं की तुलना में कर रहे हैं। क्योंकि वे दृश्यों के पीछे for लूप हैं। यह भी देखें इस पोस्ट:

http://yusung.blogspot.com/2008/04/speed-issue-in-r-computing-apply-vs.html

प्रोफेसर ब्रायन रिप्ले के अनुसार, "लागू() सिर्फ एक पाश के लिए एक आवरण है।" आवेदन() का उपयोग करने का एकमात्र लाभ यह है कि यह आपके कोड को साफ करता है!

बिल्कुल। आपको apply का उपयोग करना चाहिए यदि यह अभिव्यक्तिपूर्ण है, खासकर यदि आप एक कार्यात्मक शैली में प्रोग्रामिंग कर रहे हैं। ऐसा नहीं है क्योंकि यह तेज़ है।

+0

अच्छा अंक। इस सवाल के लिए मेरा मूल इरादा इस विचार को हाइलाइट करना था कि प्रीलोकेशन एक अच्छी बात हो सकती है। जैसा कि आपने बताया है, यह विशेष उदाहरण केवल वेक्टर परिचालनों के साथ आसानी से किया जा सकता है। कुछ अन्य उदाहरण होना अच्छा लगेगा जहां लोग आर कोड को अनुकूलित करने के विकल्प दिखाते हैं (जैसे http://wiki.r-project.org/rwiki/doku.php?id=tips:programming:code_optim2&s=optimization)। विचार? –

+0

अरे, यह एक अच्छा विचार है - मैं उस विकी के बारे में अनजान हूं। मुझे पता है कि मैं दूसरों द्वारा लिखे गए कोड को पढ़कर वेक्टर ऑप्टिमाइज़ेशन के लिए दो लूप में आया हूं - हाल ही में वेरोगर्टी द्वारा कुछ प्रोग्रामों को बनाने के लिए कुछ कोड देख रहे हैं। मुझे लगता है कि यह सामान्य ज्ञान है और दूसरों के लिए उल्लेखनीय नहीं है, लेकिन इसे दस्तावेज करने के पक्ष में गलती करना बेहतर है। मैं अपनी फाइलों के माध्यम से जाऊंगा और विकी में जोड़ने के लिए कुछ विशिष्ट खोजूंगा, उम्मीद है कि इस सप्ताह के अंत तक। क्या आपके पास संरचना बनाने के बारे में कोई विचार है? क्या हमें सिर्फ "वेक्टरिंग टिप्स" पृष्ठ बनाना चाहिए और इसे आवश्यकतानुसार तोड़ना चाहिए? – ars

+1

'लागू' फॉर-लूप के रूप में तेज़ हो सकता है, लेकिन 'लापली' और (विशेष रूप से) 'vapply' आमतौर पर तेज़ होते हैं क्योंकि उन्हें सी में कार्यान्वित किया जाता है और फ़ंक्शन' FUN' को कॉल करने का अनुकूलन किया जाता है। लेकिन यह केवल तभी महत्वपूर्ण होता है जब 'FUN' में व्यतीत वास्तविक समय छोटा होता है। – Tommy

0

हो सकता है कि अपने कार्य के लिए सबसे कारगर प्रतिस्थापन बस होगा:

fn <- function(n) rnorm(N,0,sqrt(2)) 

जो दोगुनी गति से है आईआईडी सामान्य variates के अंतर लेने के रूप में। अधिक आम तौर पर, यदि आपका लक्ष्य सरल सिमुलेशन को चलाने के लिए है, तो वेक्टर/सरणी प्रीलोकेशन और मूल कार्यों के लिए कॉल प्रक्रिया को तेज़ी से बढ़ाते हैं।

यदि आप सांख्यिकीय अनुमानों (उदाहरण के लिए, एमसीएमसी) के लिए मोंटे कार्लो सिमुलेशन करना चाहते हैं, तो आर में कई मूल पैकेज हैं। सामान्य स्टोकास्टिक सिमुलेशन के लिए, मुझे आर पैकेज के बारे में पता नहीं है लेकिन आप सिम्पी (http://simpy.sourceforge.net/) को आजमा सकते हैं, जो कि उत्कृष्ट है।

संबंधित मुद्दे