للحلقة في R مع أمثلة للقائمة والمصفوفة

⚡ ملخص ذكي

تُنفّذ حلقة التكرار "for" في لغة R كتلة من التعليمات البرمجية مرة واحدة لكل عنصر من عناصر التسلسل، سواء كان هذا التسلسل متجهًا أو قائمة أو مصفوفة. يشرح هذا الدليل كيفية تكرار كل منها، ويُبيّن متى يكون استخدام التعليمات البرمجية المتجهة هو الخيار الأفضل.

  • 🔁 بناء الجملة الأساسي: تقوم حلقة for (i in vector) { expression } بتعيين كل عنصر إلى i بدوره وتشغيل الجزء الرئيسي من البرنامج.
  • 📋 أي شيء: نفس الصيغة تتنقل بين المتجهات، والقوائم، ومجموعة أعمدة إطار البيانات، أو صفوف المصفوفة.
  • 🧮 الحلقات المتداخلة: تحتاج المصفوفة إلى حلقتين، حلقة خارجية للصفوف وحلقة داخلية للأعمدة.
  • 🛑 التحكم في التدفق: ينهي الأمر break الحلقة بالكامل، بينما يتخطى الأمر next العنصر الحالي فقط.
  • ⚡ التحويل إلى متجه أولاً: تُعد العمليات المتجهة المدمجة وعائلة تطبيق الدوال أسرع وأقصر من حلقة تكرار صريحة.
  • ⚠️ التسلسلات الآمنة: استخدم seq_along(x) بدلاً من 1:length(x)، والذي يتصرف بشكل خاطئ عندما يكون الكائن فارغًا.

حلقة التكرار في مصفوفة قائمة R

A لحلقة يكرر هذا الأمر كتلة من التعليمات البرمجية مرة واحدة لكل عنصر من عناصر التسلسل. يمكن أن يكون هذا التسلسل متجهًا، أو قائمة، أو إطار بيانات، أو مصفوفة، أو أي كائن آخر يمكن لـ R التكرار عليه. R حساسة لحالة الأحرف، لذا فإن الكلمة المفتاحية تكون دائمًا بأحرف صغيرة. لـوتكون الأقواس المعقوفة مطلوبة كلما امتد الجسم على أكثر من سطر واحد.

صيغة حلقة التكرار "for" في لغة R

for (i in vector) {
    Exp
}

هنا،

R سوف يتكرر فوق جميع المتغيرات في المتجه ويقوم بالحساب المكتوب داخل EXP.

للحلقة في R
للحلقة في R

دعونا نرى بعض الأمثلة.

للحلقة في R مثال 1: نكرر جميع عناصر المتجه ونطبع القيمة الحالية.

# Create fruit vector
fruit <- c('Apple', 'Orange', 'Passion fruit', 'Banana')
# Create the for statement
for ( i in fruit){ 
 print(i)
}

الإخراج:

## [1] "Apple"
## [1] "Orange"
## [1] "Passion fruit"
## [1] "Banana"

للحلقة في R مثال 2: قم بتربيع كل عدد صحيح من 1 إلى 4 وقم بتخزين النتائج في قائمة.

# Create an empty list
list <- c()
# Create a for statement to populate the list
for (i in seq(1, 4, by=1)) {
  list[[i]] <- i*i
}
print(list)

الإخراج:

## [1]   1  4 9 16

تُعدّ حلقات التكرار مفيدة في مجال التعلّم الآلي. ضبط مُعامل التنظيم يعني اختبار العديد من القيم المُرشّحة والاحتفاظ بها.ping الدالة التي تقلل من دالة الخسارة، وحلقة التكرار هي الطريقة المباشرة لمسح هذا النطاق.

كيفية استخدام break و next في حلقة for

كلمتان مفتاحيتان تقاطعان التسلسل الطبيعي لحلقة for.

  • استراحة يخرج من الحلقة فوراً ويتخطى كل عنصر متبقٍ.
  • التالي يتخلى عن العنصر الحالي فقط وينتقل إلى العنصر التالي.
fruit <- c('Apple', 'Orange', 'Passion fruit', 'Banana')

# break: stop at the first match
for (i in fruit) {
    if (i == 'Passion fruit') {
        print('Found it, stopping here')
        break
    }
    print(i)
}

# next: skip one element and carry on
for (i in fruit) {
    if (i == 'Orange') next
    print(i)
}

في الحلقات المتداخلة، تعمل عبارتا break و next فقط على الحلقة الداخلية التي تحتويهما. ولإخراج كلتا الحلقتين من مثال المصفوفة، قم بتعيين متغير علامة واختبره في الحلقة الخارجية أيضًا.

استخدم الدالة seq_along() للفهارس. كتابة حلقة التكرار (for (i in 1:length(x)) تبدو غير ضارة، لكنها تفشل مع كائن فارغ، لأن 1:0 ينتج التسلسل 1، 0، وبالتالي يتم تنفيذ الحلقة مرتين. أما دالة seq_along(x) فتعيد تسلسلًا فارغًا، لذا يتم تخطي الحلقة بشكل صحيح.

for (i in seq_along(fruit)) {
    cat(i, fruit[i], '\n')
}

حلقة تكرارية على قائمة

مرحاضping يعمل الأمر على قائمة تمامًا مثل المرحاضping على متجه، باستثناء أن كل عنصر يمكن أن يحمل نوعًا مختلفًا:

# Create a list with three vectors
fruit <- list(Basket = c('Apple', 'Orange', 'Passion fruit', 'Banana'), 
Money = c(10, 12, 15), purchase = FALSE)
for (p  in fruit) 
{ 
	print(p)
}

الإخراج:

## [1] "Apple" "Orange" "Passion fruit" "Banana"       
## [1] 10 12 15
## [1] FALSE

حلقة تكرارية على مصفوفة

تحتوي المصفوفة على بعدين، الصفوف والأعمدة، لذا فإن التكرار على كل خلية يتطلب حلقتين متداخلتين: حلقة خارجية للصفوف وحلقة داخلية للأعمدة.

# Create a matrix
mat <- matrix(data = seq(10, 20, by=1), nrow = 6, ncol =2)
# Create the loop with r and c to iterate over the matrix
for (r in 1:nrow(mat))   
    for (c in 1:ncol(mat))  
         print(paste("Row", r, "and column",c, "have values of", mat[r,c]))  

الإخراج:

## [1] "Row 1 and column 1 have values of 10"
## [1] "Row 1 and column 2 have values of 16"
## [1] "Row 2 and column 1 have values of 11"
## [1] "Row 2 and column 2 have values of 17"
## [1] "Row 3 and column 1 have values of 12"
## [1] "Row 3 and column 2 have values of 18"
## [1] "Row 4 and column 1 have values of 13"
## [1] "Row 4 and column 2 have values of 19"
## [1] "Row 5 and column 1 have values of 14"
## [1] "Row 5 and column 2 have values of 20"
## [1] "Row 6 and column 1 have values of 15"
## [1] "Row 6 and column 2 have values of 10" 

حلقة تكرارية على إطار بيانات في لغة R

إطار البيانات عبارة عن قائمة من الأعمدة، لذا فإن حلقة التكرار العادية تتنقل بين أعمدته بدلاً من صفوفه. وهذا هو المطلوب عادةً.

df <- data.frame(a = 1:5, b = 6:10, c = 11:15)

# Loop over the columns
for (col in names(df)) {
    cat(col, 'has mean', mean(df[[col]]), '\n')
}

لاحظ القوس المزدوج. df[[col]] extracts العمود كمتجه، بينما df[col] تُرجع إطار بيانات من عمود واحد لا يمكن لـ mean() التعامل معه.

مرحاضping على صفوف. التكرار على مستوى الصفوف ممكن ولكنه بطيء، لأن برنامج R ينسخ الصف في كل تمريرة:

for (r in seq_len(nrow(df))) {
    cat('Row', r, 'sums to', sum(df[r, ]), '\n')
}

لأي شيء يتجاوز بضعة آلاف من الصفوف، يُفضل استخدام rowSums(df) أو apply(df, 1, sum) أو dplyr group_by() و summarise() خط الأنابيب، وكلها تقوم بنفس العمل دون الحاجة إلى النسخ.

مقارنة بين حلقات التكرار (for Loops) والتحويل إلى متجهات (Vectorization) في لغة R

لغة R هي لغة متجهة: فمعظم عواملها ووظائفها تعمل بالفعل على متجهات كاملة دفعة واحدة، في كود C المُترجم. أما الحلقة الصريحة التي تُكرر عملية متجهة عنصرًا بعنصر فهي أطول وأبطأ.

# Loop version
squares <- c()
for (i in 1:4) {
    squares[i] <- i * i
}

# Vectorized version, same result
squares <- (1:4)^2
مهمة أنشوطة المكافئ المتجهي
الحساب العنصري لكل عنصر x * 2، x + y، x^2
قم بتطبيق دالة لكل عمود for over names(df) sapply(df, mean)
قم بتطبيق دالة لكل صف for over seq_len(nrow(df)) تطبيق(df, 1, sum)
أنشئ قائمة بالنتائج for with list[[i]] <- … تطبيق(v, f)
إعادة التسجيل المشروط مع شرط if و else ifelse(cond, a, b)

عندما تكون الحلقة هي الحل الصحيح. احتفظ بحلقة for عندما تعتمد كل تكرار على النتيجة السابقة، أو عندما تقوم باستدعاء خدمة خارجية أو كتابة ملفات، أو عندما تكون الوضوح أهم من السرعة في كائن صغير.

إذا كان لا بد من استخدام حلقة تكرارية، فقم بتخصيص الذاكرة مسبقًا. يؤدي تكبير كائن داخل حلقة تكرارية إلى إجبار لغة R على نسخه في كل دورة. أنشئه بالحجم الكامل أولاً:

# Slow: the vector is reallocated on every pass
out <- c()
for (i in 1:1000) out[i] <- i^2

# Fast: allocated once
out <- numeric(1000)
for (i in 1:1000) out[i] <- i^2

حلقة التكرار For في لغة R: مرجع سريع

جميع العناصر المستخدمة في هذا الدرس التعليمي مدرجة أدناه:

الهدف Code
قم بالتكرار على متجه
for (i in v) { print(i) }
قم بالتكرار على الفهارس بأمان
for (i in seq_along(v)) { print(v[i]) }
تكرار قائمة
for (p in my_list) { print(p) }
قم بالتكرار على أعمدة إطار البيانات
for (col in names(df)) { print(mean(df[[col]])) }
تكرار العملية على مصفوفة
for (r in 1:nrow(m)) for (c in 1:ncol(m)) print(m[r, c])
الخروج من الحلقة مبكراً
if (condition) break
تخطي تكرار واحد
if (condition) next
قم بتخصيص المخرجات مسبقًا
out <- numeric(n)

الأسئلة الشائعة

عندما تكون x فارغة، تُعيد الدالة 1:length(x) التسلسل 1، 0، وتُنفَّذ الحلقة مرتين على العناصر غير الموجودة. أما الدالة seq_along(x) فتُعيد تسلسلًا فارغًا، لذا يتم تخطي الحلقة بشكل صحيح.

ليست الحلقة نفسها هي المشكلة، بل المشكلة تكمن في توسيع الكائن داخلها، لأن لغة R تنسخ الكائن بأكمله في كل دورة. لذا، يُنصح بتخصيص الذاكرة مسبقًا للنتيجة، أو استخدام دالة متجهة، وسيختفي هذا الخلل إلى حد كبير.

الأعمدة. إطار البيانات عبارة عن قائمة من الأعمدة، لذا فإن كل تكرار يُعيد إليك عمودًا كاملاً. استخدم الدالة seq_len(nrow(df)) صراحةً إذا كنت بحاجة إلى المرور على الصفوف بدلاً من ذلك.

تُستخدم حلقات التكرار (for loops) في عمليات مسح المعلمات الفائقة، وطيات التحقق المتبادل، وفترات التدريب. لكل منها عدد تكرارات معروف، وهو بالضبط ما صُممت بنية حلقة التكرار (for) لأجله.

نعم. يمكن للمساعدين المدعومين بالذكاء الاصطناعي تحويل معظم الحلقات التي تعمل على مستوى العناصر إلى ما يعادلها من متجهات أو دوال تطبيقية. قارن مخرجات النسختين باستخدام الدالة `individual()` قبل استبدال النسخة الأصلية.

تلخيص هذه التدوينة بـ: