2010-04-13 10 views
96

मैंने अभी scoping in the R intro पढ़ना समाप्त कर दिया है, और <<- असाइनमेंट के बारे में बहुत उत्सुक हूं।आर में आप "<< -" (स्कॉइंग असाइनमेंट) का उपयोग कैसे करते हैं?

मैनुअल ने <<- के लिए एक (बहुत रोचक) उदाहरण दिखाया, जिसे मैं समझता हूं। जो भी मैं अभी भी लापता हूं वह यह संदर्भ है कि यह उपयोगी हो सकता है।

तो <<- का उपयोग दिलचस्प/उपयोगी हो सकता है, तो मुझे आपके द्वारा पढ़ना अच्छा लगेगा उदाहरण के लिए उदाहरण (या उदाहरणों के लिंक)। इसका उपयोग करने के खतरे क्या हो सकते हैं (यह ट्रैक को ढीला करना आसान लगता है), और साझा करने जैसे किसी भी सुझाव को आप महसूस कर सकते हैं।

उत्तर

139

<<- राज्य को बनाए रखने के बंद होने के साथ संयोजन में सबसे उपयोगी है। यहां मेरे हाल के एक पेपर से एक अनुभाग दिया गया है:

एक बंद करना किसी अन्य फ़ंक्शन द्वारा लिखित एक फ़ंक्शन है।क्लोजर को इसलिए कहा जाता है क्योंकि पैरेंट फ़ंक्शन का वातावरण संलग्न करता है, और उस फ़ंक्शन में सभी चर और पैरामीटर तक पहुंच सकता है। यह उपयोगी है क्योंकि यह हमें पैरामीटर के दो स्तरों की अनुमति देता है। पैरामीटर का एक स्तर (अभिभावक) यह नियंत्रित करता है कि फ़ंक्शन कैसे काम करता है। दूसरा स्तर (बच्चा) काम करता है। निम्नलिखित उदाहरण दिखाता है कि इस विचार का उपयोग बिजली कार्यों के परिवार को उत्पन्न करने के लिए कैसे किया जा सकता है। अभिभावक फ़ंक्शन (power) बाल कार्यों (square और cube) बनाता है जो वास्तव में कड़ी मेहनत करते हैं।

power <- function(exponent) { 
    function(x) x^exponent 
} 

square <- power(2) 
square(2) # -> [1] 4 
square(4) # -> [1] 16 

cube <- power(3) 
cube(2) # -> [1] 8 
cube(4) # -> [1] 64 

दो स्तरों पर चर प्रबंधित करने की क्षमता भी यह संभव एक समारोह उसकी पेरेंट वातावरण में चर को संशोधित करने की अनुमति देकर समारोह आमंत्रण भर में राज्य बनाए रखने के लिए बनाता है। विभिन्न स्तरों पर चर का प्रबंधन करने की कुंजी डबल तीर असाइनमेंट ऑपरेटर <<- है। सामान्य एकल तीर असाइनमेंट (<-) के विपरीत जो हमेशा मौजूदा स्तर पर काम करता है, डबल तीर ऑपरेटर पैरेंट स्तरों में चर को संशोधित कर सकता है।

इससे काउंटर को बनाए रखना संभव हो जाता है जो रिकॉर्ड करता है कि फ़ंक्शन को कितनी बार बुलाया गया है, जैसा कि निम्न उदाहरण दिखाता है। प्रत्येक बार new_counter चलाया जाता है, यह वातावरण बनाता है, इस वातावरण में काउंटर i प्रारंभ करता है, और उसके बाद एक नया फ़ंक्शन बनाता है।

new_counter <- function() { 
    i <- 0 
    function() { 
    # do something useful, then ... 
    i <<- i + 1 
    i 
    } 
} 

नया कार्य एक बंद है, और इसका पर्यावरण संलग्न वातावरण है। जब बंद counter_one और counter_two चलाए जाते हैं, तो प्रत्येक काउंटर को अपने संलग्न वातावरण में संशोधित करता है और फिर वर्तमान गणना देता है।

counter_one <- new_counter() 
counter_two <- new_counter() 

counter_one() # -> [1] 1 
counter_one() # -> [1] 2 
counter_two() # -> [1] 1 
+2

अरे यह Rosettacode (http://rosettacode.org/wiki/Accumulator_factory#R) पर एक अनसुलझा आर कार्य है, ठीक है, यह था ... –

+0

क्या कोई आवश्यकता होगी एक पैरेंट फ़ंक्शन में 1 से अधिक बंद संलग्न करें? मैंने अभी एक स्निपेट की कोशिश की, ऐसा लगता है कि केवल अंतिम बंद करने का निष्पादन किया गया था ... –

5

एक जगह जहां मैंने <<- का उपयोग किया था, टीसीएल/टीके का उपयोग करके सरल जीयूआई में था। शुरुआती उदाहरणों में से कुछ में यह है - क्योंकि आपको राज्य के लिए स्थानीय और वैश्विक चर के बीच अंतर बनाने की आवश्यकता है। उदाहरण के लिए देखें

library(tcltk) 
demo(tkdensity) 

जो <<- का उपयोग करता है। अन्यथा मैं मरेक के साथ सहमत हूं :) - एक Google खोज मदद कर सकती है।

5
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())} 
plot(f(1000,0),typ="l") 
+7

यह _not_ का उपयोग करने के लिए _not_ का एक अच्छा उदाहरण है <<< '। इस मामले में लूप के लिए एक स्पष्ट होगा। – hadley

25

यह (यदि आप TRUE है कि समारोह में inherits पैरामीटर सेट) assign के बराबर के रूप <<- के बारे में सोच में मदद करता है। assign का लाभ यह है कि यह आपको अधिक पैरामीटर (उदा। पर्यावरण) निर्दिष्ट करने की अनुमति देता है, इसलिए मैं ज्यादातर मामलों में से assign का उपयोग करना पसंद करता हूं।

<<- और assign(x, value, inherits=TRUE) का उपयोग करना मतलब है कि "आपूर्ति किए गए पर्यावरण के वातावरण को तब तक खोजा जाता है जब तक वेरिएबल 'x' का सामना नहीं होता है।" दूसरे शब्दों में, यह वातावरण के माध्यम से तब तक जारी रहेगा जब तक कि वह उस नाम के साथ एक चर नहीं पाता, और यह उसे असाइन करेगा। यह किसी फ़ंक्शन के दायरे में या वैश्विक वातावरण में हो सकता है।

यह समझने के लिए कि ये कार्य क्या करते हैं, आपको आर वातावरण को भी समझना होगा (उदाहरण के लिए search का उपयोग करना)।

मैं नियमित रूप से इन कार्यों का उपयोग करता हूं जब मैं एक बड़ा सिमुलेशन चला रहा हूं और मैं मध्यवर्ती परिणामों को सहेजना चाहता हूं। यह आपको दिए गए फ़ंक्शन या apply लूप के दायरे से बाहर ऑब्जेक्ट बनाने की अनुमति देता है। यह बहुत उपयोगी है, विशेष रूप से यदि आपको अप्रत्याशित रूप से समाप्त होने वाले बड़े लूप के बारे में कोई चिंता है (उदा। डेटाबेस डिस्कनेक्शन), इस स्थिति में आप प्रक्रिया में सबकुछ खो सकते हैं। यह लंबे समय तक चलने वाली प्रक्रिया के दौरान डेटाबेस या फ़ाइल में आपके परिणामों को लिखने के बराबर होगा, सिवाय इसके कि यह इसके बजाय आर पर्यावरण के भीतर परिणाम संग्रहीत कर रहा है।

इसके साथ मेरी प्राथमिक चेतावनी: सावधान रहें क्योंकि अब आप वैश्विक चर के साथ काम कर रहे हैं, खासकर <<- का उपयोग करते समय। इसका अर्थ यह है कि आप उन परिस्थितियों के साथ समाप्त हो सकते हैं जहां एक फ़ंक्शन पर्यावरण से किसी ऑब्जेक्ट वैल्यू का उपयोग कर रहा है, जब आप उम्मीद करते हैं कि यह पैरामीटर के रूप में आपूर्ति की जा रही है। यह मुख्य चीजों में से एक है कि कार्यात्मक प्रोग्रामिंग से बचने की कोशिश करता है (देखें side effects)। मैं अपने मानों को एक अद्वितीय चर नामों (एक सेट या अद्वितीय पैरामीटर के साथ पेस्ट का उपयोग करके) को असाइन करके इस समस्या से बचता हूं, जो कि फ़ंक्शन के भीतर कभी भी उपयोग नहीं किया जाता है, लेकिन केवल कैशिंग के लिए उपयोग किया जाता है और यदि मुझे बाद में पुनर्प्राप्त करने की आवश्यकता होती है (या कुछ मेटा करें मध्यवर्ती परिणामों पर विश्लेषण।)

+2

धन्यवाद ताल। मेरे पास एक ब्लॉग है, हालांकि मैं वास्तव में इसका उपयोग नहीं करता हूं। मैं कभी भी एक पोस्ट नहीं समाप्त कर सकता क्योंकि मैं इसे तब तक प्रकाशित नहीं करना चाहता जब तक कि यह सही न हो, और मेरे पास इसके लिए समय नहीं है ... – Shane

+1

एक बुद्धिमान व्यक्ति ने मुझे एक बार कहा कि यह सही होना महत्वपूर्ण नहीं है - केवल खड़े हो जाओ - जो आप हैं, और आपकी पोस्ट भी होगी। इसके अलावा - कभी-कभी पाठक टिप्पणी के साथ पाठ को बेहतर बनाने में मदद करते हैं (यही मेरे ब्लॉग के साथ होता है)। मुझे उम्मीद है कि एक दिन आप पुनर्विचार करेंगे :) –

2

इस विषय मैं करते रहे कि < < ऑपरेटर अजीब जब (गलत) (भी अन्य मामलों हो सकता है) लागू किया एक पाश के लिए भीतर व्यवहार करेंगे चाहते हैं पर। निम्नलिखित कोड को देखते हुए:

fortest <- function() { 
    mySum <- 0 
    for (i in c(1, 2, 3)) { 
     mySum <<- mySum + i 
    } 
    mySum 
} 

आप उम्मीद कर सकते है कि समारोह की उम्मीद राशि, 6 वापसी होगी, लेकिन इसके बजाय यह 0 देता है, एक वैश्विक चर mySum बनाया जा रहा है और मूल्य 3. सौंपा मैं पूरी तरह से नहीं कर सकते हैं समझाओ कि यहां क्या हो रहा है लेकिन निश्चित रूप से लूप का शरीर एक नया दायरा 'स्तर' नहीं है। इसके बजाए, ऐसा लगता है कि आर fortest फ़ंक्शन के बाहर दिखता है, mySum वैरिएबल को असाइन करने के लिए नहीं मिल सकता है, इसलिए एक बनाता है और लूप के माध्यम से पहली बार मान 1 असाइन करता है। बाद के पुनरावृत्तियों पर, असाइनमेंट में आरएचएस को (अपरिवर्तित) आंतरिक mySum वैरिएबल का जिक्र करना चाहिए जबकि एलएचएस वैश्विक चर को संदर्भित करता है। इसलिए प्रत्येक पुनरावृत्ति वैश्विक चर के मान को i के पुनरावृत्ति के मान पर ओवरराइट करता है, इसलिए फ़ंक्शन से बाहर निकलने पर यह मान 3 है।

आशा है कि यह किसी की मदद करे - यह आज मुझे कुछ घंटों तक फेंक दिया! (बीटीडब्ल्यू, बस < < < के साथ प्रतिस्थापित करें और फ़ंक्शन अपेक्षित कार्य करता है)।

+2

आपके उदाहरण में, स्थानीय 'mySum' कभी बढ़ी नहीं बल्कि केवल वैश्विक 'mySum'। इसलिए लूप के प्रत्येक पुनरावृत्ति पर, वैश्विक 'mySum' मान '0 + i' मिलता है। आप इसे 'डीबग (किलेस्ट)' के साथ अनुसरण कर सकते हैं। – clemlaflemme

+0

इसे फॉर-लूप होने के साथ कुछ भी नहीं मिला है; आप दो अलग-अलग क्षेत्रों का संदर्भ दे रहे हैं। यदि आप केवल फ़ंक्शन के अंदर स्थानीय चर को अपडेट करना चाहते हैं तो बस फंक्शन के भीतर हर जगह '<-' का उपयोग करें। – smci

+0

या << - हर जगह @smci का उपयोग करें। हालांकि ग्लोबल्स से बचने के लिए सबसे अच्छा है। –

2

<<- ऑपरेटर Reference Classes when writing Reference Methods के लिए भी उपयोगी हो सकता है। उदाहरण के लिए:

myRFclass <- setRefClass(Class = "RF", 
         fields = list(A = "numeric", 
             B = "numeric", 
             C = function() A + B)) 
myRFclass$methods(show = function() cat("A =", A, "B =", B, "C =",C)) 
myRFclass$methods(changeA = function() A <<- A*B) # note the <<- 
obj1 <- myRFclass(A = 2, B = 3) 
obj1 
# A = 2 B = 3 C = 5 
obj1$changeA() 
obj1 
# A = 6 B = 3 C = 9 
संबंधित मुद्दे