Цикл For у R із прикладами для списку та матриці

⚡ Розумний підсумок

Цикл For в R виконує блок коду один раз для кожного елемента послідовності, незалежно від того, чи є ця послідовність вектором, списком чи матрицею. Цей покроковий посібник ітерує по кожному з них і показує, коли векторизований код є кращим вибором.

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

Цикл For у матриці списку R

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)
}

У вкладених циклах, break та next діють лише на найвнутрішній цикл, який їх містить. Щоб залишити обидва цикли в матричному прикладі, встановіть змінну flag та перевірте її також у зовнішньому циклі.

Використовуйте seq_along() для індексів. Запис for (i в 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

Фрейм даних – це список стовпців, тому звичайний цикл 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]] 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() та summarize() конвеєр, усі з яких виконують ту саму роботу без копіювання.

Цикли 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
Завдання Петля Векторизований еквівалент
Поелементна арифметика для кожного елемента x * 2, x + y, x^2
Застосування функції для кожного стовпця для назв (df) саплі(df, середнє)
Застосування функції для кожного рядка для понад seq_len(nrow(df)) застосувати(df, 1, сума)
Створіть список результатів для зі списком[[i]] <- … lapply(v, f)
Умовне перекодування для з if та else якщо(умовність, 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 керують гіперпараметричними скануваннями, перехресними перевірками згортання та епохами навчання. Кожна з них має відому кількість ітерацій, саме для цього і призначена конструкція for.

Так. Помічники ШІ можуть конвертувати більшість поелементних циклів у векторизовані або еквіваленти застосовної родини. Порівняйте вивід обох версій за допомогою identique() перед заміною оригіналу.

Підсумуйте цей пост за допомогою: