R में आप "<< -" (स्कूपिंग असाइनमेंट) का उपयोग कैसे करते हैं?


140

मैंने अभी आर इंट्रो में स्कोपिंग के बारे में पढ़ा , और <<-असाइनमेंट को लेकर बहुत उत्सुक हूं ।

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

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

जवाबों:


196

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

एक क्लोजर एक फ़ंक्शन है जिसे दूसरे फ़ंक्शन द्वारा लिखा जाता है। क्लोज़र इसलिए कहा जाता है क्योंकि वे मूल फ़ंक्शन के वातावरण को संलग्न करते हैं, और उस फ़ंक्शन के सभी चर और मापदंडों तक पहुंच सकते हैं। यह उपयोगी है क्योंकि यह हमें दो स्तरों के मापदंडों की अनुमति देता है। मापदंडों का एक स्तर (माता-पिता) नियंत्रित करता है कि फ़ंक्शन कैसे काम करता है। दूसरे स्तर (बच्चा) काम करता है। निम्न उदाहरण से पता चलता है कि इस विचार का उपयोग बिजली के कार्यों के परिवार को कैसे उत्पन्न किया जा सकता है। मूल कार्य ( 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

4
अरे यह Rosettacode ( rosettacode.org/wiki/Accumulator_factory#R ) पर एक अनसुलझा आर कार्य है , ठीक है, यह था ...
Karsten डब्ल्यू।

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

क्या "<< -" चिन्ह के लिए कोई समान संकेत विकल्प है?
जीनोम

38

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

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

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

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

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


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

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

9

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

 library(tcltk)
 demo(tkdensity)

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


दिलचस्प है, मैं किसी तरह tkdensityआर 3.6.0 में नहीं मिल सकता ।
नेल्सनगॉन


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

11
यह एक अच्छा उदाहरण है जहां उपयोग नहीं करना है <<-। लूप के लिए इस मामले में स्पष्ट होगा।
हैली

4

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

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

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

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


2
आपके उदाहरण में, स्थानीय mySumकभी भी संवर्धित नहीं है , बल्कि केवल वैश्विक है mySum। इसलिए, लूप के प्रत्येक पुनरावृत्ति पर, वैश्विक mySumको मूल्य मिलता है 0 + i। आप इसके साथ अनुसरण कर सकते हैं debug(fortest)
क्लेमेंटवैल्टर

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

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

3

<<-ऑपरेटर के लिए भी उपयोगी हो सकता है जब संदर्भ तरीके लेखन संदर्भ क्लासेस । उदाहरण के लिए:

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.