Цикл For в R с примерами для списка и матрицы

⚡ Умное резюме

Цикл `for` в R выполняет блок кода один раз для каждого элемента последовательности, будь то вектор, список или матрица. В этом пошаговом руководстве рассматривается каждый из этих случаев и показано, когда векторизованный код является лучшим выбором.

  • 🔁 Основной синтаксис: for (i in vector) { expression } присваивает каждому элементу i по очереди и выполняет тело цикла.
  • 📋 Любой объект: Один и тот же синтаксис используется для обхода вектора, списка, набора столбцов фрейма данных или строк матрицы.
  • 🧮 Вложенные циклы: Для построения матрицы необходимы два цикла: внешний для строк и внутренний для столбцов.
  • 🛑 Управление потоком: Оператор break полностью прерывает цикл, а оператор next пропускает только текущий элемент.
  • Векторизация прежде всего: Встроенные векторизованные операции и семейство методов apply работают быстрее и короче, чем явный цикл.
  • ⚠️ Безопасные последовательности: Используйте seq_along(x) вместо 1:length(x), так как это приводит к некорректной работе, если объект пуст.

Цикл for в R List Matrix

A для цикла Эта команда повторяет блок кода один раз для каждого элемента последовательности. Эта последовательность может быть вектором, списком, фреймом данных, матрицей или любым другим объектом, по которому может выполняться итерация в R. R чувствителен к регистру, поэтому ключевое слово всегда пишется строчными буквами. дляФигурные скобки необходимы всякий раз, когда основной текст занимает более одной строки.

Синтаксис цикла for в R

for (i in vector) {
    Exp
}

Здесь,

R будет перебирать все переменные в векторе и выполнять вычисления, записанные внутри exp.

Цикл for в R
Цикл for в R

Давайте посмотрим несколько примеров.

Цикл For в 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"

Цикл For в 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

Циклы for полезны в работе с машинным обучением. Настройка параметра регуляризации подразумевает тестирование множества возможных значений и поддержаниеping Тот, который минимизирует функцию потерь, и цикл for — это простой способ пройтись по этому диапазону.

Как использовать операторы 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)
}

Вложенные циклы прерывания и последующие действия применяются только к самому внутреннему циклу, который их содержит. Чтобы оставить оба цикла в примере с матрицей, установите флаговую переменную и проверьте её также во внешнем цикле.

Для индексов используйте функцию 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')
}

Цикл for по списку

Туалет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

Цикл for по матрице

Матрица имеет два измерения: строки и столбцы, поэтому для перебора каждой ячейки требуется два вложенных цикла for: внешний для строк и внутренний для столбцов.

# 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" 

Цикл for по фрейму данных в R

DataFrame представляет собой список столбцов, поэтому обычный цикл for проходит по столбцам, а не по строкам. Обычно это именно то, что вам нужно:

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]] extracФункция `df[col]` возвращает столбец в виде вектора, тогда как `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 против векторизации в R

R — векторизованный язык: большинство его операторов и функций уже работают с целыми векторами сразу в скомпилированном коде C. Явный цикл, повторяющий векторизованную операцию поэлементно, будет и длиннее, и медленнее.

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

# Vectorized version, same result
squares <- (1:4)^2
Сложность задачи Loop Векторизованный эквивалент
Поэлементная арифметика для каждого элемента x * 2, x + y, x^2
Примените функцию к каждому столбцу. для всех имен (df) sapply(df, mean)
Примените функцию к каждой строке. for over seq_len(nrow(df)) apply(df, 1, sum)
Составьте список результатов для списка[[i]] <- … lapply(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)

Часто задаваемые вопросы (FAQ)

Когда x пуст, 1:length(x) возвращает последовательность 1, 0, и цикл выполняется дважды для несуществующих элементов. seq_along(x) возвращает пустую последовательность, поэтому цикл корректно пропускается.

Сам цикл не является проблемой. Проблема заключается в наращивании объекта внутри него, поскольку R копирует весь объект при каждом проходе. Предварительное выделение памяти для результата или использование векторизованной функции в значительной степени устраняют эту проблему.

Столбцы. DataFrame представляет собой список столбцов, поэтому каждая итерация возвращает вам один целый столбец. Используйте seq_len(nrow(df)) явно, если вам нужно пройтись по строкам.

Циклы for управляют перебором гиперпараметров, перекрестной проверкой и эпохами обучения. Для каждого из этих процессов известно количество итераций, что как раз и является целью конструкции for.

Да. Искусственный интеллект может преобразовывать большинство поэлементных циклов в векторизованные или эквивалентные конструкции с использованием семейства функций apply. Сравните вывод обеих версий с помощью функции identical() перед заменой исходного результата.

Подведем итог этой публикации следующим образом: