कोर्स
यह R लूप्स ट्यूटोरियल R में उपलब्ध लूपिंग संरचनाओं, उन्हें कब उपयोग करना चाहिए, और विकल्पों जैसे R की वेक्टराइज़ेशन सुविधा का उपयोग करके अपनी लूपिंग कार्यों को अधिक कुशलता से कैसे करना है, इन सब पर विचार करेगा।
यह पोस्ट कुछ लूपिंग उदाहरण प्रस्तुत करेगी और फिर R द्वारा उपलब्ध समृद्ध लाइब्रेरी सेट में से सबसे लोकप्रिय वेक्टराइज़्ड विकल्पों के पक्ष में उनकी आलोचना और अप्रचलन का सुझाव देगी।
सामान्य तौर पर, इस R लूप्स ट्यूटोरियल की सलाह होगी: लूप्स के बारे में सीखें। वे आपको प्राथमिक स्तर पर क्या होना चाहिए इसका विस्तृत दृश्य देते हैं और साथ ही आप जिस डेटा को संसाधित कर रहे हैं उसकी समझ भी कराते हैं।
और जब आपको लूप्स की स्पष्ट समझ हो जाए, तो उनसे छुटकारा पाएं।
अपना प्रयास वेक्टराइज़्ड विकल्पों को सीखने में लगाएं। दक्षता के लिहाज से यह लाभ देता है।
इंटरैक्टिव अभ्यास के लिए, हमारे इंटरमीडिएट R कोर्स में लूप्स वाला अध्याय आज़माएँ।
लूप्स क्या हैं?
“लूपिंग”, “साइक्लिंग”, “इटरेटिंग” या केवल निर्देशों की पुनरावृत्ति करना कंप्यूटर के आविष्कार से बहुत पहले की पुरानी प्रथा है। यह दरअसल बहु-चरणीय प्रक्रिया को स्वचालित करना है, जिसमें क्रियाओं के अनुक्रमों या ‘बैच’ प्रक्रियाओं को व्यवस्थित किया जाता है और उन हिस्सों को समूहित किया जाता है जिन्हें दोहराने की आवश्यकता होती है।
सभी आधुनिक प्रोग्रामिंग भाषाएँ विशेष संरचनाएँ प्रदान करती हैं जो निर्देशों या निर्देशों के ब्लॉक्स की पुनरावृत्ति की अनुमति देती हैं।
व्यापक रूप से कहें, तो आधुनिक प्रोग्रामिंग भाषाओं में इन विशेष संरचनाओं या लूप्स के दो प्रकार होते हैं। कुछ लूप्स एक निर्धारित संख्या में चलते हैं, जिसे काउंटर या इंडेक्स द्वारा नियंत्रित किया जाता है, जो हर इटरेशन चक्र में बढ़ाया जाता है। ये for लूप परिवार का हिस्सा हैं।
दूसरी ओर, कुछ लूप्स एक तार्किक शर्त के आरंभ और सत्यापन पर आधारित होते हैं। यह शर्त लूप संरचना की शुरुआत या अंत में परखी जाती है। क्रमशः ये वेरिएंट्स while या repeat लूप परिवार से संबंधित हैं।
R में लूप्स का परिचय
R बेस मैनुअल के अनुसार, कंट्रोल फ्लो कमांड्स में लूप संरचनाएँ for, while और repeat हैं, जिनके साथ अतिरिक्त उपवाक्य break और next उपलब्ध हैं।
याद रखें कि कंट्रोल फ्लो कमांड्स वे कमांड्स हैं जो प्रोग्राम को विकल्पों के बीच शाखाबद्ध होने या यूँ कहें “निर्णय लेने” में सक्षम बनाते हैं।
आप इन कंट्रोल फ्लो कमांड्स को हमेशा RStudio के कमांड लाइन पर ?Control बुलाकर देख सकते हैं।
?Control
यह फ्लो चार्ट R लूप संरचनाएँ दिखाता है:

R में For लूप्स
अगले खंडों में हम ऊपर दिए गए चित्र में दर्शाई गई प्रत्येक संरचना पर करीब से नज़र डालेंगे। हम चर्चा की शुरुआत बाएँ वाली संरचना से करेंगे और फिर धीरे-धीरे दाएँ की संरचनाओं की ओर बढ़ेंगे।
For लूप्स का वीडियो परिचय और एक फॉलो-अप अभ्यास के लिए, हमारे इंटरमीडिएट R कोर्स के For Loop अध्याय को आज़माएँ।
For लूप्स की व्याख्या
यह लूप संरचना, जो आयताकार बॉक्स ‘init’ (या initialization), निर्णय वाला हीरा या रहॉम्बस, और आयताकार बॉक्स i1 से बनती है, एक ज्ञात संख्या बार निष्पादित होती है।
फ्लोचार्ट की भाषा में, आयताकार बॉक्स का अर्थ कुछ ऐसा होता है “ऐसा कुछ करें जिसमें निर्णय शामिल न हों”। दूसरी ओर, रहॉम्बस या हीरे “निर्णय प्रतीक” कहलाते हैं और इसलिए ऐसे प्रश्नों में अनूदित होते हैं जिनके केवल दो तार्किक उत्तर होते हैं: True (T) या False (F)।
ध्यान दें कि चीजों को सरल रखने के लिए, अन्य संभावित प्रतीकों को चित्र से हटा दिया गया है।
इनिशियलाइज़ेशन वाले आयत के भीतर एक या अधिक निर्देशों के बाद एक शर्त का मूल्यांकन होता है, जो एक ऐसे वेरिएबल पर है जो किसी निर्दिष्ट अनुक्रम के भीतर मान धारण कर सकता है। चित्र में, यह हीरे द्वारा दर्शाया गया है: प्रतीकों का अर्थ है “क्या वेरिएबल v का वर्तमान मान अनुक्रम seq का सदस्य है?”।
दूसरे शब्दों में, आप जाँच रहे हैं कि v का वर्तमान मान किसी निर्दिष्ट सीमा के भीतर है या नहीं। आप प्रायः यह सीमा इनिशियलाइज़ेशन में निर्धारित करते हैं, जैसे 1:100 ताकि लूप शुरू हो सके।
यदि शर्त पूरी नहीं होती और परिणाम False होता है, तो लूप कभी निष्पादित नहीं होता। यह for लूप संरचना के दाईं ओर ढीले तीर से दर्शाया गया है। तब प्रोग्राम लूप ब्लॉक के बाद मिलने वाले पहले निर्देश को निष्पादित करेगा।
यदि शर्त सत्यापित हो जाती है, तो एक निर्देश — या निर्देशों का ब्लॉक — i1 निष्पादित होता है। और संभव है कि यह ब्लॉक स्वयं एक और लूप हो। ऐसे मामलों में, इसे नेस्टेड लूप कहते हैं।
एक बार यह हो जाने पर, शर्त का फिर मूल्यांकन किया जाता है। यह i1 से ऊपर की ओर जाने वाली लाइनों से इंगित है, जो इनिशियलाइज़ेशन बॉक्स के तुरंत बाद शीर्ष पर लौटती हैं। R — और Python — में हम इसे सामान्य अंग्रेज़ी में भी व्यक्त कर सकते हैं, यह पूछकर कि हमारा वेरिएबल मानों की किसी रेंज में आता है या नहीं।
ध्यान दें कि अन्य भाषाओं में, उदाहरण के लिए C में, शर्त को तार्किक ऑपरेटरों जैसे greater than, less than, equal to, … के साथ अधिक स्पष्ट रूप से व्यक्त किया जाता है।
यहाँ एक सरल for लूप का उदाहरण है:
# Create a vector filled with random normal values
u1 <- rnorm(30)
print("This loop calculates the square of the first 10 elements of vector u1")
# Initialize `usq`
usq <- 0.
for (i in 1:10) {
# i-th element of `u1` squared into `i`-th position of `usq`
usq[i] <- u1[i] * u1[i]
print(usq[i])
}
print(i)
for ब्लॉक कर्ली ब्रेसेज़ में घिरा होता है। इन्हें परीक्षण शर्त के तुरंत बाद या उसके नीचे रखा जा सकता है, और बेहतर है कि उसके बाद इंडेंटेशन आए। यह अनिवार्य नहीं है, लेकिन कर्ली ब्रेसेज़ निश्चित रूप से आपके कोड की पठनीयता बढ़ाती हैं और लूप ब्लॉक तथा उसके भीतर संभावित त्रुटियों को आसानी से पहचानने देती हैं।
ध्यान दें कि वर्गों के वेक्टर usq को इनिशियलाइज़ किया गया है। यह सादे RStudio कोड में आवश्यक नहीं होता, लेकिन मार्कअप संस्करण में knitr संकलित नहीं करेगा क्योंकि लूप में उपयोग से पहले वेक्टर के संदर्भ का न मिलना RStudio में त्रुटि फेंक देता है। knitr के बारे में अधिक जानकारी के लिए, R Markdown पेज पर जाएँ।
For लूप्स को नेस्ट करना
अब जब आप जानते हैं कि for लूप्स को नेस्ट भी किया जा सकता है, तो आप शायद सोच रहे होंगे कि ऐसा क्यों और कब अपने कोड में उपयोग करें।
मान लीजिए कि आप किसी द्वि-आयामी array में उसके तत्वों को विशिष्ट मान देकर हेरफेर करना चाहते हैं।
तब आप कुछ ऐसा कर सकते हैं:
# Insert your own integer here
my_int <- 42
nr <- as.integer(my_int)
# Create a `n` x `n` matrix with zeros
mymat <- matrix(0, nr, nr)
# For each row and for each column, assign values based on position
# These values are the product of two indexes
for (i in 1:dim(mymat)[1]) {
for (j in 1:dim(mymat)[2]) {
mymat[i, j] = i * j
}
}
टिप: matrix() फ़ंक्शन के बारे में अधिक जानकारी के लिए, R Documentation देखें।
i runs over the lines and j runs over the columns.खैर, आपने वही परिचित गुणा तालिका बनाई है जिसे आपको कंठस्थ होना चाहिए।
आप कोई पूर्णांक भी चुन सकते हैं और फिर अपनी पसंद के अनुसार तालिका बना सकते हैं: यदि तालिका वर्गाकार है तो आप किसी चर को एक पूर्णांक सौंप सकते हैं या यदि तालिका आयताकार है तो दो चरों को। यह चर फिर इंडेक्स i और j के ऊपरी सीमा के रूप में काम करेगा।
# Show the first 10x10 chunk or the first `nr` x `nr` chunk
if (nr > 10) {
mymat[1:10, 1:10]
} else
mymat[1:nr, 1:nr]
ध्यान दें कि उपयोगकर्ता को बहुत बड़ी तालिकाओं से स्क्रीन न भर दे, इसके लिए आपने अंत में एक शर्त रखी है कि यदि उपयोगकर्ता ने 10 से बड़ा पूर्णांक माँगा है तो केवल पहली 10 x 10 खंड को प्रिंट करें। अन्यथा, एक n x n खंड प्रिंट होगा।
पूरा कोड इस प्रकार दिखता है:
# Insert your own integer here
my_int <- 42
nr <- as.integer(my_int)
# Create a `n` x `n` matrix with zeroes
mymat <- matrix(0, nr, nr)
# For each row and for each column, assign values based on position
# These values are the product of two indexes
for (i in 1:dim(mymat)[1]) {
for (j in 1:dim(mymat)[2]) {
mymat[i, j] = i * j
}
}
# Show the first 10x10 chunk or the first `nr` x `nr` chunk
if (nr > 10) {
mymat[1:10, 1:10]
} else
mymat[1:nr, 1:nr]
For लूप्स: लोकप्रिय, लेकिन हर बार आपके लिए सर्वोत्तम नहीं
for लूप अब तक का सबसे लोकप्रिय है, और इसकी संरचना यह मानती है कि इटरेशन की संख्या तय और पहले से ज्ञात है, जैसे “पहले 200 अभाज्य संख्याएँ उत्पन्न करें” या “सबसे महत्वपूर्ण 10 ग्राहकों की सूची बनाएँ” जैसे मामलों में।
लेकिन अगर आपको इटरेशन की संख्या का पता न हो या वह आपके नियंत्रण में न हो, और एक या कई शर्तें ऐसी हों जो पहले से अनुमानित न की जा सकें, तो क्या होगा?
उदाहरण के लिए, आप किसी निर्दिष्ट पोस्टल कोड वाले क्षेत्र में रहने वाले ग्राहकों की संख्या गिनना चाह सकते हैं, या पिछले दो दिनों में किसी वेब पेज बैनर पर क्लिकों की संख्या, या इसी तरह की अप्रत्याशित घटनाएँ।
ऐसे मामलों में, while लूप और उसका करीबी repeat मददगार साबित हो सकते हैं…
While लूप्स
while लूप, जो ऊपर दिए गए चित्र के बीच में है, पहले की तरह एक इनिशियलाइज़ेशन ब्लॉक से बना होता है, जिसके बाद एक तार्किक शर्त आती है। यह शर्त सामान्यतः किसी नियंत्रण वेरिएबल और एक मान के बीच तुलना द्वारा व्यक्त की जाती है, जैसे greater than, less than या equal to का उपयोग करके, लेकिन कोई भी ऐसा अभिव्यक्ति जो तार्किक मान True या False देती है, मान्य है।
यदि परिणाम False (F) है, तो लूप कभी निष्पादित नहीं होता, जैसा कि चित्र के दाईं ओर ढीले तीर से दिखाया गया है। तब प्रोग्राम लूप ब्लॉक के बाद मिलने वाले पहले निर्देश को निष्पादित करेगा।
यदि यह True (T) है, तो अगला निर्देश या निर्देशों का ब्लॉक i1 निष्पादित होता है।
ध्यान दें कि एक अतिरिक्त निर्देश या निर्देशों का ब्लॉक i2 जोड़ा गया है: यह नियंत्रण वेरिएबल के अद्यतन के रूप में कार्य करता है, जो लूप की शुरुआत में शर्त के परिणाम को बदल सकता है, पर यह अनिवार्य नहीं है। या शायद आप इटरेशन की संख्या का हिसाब रखने के लिए एक काउंटर में वृद्धि जोड़ना चाहते हैं। जैसे ही शर्त false हो जाती है, इटरेशन बंद हो जाते हैं।
फॉर्मैट है while(cond) expr, जहाँ cond परीक्षण की जाने वाली शर्त है और expr एक अभिव्यक्ति है।
उदाहरण के लिए, निम्नलिखित लूप उपयोगकर्ता से एक User Defined Function या UDF के माध्यम से ब्रह्मांड और हर चीज़ के प्रश्न का सही उत्तर दर्ज करने को कहता है। जब तक उपयोगकर्ता सही उत्तर नहीं दे देता, यह ऐसा करता रहेगा:
# Your User Defined Function
readinteger <- function(){
n <- readline(prompt="Please, enter your ANSWER: ")
}
response <- as.integer(readinteger())
while (response!=42) {
print("Sorry, the answer to whatever the question MUST be 42");
response <- as.integer(readinteger());
}
शुरुआत में, लूप में प्रवेश करने से पहले उपयोगकर्ता इनपुट लेने के लिए एक यूज़र डिफाइंड फ़ंक्शन का उपयोग करें। यह लूप तब तक चलता रहेगा जब तक उत्तर अपेक्षित 42 नहीं होता।
दूसरे शब्दों में, आप ऐसा इसलिए करते हैं क्योंकि अन्यथा R उस गुम अभिव्यक्ति के बारे में शिकायत करेगा जो आवश्यक True या False प्रदान करने वाली थी — और वास्तव में, वह लूप में इस्तेमाल से पहले ‘response’ को जानता ही नहीं। आप ऐसा इसलिए भी करते हैं क्योंकि यदि आप पहली कोशिश में सही उत्तर दे देते हैं, तो लूप बिल्कुल भी निष्पादित नहीं होगा।
Repeat लूप्स
repeat लूप ऊपर दिए गए फ्लो चार्ट के सबसे दाईं ओर स्थित है। यह लूप while लूप के समान है, लेकिन इसमें i1 और i2 निर्देशों के ब्लॉक कम से कम एक बार निष्पादित होते हैं, चाहे शर्त का परिणाम कुछ भी हो।
अन्य भाषाओं के अनुरूप, कोई इस लूप को “repeat until” भी कह सकता है ताकि इस तथ्य पर ज़ोर दिया जा सके कि निर्देश i1 और i2 तब तक चलेंगे जब तक शर्त False (F) रहती है या, समतुल्य रूप से, True (T) हो जाती है, जिससे बाहर निकला जा सके; लेकिन किसी भी हालत में, कम से कम एक बार तो होगा ही।
पिछले उदाहरण के एक रूपांतर के रूप में, आप यह लिख सकते हैं:
readinteger <- function(){
n <- readline(prompt="Please, enter your ANSWER: ")
}
repeat {
response <- as.integer(readinteger());
if (response == 42) {
print("Well done!");
break
} else print("Sorry, the answer to whatever the question MUST be 42");
}
अब परिचित इनपुट फ़ंक्शन के बाद, आपके पास repeat लूप है जिसका ब्लॉक कम से कम एक बार निष्पादित होता है और if शर्त सत्य होते ही समाप्त हो जाएगा।
ध्यान दें कि आपको लूप के भीतर एक शर्त निर्धारित करनी पड़ी जिस पर break उपवाक्य के साथ निकला जा सके। यह उपवाक्य हमें लूप्स के भीतर चक्रों से बाहर निकलने या उन्हें बाधित करने की धारणा से परिचित कराता है।
R में लूप्स का अवरोधन और उनसे बाहर निकलना
तो आप किसी लूप से बाहर कैसे निकलते हैं?
दूसरे शब्दों में, लूप के “स्वाभाविक” अंत के अलावा, जो या तो इसलिए होता है कि आपने निर्धारित इटरेशन संख्या पूरी कर ली (for) या कोई शर्त पूरी हो गई (while, repeat), क्या आप लूप को रोक या बाधित कर सकते हैं?
और अगर हाँ, तो कैसे?
break स्टेटमेंट पहले प्रश्न का उत्तर देता है: आपने इसे आखिरी उदाहरण में देखा है।
break के साथ अपने लूप्स तोड़ें
जब R इंटरप्रेटर को break मिलता है, तो वह नियंत्रण को लूप के अंत के तुरंत बाद वाली निर्देश पंक्ति (यदि कोई है) को सौंप देता है। नेस्टेड लूप्स के मामले में, break केवल सबसे अंदरूनी लूप से बाहर निकलने की अनुमति देगा।
यहाँ एक उदाहरण है।
यह कोड खंड शून्यों की एक m x n मैट्रिक्स परिभाषित करता है और फिर मैट्रिक्स के स्थानों को भरने के लिए एक नेस्टेड for लूप में प्रवेश करता है, लेकिन केवल तब जब दोनों इंडेक्स अलग हों। उद्देश्य एक लोअर ट्रायएंगुलर मैट्रिक्स बनाना है, यानी ऐसी मैट्रिक्स जिसकी मुख्य विकर्ण के नीचे के तत्व शून्य न हों। बाकी को उनकी इनिशियलाइज़ की गई शून्य मान पर छोड़ दिया जाता है।
जब इंडेक्स बराबर होते हैं और इस प्रकार अंदरूनी लूप में, जो कॉलम इंडेक्स j पर चलता है, शर्त पूरी होती है, तो एक break निष्पादित होता है और सबसे अंदरूनी लूप बाधित हो जाता है, और सीधे अंदरूनी लूप के बाद वाली निर्देश पर जंप हो जाता है। यह निर्देश एक print() निर्देश है। फिर नियंत्रण बाहरी for शर्त (पंक्तियों पर, इंडेक्स i) पर आता है, जिसका फिर से मूल्यांकन होता है।
यदि इंडेक्स अलग हैं, तो असाइनमेंट किया जाता है और काउंटर 1 से बढ़ाया जाता है। अंत में, प्रोग्राम काउंटर ctr प्रिंट करता है, जिसमें असाइन किए गए तत्वों की संख्या होती है।
# Make a lower triangular matrix (zeroes in upper right corner)
m = 10
n = 10
# A counter to count the assignment
ctr = 0
# Create a 10 x 10 matrix with zeroes
mymat = matrix(0, m, n)
for (i in 1:m) {
for (j in 1:n) {
if (i == j) {
break
} else {
# you assign the values only when i<>j
mymat[i, j] = i * j
ctr = ctr + 1
}
}
print(i * j)
}
# Print how many matrix cells were assigned
print(ctr)
ध्यान दें कि कभी-कभी कर्ली ब्रैकेट्स वहाँ भी लगा देना, जहाँ वे सख्ती से आवश्यक नहीं हैं, थोड़ा ज्यादा सतर्क होना लग सकता है। आप आमतौर पर यह सुनिश्चित करने के लिए ऐसा करते हैं कि जो भी { से खोला गया है, वह } से बंद भी हो। तो यदि आपको { या } की असंगत संख्या दिखे, तो आप जानते हैं कि कोई त्रुटि है, हालाँकि इसका उलटा आवश्यक रूप से सत्य नहीं है!
लूप्स में next का उपयोग
next किसी विशेष इटरेशन को समाप्त कर अगले चक्र पर कूद जाता है। वास्तव में, यह वर्तमान लूप की शर्त के मूल्यांकन पर छलांग लगा देता है।
अन्य भाषाओं में, आपको इसका (हल्का भ्रमित करने वाला) समकक्ष “continue” मिल सकता है, जिसका अर्थ वही है: जहाँ कहीं भी हों, शर्त की जाँच होते ही लूप के मूल्यांकन पर कूद जाएँ।
किसी शर्त के घटित होने पर किसी विशेष चक्र को छोड़ते हुए लूप को जारी रखने का एक सरल उदाहरण है:
m = 20
for (k in 1:m) {
if (!k %% 2)
next
print(k)
}
यह कोड खंड अंतराल 1:m (यहाँ m=20) के सभी विषम संख्याएँ प्रिंट करता है। दूसरे शब्दों में, वे सभी पूर्णांक जिनका 2 से भाग देने पर शेषफल शून्य नहीं आता (इसीलिए मॉड्यूलस ऑपरेन्ड %% का उपयोग), जैसा कि if परीक्षण में निर्दिष्ट है, प्रिंट होंगे।
जिन संख्याओं का शेषफल शून्य है वे प्रिंट नहीं होंगी, क्योंकि प्रोग्राम i in 1:m शर्त के मूल्यांकन पर कूद जाता है और उसके बाद आने वाले किसी भी निर्देश को नज़रअंदाज़ कर देता है। इस मामले में, print(k) को छोड़ दिया जाता है।
R में लूप्स के उपयोग का समापन
- लूप के भीतर यथासंभव कम कोड रखें, जितने निर्देश आप बाहर ले जा सकते हैं, ले जाएँ। याद रखें, लूप के अंदर की हर चीज़ कई बार दोहराई जाएगी और संभव है कि उसकी ज़रूरत न हो।
repeatका उपयोग करते समय सावधानी बरतें: सुनिश्चित करें कि किसी शर्त की जाँच द्वारा स्पष्ट रूप से समाप्ति निर्धारित हो, अन्यथा आप अनंत लूप में फँस सकते हैं।- यदि कोई लूप (बहुत) बड़ा हो रहा है, तो लूप के भीतर एक या अधिक फ़ंक्शन कॉल्स का उपयोग करना बेहतर है। फ़ंक्शन कॉल्स अन्य उपयोगकर्ताओं के लिए कोड का अनुसरण करना आसान बना देंगी। लेकिन मैट्रिक्स या array ऑपरेशन्स करने के लिए नेस्टेड for लूप का उपयोग करना संभवतः इस बात का संकेत है कि आपने R जैसी मैट्रिक्स-आधारित भाषा के लिए चीज़ों को सर्वश्रेष्ठ तरीके से लागू नहीं किया है।
- हर इटरेशन में असाइनमेंट करके किसी वेरिएबल या डेटासेट को “बढ़ाना” अनुशंसित नहीं है। Matlab जैसी कुछ भाषाओं में एक चेतावनी त्रुटि जारी की जाती है: आप जारी रख सकते हैं, लेकिन आपको विकल्पों पर विचार करने के लिए आमंत्रित किया जाता है। एक सामान्य उदाहरण अगले खंड में दिखाया जाएगा।
R लूप्स का उपयोग कब करें
यह सब ठीक है, लेकिन R में आपको लूप्स कब इस्तेमाल करने चाहिए और कब नहीं?
जब भी किसी ऑपरेशन(ऑपरेशन्स) को दोहराने की ज़रूरत हो, एक लूप काम आ सकता है।
आपको केवल यह निर्दिष्ट करना होता है कि वे ऑपरेशन्स कितनी बार या किन शर्तों पर निष्पादित हों: आप किसी कंट्रोल लूप वेरिएबल को प्रारंभिक मान देते हैं, लूप चलाते हैं और फिर, लूप समाप्त होने पर, आमतौर पर परिणामों के साथ कुछ करते हैं।
लेकिन आपको लूप्स का उपयोग कब करना चाहिए?
क्या आप वांछित निर्देश को पर्याप्त बार प्रतिलिपि बनाकर काम नहीं चला सकते?
ठीक है, एक मोटा नियम यह हो सकता है कि यदि आपको कोई क्रिया (मान लें) तीन बार या उससे अधिक करनी हो, तो लूप आपके लिए बेहतर रहेगा। यह कोड को अधिक कॉम्पैक्ट, पठनीय और अनुरक्षित बनाता है और आपका टाइपिंग भी बचा सकता है: मान लीजिए आपको पता चलता है कि किसी निर्देश को प्रारंभिक अनुमान से एक बार अधिक दोहराने की ज़रूरत है: पूरी निर्देश को फिर से लिखने के बजाय, आप बस परीक्षण शर्त में किसी वेरिएबल का मान बदल सकते हैं।
फिर भी, R की विशिष्ट प्रकृति सुझाव देती है कि जहाँ भी विकल्प उपलब्ध हों, वहाँ लूप्स का उपयोग बिल्कुल न करें(!)।
खुशकिस्मती से, कुछ विकल्प मौजूद हैं!
R में एक ऐसी सुविधा है जो कुछ ही प्रोग्रामिंग भाषाओं में होती है, जिसे वेक्टराइज़ेशन कहते हैं।
R में लूप्स के विकल्प
वेक्टराइजेशन क्या है?
जैसा कि शब्द से स्पष्ट है, वेक्टराइजेशन का अर्थ है सरल संख्याओं (“स्केलर”) पर दोहराए जाने वाले ऑपरेशन्स को वेक्टर या मैट्रिस पर एकल ऑपरेशन्स में बदलना। आप उपर्युक्त उपखंडों में इसके कई उदाहरण देख चुके हैं।
अब, R में वेक्टर एक प्राथमिक डेटा संरचना है और R बेस मैनुअल के अनुसार यह “वस्तुओं के संग्रह से बना एक एकल ईकाई” है।
तो, संख्याओं का संग्रह एक न्यूमेरिक वेक्टर है।
यदि आप (समान लंबाई वाले) वेक्टर्स को संयोजित करते हैं, तो आपको एक मैट्रिस मिलती है। आप ऐसा ऊर्ध्वाधर या क्षैतिज रूप से, विभिन्न R निर्देशों से कर सकते हैं। अतः R में, किसी मैट्रिस को क्षैतिज या ऊर्ध्वाधर वेक्टर्स के संग्रह के रूप में देखा जाता है। विस्तार से, आप वेक्टर्स पर दोहराए जाने वाले ऑपरेशन्स को भी वेक्टराइज़ कर सकते हैं।
ऊपर दिए गए कई लूप संरचनाओं को वेक्टराइजेशन का उपयोग करके अप्रकट बनाया जा सकता है।
मैं “अप्रकट” कहता/कहती हूँ, क्योंकि वे वास्तव में गायब नहीं होते। निम्न स्तर पर, वैकल्पिक वेक्टराइज़्ड रूप उस निम्न-स्तरीय भाषा (Fortran, C, या C++ ) में ऐसे कोड में अनूदित हो जाता है जिसमें एक या अधिक लूप्स होते हैं, जहाँ उस रूप को लागू और संकलित किया गया था।
ये उपयोगकर्ता से छिपे रहते हैं और सामान्यतः समकक्ष स्पष्ट R कोड से तेज़ चलते हैं, पर जब तक आप उन भाषाओं में अपने स्वयं के R फ़ंक्शन्स लागू करने की योजना नहीं बनाते, यह आपके लिए पूरी तरह पारदर्शी रहता है।
सबसे प्राथमिक उदाहरण जो आप सोच सकते हैं, वह है दो वेक्टर्स v1 और v2 का जोड़ कर एक वेक्टर v3 बनाना, जिसे या तो for लूप से प्रत्येक तत्व पर किया जा सकता है:
v1 <- c(3,4,5)
v2 <- c(3,4,6)
v3 <- c(0,0,0)
n = length(v1)
for (i in 1:n) {
v3[i] <- v1[i] + v2[i]
}
v3
या आप “मूल” वेक्टराइज़्ड रूप का उपयोग कर सकते हैं:
v3 = v1 + v2
v3
ध्यान दें कि इसे “मूल” इसलिए कहते हैं क्योंकि R सभी अंकगणितीय ऑपरेटरों को वेक्टर और मैट्रिस पर कार्यरत समझता है।
इसी तरह, दो मैट्रिस A और B के लिए, A[i,j] और B[i,j] के क्रम-स्थानों के तत्वों को जोड़ने की बजाय, जिसके लिए आपको दो इंडेक्स i और j का ध्यान रखना पड़ता है, आप R को यह करने के लिए कहते हैं:
A <- matrix(1:6, nrow = 3, ncol = 2)
B <- matrix(c(2,4,3,1,5,7), nrow=3, ncol=2)
C= A + B
C
और यह सचमुच बहुत सरल है!
R में वेक्टराइजेशन समझाया गया
जबकि प्राथमिक ऑपरेशन्स की संख्या समान दिखती है, फिर वेक्टराइजेशन तेज़ क्यों चलता है?
यह R की आंतरिक कार्यप्रणाली देखकर सबसे बेहतर समझाया जा सकता है, जिसके लिए अलग पोस्ट चाहिए होगा, पर संक्षेप में: सबसे पहले, R एक इंटरप्रेटेड भाषा है और इस रूप में, वैरिएबल परिभाषा से जुड़े सभी विवरण इंटरप्रेटर संभालता है। उदाहरण के लिए, आपको यह निर्दिष्ट करने की आवश्यकता नहीं होती कि कोई संख्या फ्लोटिंग पॉइंट है या मेमोरी में पॉइंटर से मेमोरी आबंटित करनी है।
R इंटरप्रेटर आपके कमांड्स के संदर्भ से इन बातों को “समझता” है, लेकिन वह यह काम कमांड-दर-कमांड करता है। इसलिए, चाहे आप किसी कमांड को दोहराएँ, उसे हर बार ऐसी परिभाषाओं से निपटना पड़ता है।
इसके बजाय, एक कम्पाइलर समूचे कोड पर संकलन-समय में शाब्दिक रूप से सारी परिभाषाएँ और घोषणाएँ हल कर देता है; तत्पश्चात कुछ भी निष्पादित करने से पहले कोड को एक सघन और अनुकूलित बाइनरी में बदल दिया जाता है। अब, चूँकि R फ़ंक्शन्स इनमें से किसी निम्न-स्तरीय भाषा में लिखे होते हैं, वे अधिक दक्ष होते हैं।
व्यवहार में, यदि कोई निम्न-स्तरीय कोड देखे, तो उसे प्रायः C या C++ के कॉल्स मिलेंगे, जो सामान्यतः एक तथाकथित रैपर कोड के भीतर लागू होते हैं।
दूसरे, वेक्टराइजेशन का समर्थन करने वाली भाषाओं (जैसे R या Matlab) में, प्रत्येक निर्देश जो किसी न्यूमेरिक डाटा का उपयोग करता है, ऐसे ऑब्जेक्ट पर कार्य करता है जो मूलतः वेक्टर के रूप में परिभाषित है, भले ही उसमें केवल एक तत्व हो। यह डिफ़ॉल्ट है जब आप, उदाहरण के लिए, एक एकल न्यूमेरिक वैरिएबल परिभाषित करते हैं: R में उसकी आंतरिक अभिव्यक्ति हमेशा एक वेक्टर होगी, चाहे वह सिर्फ एक संख्या ही क्यों न हो।
लूप्स परदे के पीछे बने रहते हैं, पर C/C++ के संकलित निम्न और बहुत तेज़ स्तर पर। वेक्टर होने का लाभ यह है कि परिभाषाएँ इंटरप्रेटर द्वारा पूरे वेक्टर पर केवल एक बार हल कर दी जाती हैं, उसके आकार से निरपेक्ष। इसके विपरीत, स्केलर पर किए गए लूप में परिभाषाएँ और आबंटन तत्व-दर-तत्व करने पड़ते हैं, और यह धीमा है।
अंततः, मूल वेक्टर फ़ॉर्मैट के साथ कार्य करना अत्यंत दक्ष रैखिक बीजगणित रूटीनों (जैसे BLAS या Basic Linear Algebra Subprograms) का उपयोग संभव बनाता है, ताकि वेक्टराइज़्ड निर्देशों के निष्पादन पर R इन प्रभावी संख्यात्मक रूटीनों का लाभ उठा सके। अतः संदेश यह होगा कि जहाँ संभव हो, एक ही फ़ंक्शन कॉल में संपूर्ण डाटा संरचनाओं को प्रोसेस करें ताकि उन सारी कॉपींग ऑपरेशन्स से बचा जा सके जो अन्यथा निष्पादित होते हैं।
पर अब विषयांतर काफी हुआ, आइए वेक्टराइजेशन का एक सामान्य उदाहरण देखें, और फिर अगले उपखंड में, आप लूप्स के स्थान पर उपयोग होने वाले कुछ विशिष्ट और लोकप्रिय R वेक्टराइज़्ड फ़ंक्शन्स में उतरेंगे।
R में वेक्टराइजेशन का एक उदाहरण
“ग्रोइंग डाटा” की धारणा पर लौटते हैं, जो कि किसी डेटा फ्रेम को “अपडेट” करने का आम तौर पर अक्षम तरीका है।
पहले, आप replicate(m, rnorm(n)) से एक m x n मैट्रिस बनाते हैं, जहाँ m=10 कॉलम वेक्टर्स में प्रत्येक में n=10 तत्व होते हैं, जो rnorm(n) से बनते हैं, जो यादृच्छिक सामान्य संख्याएँ बनाता है।
फिर आप इसे डेटा फ्रेम में बदलते हैं (अर्थात् 10 वैरिएबल्स के 10 ऑब्ज़र्वेशन्स) और एक नेस्टेड for लूप से प्रत्येक तत्व पर एक बीजीय क्रिया करते हैं: हर इटेरेशन पर, एक साइनसोइडल फ़ंक्शन उन दो इंडेक्सेस द्वारा संदर्भित हर तत्व में वृद्धि करता है।
निम्न उदाहरण थोड़ा कृत्रिम है, पर यह किसी सिग्नल को कुछ रैंडम नॉइज़ में जोड़ने का प्रतिनिधित्व कर सकता है:
# This is a bad loop with 'growing' data
set.seed(42)
m = 10
n = 10
# Create matrix of normal random numbers
mymat <- replicate(m, rnorm(n))
# Transform into data frame
mydframe <- data.frame(mymat)
for (i in 1:m) {
for (j in 1:n) {
mydframe[i, j] <- mydframe[i, j] + 10 * sin(0.75 * pi)
print(mydframe)
}
}
यहाँ, निष्पादन समय का अधिकांश भाग कॉपी करने और लूप को मैनेज करने में लगता है।
देखें कि वेक्टराइज़्ड समाधान कैसा दिखता है:
set.seed(42)
m = 10
n = 10
mymat <- replicate(m, rnorm(n))
mydframe <- data.frame(mymat)
mydframe <- mydframe + 10 * sin(0.75 * pi)
mydframe
यह सरल लगता है: आखिरी पंक्ति नेस्टेड for लूप की जगह लेती है। ध्यान दें कि दोनों इंप्लीमेंटेशन्स का ठीक वही परिणाम सुनिश्चित करने के लिए set.seed() का उपयोग किया गया है।
अब दोनों समाधानों के निष्पादन समय को परिमाणित करते हैं।
आप यह R के सिस्टम कमांड्स, जैसे system.time() का उपयोग करके कर सकते हैं, जिसमें कोड का एक टुकड़ा इस तरह पास किया जा सकता है:
टिप: जिस कोड का आप आकलन करना चाहते हैं, उसे system.time() फ़ंक्शन के कोष्ठकों के बीच रख दें।
# Insert `system.time()` to measure loop execution
for (i in 1:m) {
for (j in 1:n) {
mydframe[i, j] <- mydframe[i, j] + 10 * sin(0.75 * pi)
}
}
# Add `system.time()` to measure vectorized execution
mydframe <- mydframe + 10 * sin(0.75 * pi)
ऊपर के कोड खंड में, आप m और n चुनने, मैट्रिस बनाने और उसे डेटा फ्रेम में बदलने का काम शुरुआत में केवल एक बार करते हैं, और फिर for वाले भाग का वेक्टराइज़्ड संस्करण के “वन-लाइनर” के मुकाबले दो अलग-अलग system.time() कॉल्स से मूल्यांकन करते हैं।
आप देखते हैं कि केवल m=n=10 की न्यूनतम सेटिंग के साथ भी वेक्टराइज़्ड संस्करण 7 गुना तेज़ है, यद्यपि इतने कम मानों के लिए, यह उपयोगकर्ता के लिए बमुश्किल मायने रखता है।
अंतर (मानवीय पैमाने पर) तब ध्यान देने योग्य हो जाते हैं जब आप m=n=100 रखते हैं, जबकि 1000 तक बढ़ाने पर for लूप कई दर्जन सेकंड तक अटका हुआ लगता है, जबकि वेक्टराइज़्ड रूप अब भी आँख झपकते ही चल जाता है।
m=n=10000 के लिए for लूप एक मिनट से अधिक अटका रहता है जबकि वेक्टराइज़्ड को 2.54 सेकंड लगते हैं। बेशक, इन मापों को हल्के में लेना चाहिए और ये हार्डवेयर और सॉफ्टवेयर कॉन्फ़िगरेशन पर निर्भर होंगे; बेहतर है कि अपने लैपटॉप पर इंटरनेट ब्राउज़र में दर्जनों खुले टैब और पृष्ठभूमि में चल रहे कई अनुप्रयोगों से ओवरलोडिंग से बचें; फिर भी ये माप अंतर की झलक दिखाते हैं।
न्यायपूर्वक कहें तो, m और n की वृद्धि मैट्रिस जनरेशन को भी गंभीर रूप से प्रभावित करती है जैसा कि आप आसानी से प्रतिकृति फ़ंक्शन के चारों ओर एक और system.time() कॉल रखकर देख सकते हैं।
आपको प्रोत्साहित किया जाता है कि m और n के साथ खेलें और देखें कि निष्पादन समय कैसे बदलता है, निष्पादन समय को गुणनफल m x n के एक फ़ंक्शन के रूप में प्लॉट करके। यही प्रासंगिक संकेतक है, क्योंकि यह बनाई गई मैट्रिसों का आयाम व्यक्त करता है। यह इस प्रकार nset-ed for लूप के जरिए कार्य पूरा करने के लिए आवश्यक इटेरेशन्स की संख्या को भी मापता है।
तो यह वेक्टराइजेशन का एक उदाहरण है। पर ऐसे और भी कई हैं। R News, जो R प्रोजेक्ट का न्यूज़लेटर है के पेज 46 पर, एर्रे या मैट्रिस में कुछ आयामों पर सम और औसत निकालने के लिए बहुत दक्ष फ़ंक्शन्स हैं, जैसे: rowSums(), colSums(), rowMeans(), और colMeans()।
इसके अलावा, न्यूज़लेटर यह भी उल्लेख करता है कि “…‘apply’ परिवार के फ़ंक्शन्स, जिनके नाम [s,l,m,t]apply हैं, ऑब्जेक्ट्स के तत्वों/आयामों पर किसी अन्य फ़ंक्शन को लागू करने के लिए दिए गए हैं। ये ‘apply’ फ़ंक्शन्स कभी-कभी काफ़ी जटिल कार्यों के लिए एक संक्षिप्त सिंटैक्स देते हैं जो कि खराब लिखे गए लूप्स की तुलना में अधिक पठनीय और तेज़ है।”.
apply परिवार: क्या सिर्फ़ छिपे हुए लूप्स?
apply फ़ंक्शन्स का बहुत समृद्ध और शक्तिशाली परिवार मूलतः वेक्टराइज़्ड फ़ंक्शन्स से बना है। पहली नज़र में यदि इनमें कोई लूप नज़र नहीं आता, तो यह विशेषता तब स्पष्ट होती है जब आप परदे के पीछे ध्यान से देखते हैं।
apply कमांड या यों कहें कमांड्स का परिवार, R बेस पैकेज का हिस्सा है। यह कई फ़ंक्शन्स ([s,l,m,r, t,v]apply) से भरा है जो मैट्रिस या एर्रे के रूप में डेटा की स्लाइसों को बार-बार संसाधित करने की सुविधा देता है, डेटा को क्रॉस या ट्रैवर्स करने की अनुमति देता है और स्पष्ट लूप संरचनाओं के उपयोग से बचाता है। ये फ़ंक्शन्स इनपुट मैट्रिस या एर्रे पर कार्य करते हैं और चुने गए नामित फ़ंक्शन को एक या अधिक वैकल्पिक आर्ग्युमेंट्स के साथ लागू करते हैं।
ध्यान दें कि यही कारण है कि ये तथाकथित ‘फंक्शनल्स’ (Hadley Wickham के Advanced R पेज में) के अंतर्गत आते हैं।
कॉल किया गया फ़ंक्शन एक एग्रीगेटिंग फ़ंक्शन हो सकता है, जैसे सरल mean, या कोई अन्य ट्रांसफॉर्मिंग या सब-सेटिंग फ़ंक्शन।
यह ध्यान देने योग्य है कि इन फ़ंक्शन्स के अनुप्रयोग से अनिवार्य रूप से तेज़ निष्पादन नहीं मिलता: अंतर बहुत बड़े नहीं होते; बल्कि यह झंझटपूर्ण लूप्स के कोडिंग से बचाता है और त्रुटियों की संभावना कम करता है।
परिवार के भीतर के फ़ंक्शन्स हैं: apply(), sapply(), lapply(), mapply(), rapply(), tapply(), vapply()।
पर इन्हें कब और कैसे उपयोग करना चाहिए?
खैर, यह ध्यान देने योग्य है कि plyr जैसा पैकेज इस परिवार की कार्यक्षमता को कवर करता है; यद्यपि इन्हें आधिकारिक डाक्यूमेंटेशन देखे बिना सब याद रखना कठिन लग सकता है, फिर भी ये फ़ंक्शन्स अधिक जटिल और उपयोगी संयोजनों की बुनियाद बनाते हैं।
पहले तीन सबसे अधिक उपयोग किए जाते हैं:
apply()
आप किसी दी हुई फ़ंक्शन को किसी मैट्रिस की पंक्तियों (इंडेक्स “1”) या स्तंभों (इंडेक्स “2”) पर लागू करना चाहते हैं। अधिक जानकारी के लिए यह पेज देखें।
lapply()
आप किसी दी हुई फ़ंक्शन को किसी सूची के हर तत्व पर लागू करना चाहते हैं और परिणाम में एक सूची प्राप्त करना चाहते हैं (इसीलिए फ़ंक्शन नाम में “l” है)। इस फ़ंक्शन पर R डाक्यूमेंटेशन पढ़ें।
sapply()
आप किसी दी हुई फ़ंक्शन को सूची के हर तत्व पर लागू करना चाहते हैं पर आप सूची के बजाय वेक्टर प्राप्त करना चाहते हैं। और जानना चाहते हैं? R डाक्यूमेंटेशन पेज देखें।
संबंधित फ़ंक्शन्स sweep(), by() और aggregate() हैं और कभी-कभी इन्हें apply() परिवार के तत्वों के साथ मिलकर उपयोग किया जाता है।
मैं इस ब्लॉग पोस्ट की चर्चा को apply() फ़ंक्शन तक सीमित रखता/रखती हूँ (इस विषय पर अधिक विस्तृत चर्चा किसी भविष्य के पोस्ट का विषय हो सकती है)।
किसी मैट्रिस M को दिया जाए, तो कॉल apply(M,1,fun) या apply(M, 2,fun) निर्दिष्ट फ़ंक्शन fun को 1 निर्दिष्ट होने पर M की पंक्तियों पर, या 2 निर्दिष्ट होने पर M के स्तंभों पर लागू करेगा। इस संख्यात्मक आर्ग्युमेंट को “margin” कहा जाता है और यह मान 1 और 2 तक सीमित है क्योंकि फ़ंक्शन मैट्रिस पर कार्य करता है। हालाँकि, आपके पास अधिकतम 8 आयामों वाला एर्रे भी हो सकता है।
फ़ंक्शन कोई भी मान्य R फ़ंक्शन हो सकता है, बल्कि यह एक यूज़र डिफ़ाइंड फ़ंक्शन (UDF) भी हो सकता है, जिसे apply() के अंदर ही कोड किया गया हो, जो सुविधाजनक है।
apply(): एक उदाहरण
# define matrix `mymat` by replicating the sequence `1:5` for `4` times and transforming into a matrix
mymat <- matrix(rep(seq(5), 4), ncol = 5)
# `mymat` sum on rows
apply(mymat, 1, sum)
# `mymat` sum on columns
apply(mymat, 2, sum)
# With user defined function within the apply that adds any number `y` to the sum of the row
# `y` is set at `4.5`
apply(mymat, 1, function(x, y)
sum(x) + y, y = 4.5)
# Or produce a summary column wise for each column
apply(mymat, 2, function(x, y)
summary(mymat))
आप अक्सर डेटा फ्रेम का उपयोग करते हैं: इस विशेष मामले में, आपको सुनिश्चित करना चाहिए कि डेटा का प्रकार समान हो, नहीं तो बाध्य डेटा प्रकार रूपांतरण हो सकते हैं, जो संभवतः आपकी मंशा नहीं है। उदाहरण के लिए, मिश्रित टेक्स्ट और संख्या वाले डेटा फ्रेम में, न्यूमेरिक डेटा स्ट्रिंग्स या कैरेक्टर्स में परिवर्तित हो जाएगा।
R में लूप्स के उपयोग और उनके विकल्पों पर अंतिम विचार
तो अब, यह यात्रा हमें प्रोग्रामिंग में प्रयुक्त बुनियादी लूप संरचनाओं से वेक्टराइजेशन की (मूल) धारणा तक और R में अक्सर सामने आने वाले apply() परिवार के एक फ़ंक्शन के उपयोग के उदाहरण तक ले आई।
कोड फ्लो कंट्रोल की दृष्टि से, आपने केवल लूप्स से निपटा: for, while, repeat और इन्हें बाधित कर बाहर निकलने के तरीके।
चूँकि अंतिम उपखंडों में संकेत है कि R में लूप्स से बचना चाहिए, आप पूछ सकते हैं कि फिर इन्हें सीखना ही क्यों।
मेरे विचार में, आपको इन प्रोग्रामिंग संरचनाओं को इसलिए सीखना चाहिए क्योंकि:
- संभावना है कि R डेटा साइंस या अन्यत्र आपका एकमात्र भाषा नहीं होगा, और लूप्स जैसी सामान्य संरचनाओं को समझना आपके कौशल बैग में रखने लायक उपयोगी बात है। लूप सिंटैक्स भाषा पर निर्भर कर बदल सकता है, पर एक भाषा में इन्हें साध लेने पर, आप उन्हें किसी भी अन्य भाषा में सहजता से लागू कर पाएँगे।
- R का ब्रह्मांड विशाल है और सभी मौजूद R फ़ंक्शन्स से अवगत रहना बहुत कठिन, यदि असंभव नहीं, है। चीजें करने के कई तरीके हैं, कुछ अन्य की तुलना में अधिक दक्ष या सुरुचिपूर्ण, और आपका सीखना क्रमिक होगा; जब आप उनका उपयोग करेंगे, तो आप अपने आपसे चीजें अधिक दक्षता से करने के तरीकों के बारे में पूछना शुरू करेंगे और अंततः ऐसे फ़ंक्शन्स पर पहुँचेंगे जिनके बारे में आपने पहले कभी नहीं सुना होगा। जब तक आप इसे पढ़ेंगे, कुछ नई लाइब्रेरीज़ विकसित हो चुकी होंगी, अन्य जारी हो चुकी होंगी, और इसलिए उन सभी को जानने की संभावना कम है, जब तक कि आप अपना समूचा समय R विशेषज्ञ के रूप में न बिताएँ।
- अंत में, कम से कम तब जब आप विशेष रूप से अत्यधिक आयामी डेटासेट्स से नहीं निपट रहे हों, तो लूप समाधान कोड करना और पढ़ना आसान होगा। और शायद, एक डेटा साइंटिस्ट के रूप में, आपसे कोई एक-मुश्त प्रोटोटाइप बनाने को कहा जाए जो बस काम कर दे। शायद, आप परिणाम पाने के परिष्कृत या सुरुचिपूर्ण तरीकों में रुचि न रखते हों। शायद, डेटा विश्लेषण कार्यप्रवाह में, आपको बस डोमेन विशेषज्ञता दिखानी हो और विषयवस्तु पर ध्यान केंद्रित करना हो। उत्पादन चरण की देखभाल कोई और, संभवतः बैक-एंड विशेषज्ञ, करेगा (और शायद वह इसे किसी अलग भाषा में कोड कर रहा हो!)
यदि इस ट्यूटोरियल को पढ़ने के बाद R में for लूप्स आपको अब चुनौतीपूर्ण नहीं लगते, तो आप DataCamp का Intermediate R कोर्स ले सकते हैं। यह कोर्स Intermediate R के विषयों पर आपके ज्ञान को कई नए और मनोरंजक अभ्यासों के साथ मजबूत करेगा। यदि, हालाँकि, लूप्स अब आपसे कोई राज़ नहीं रखते, तो DataCamp का Writing Functions in R कोर्स, जिसे Hadley और Charlotte Wickham पढ़ाते हैं, आपको रुचिकर लग सकता है। साथ ही, For Loops in R ट्यूटोरियल भी देखें।
इस ट्यूटोरियल का कोड ऑनलाइन चलाएं और संपादित करें
कोड चलाएंR लूप्स से जुड़े सामान्य प्रश्न
R में लूप्स क्या हैं और वे क्यों उपयोगी हैं?
लूप्स किसी कोड ब्लॉक को कई बार दोहराने का एक तरीका हैं। ये तब उपयोगी होते हैं जब आप एक ही क्रिया को कई डेटा पॉइंट्स या ऑब्जेक्ट्स पर करना चाहते हैं, या जब आप किसी विशेष शर्त के पूरा होने तक कोई क्रिया दोहराना चाहते हैं।
R में लूप्स के अलग‑अलग प्रकार कौन‑से हैं?
R में दो मुख्य प्रकार के लूप्स होते हैं: for लूप्स और while लूप्स।
- For लूप्स किसी सूची या अनुक्रम की हर आइटम के लिए कोड ब्लॉक को दोहराते हैं। उदाहरण के लिए, आप किसी वेक्टर के सभी तत्वों को प्रिंट करने या किसी लिस्ट के हर तत्व पर एक फंक्शन लागू करने के लिए for लूप का उपयोग कर सकते हैं।
- While लूप्स तब तक कोड ब्लॉक को दोहराते हैं जब तक कोई शर्त सत्य रहती है। उदाहरण के लिए, आप उपयोगकर्ता से वैध उत्तर मिलने तक इनपुट मांगते रहने के लिए while लूप का उपयोग कर सकते हैं।
मैं R में किसी लूप को कैसे रोकूँ?
R में किसी लूप को रोकने के लिए आप break स्टेटमेंट का उपयोग कर सकते हैं। यह तुरंत लूप से बाहर निकलकर बाकी कोड पर आगे बढ़ जाएगा।
मैं R में लूप की अगली iteration पर कैसे जाऊँ?
R में लूप की अगली iteration पर जाने के लिए आप next स्टेटमेंट का उपयोग कर सकते हैं। यह वर्तमान iteration के बचे हुए हिस्से को छोड़कर सीधे अगले पर चला जाएगा।
क्या मैं एक लूप के अंदर दूसरा लूप रख सकता/सकती हूँ?
हाँ, आप R में एक लूप के अंदर दूसरे लूप रख सकते हैं। इसे "नेस्टिंग" लूप्स कहा जाता है। उदाहरण के लिए, आप किसी मैट्रिक्स के तत्वों पर इटरेट करने के लिए एक for लूप के अंदर दूसरा for लूप उपयोग कर सकते हैं।