for
Для того, чтобы в R осуществлял различные действия в зависимости от того, выполняется ли определенное условие или нет, понадобятся операторы условия: if
и else
. Например, мы сохраняем в R оценку по курсу и хотим, чтобы он выводил на экран “Good!” и “You are genius!!!”, если она больше или равна 5 и “Bad!” — во всех остальных случаях.
mark <- 2
if (mark >= 5){
print("Good!")
print("You are genius!!!")
}else{
print("Bad.")
}
## [1] "Bad."
Само условие записывается в круглых скобках, а то, что R должен сделать в случае, если условие выполняется, перечисляется в фигурных скобках. Логика работы конструкции if-else ничем не отличается от Python, просто в R другой синтаксис, который требует наличие скобок вместо отступов. Если мы не поставим фигурные скобки, R не поймет, что все строки выше, начиная с print("Good!")
и заканчивая print("Bad.")
, относятся к одному блоку кода, который нужно запускать сразу.
Если в случае выполнения условия R должен сделать что-то, что умещается в одну строчку кода, фигурные скобки можно опустить (и вообще все записать в одну строчку):
if (mark >= 5) print("Good.") else print("Bad.")
## [1] "Bad."
Если необходимо применить несложную конcтрукцию if-else к каждому элементу вектора, можно воспользоваться функцией ifelse()
. Сохраним вектор оценок grades
и на его основе создадим вектор grades_binary
, где 1 будет соответствовать оценкам выше 3, а 0 — всем остальным оценкам.
grades <- c(5, 7, 3, 4, 10, 8)
grades_binary <- ifelse(grades > 3, 1, 0)
grades_binary
## [1] 1 1 0 1 1 1
В функции ifelse()
на первом месте указывается условие, на втором — значение, которое должно возвращаться, если условие выполняется, на третьем — значение, которое должно возвращаться, если условие не выполняется.
Иногда мы сталкиваемся с необходимостью использовать множественные условия, например, какие-то два условия должны выполняться одновременно. Для этого потребуются те же символы, которые используются в логических выражениях (&
и |
). Напишем код, который будет выдавать разные комментарии по оценке в 10-балльной шкале:
mark <- 12
if (mark < 4) print("Bad.") else{
if (mark >= 4 & mark < 6) print("Not bad.")
if (mark >= 6 & mark < 8) print("Good.")
if (mark >= 8 & mark <= 10) print("Excellent.")
if (mark > 10) print("We are the champions, my friend...")
}
## [1] "We are the champions, my friend..."
Примечание: конечно, здесь можно было бы обойтись и без вложенной конструкции if-else, но мы немного усложнили код, чтобы еще раз потренироваться с постановкой различного вида скобок.
А вот пример с оператором |
, ситуация, когда мы выводим на экран “Excellent”, если оценка или 8, или 9, или 10:
if (mark == 8 | mark == 9 | mark == 10) print("Excellent")
Как можно заметить, так же, как и в Python, часть с else
в условной конструкции здесь тоже является необязательной.
Интересное отличие R от Python заключается в том, что здесь есть базовая функция, которая отвечает за логическую операцию XOR, исключающее «или». В то время как оператор |
возвращает значение True
, если хотя бы одно из условий верно, функция xor()
возвращает значение True
, если ровно одно из условий верно.
Сравним:
# оба условия верны —> хотя бы одно верно —> True
3 < 5 | 7 < 9
## [1] TRUE
# оба условия верны —> неверно, что верно только одно —> False
xor(3 < 5, 7 < 9)
## [1] FALSE
А вот в случае, когда только одно из условий верно, xor()
вернет True
:
xor(3 < 5, 7 > 9)
## [1] TRUE
for
Чтобы повторять действия в R и при этом не копировать один и тот же код много раз, используются циклы. Существует два основных цикла: цикл for
и цикл while
. На практике чаще используется цикл for
, потому что цикл while
более специфический и более медленный (и программу с while
очень легко зациклить).
Стоит также отметить, что для выполнения стандартных задач в рамках анализа данных в R циклы используются нечасто, так как в R многие операции векторизованы — функции применяются сразу к наборам значений, например, к векторам.
# не нужно проходить по вектору x и возводить каждый элемент в квадрат
x <- c(1, 2, 3, 8)
x ** 2
## [1] 1 4 9 64
Смысл цикла for
: «для каждого элемента в наборе (векторе) сделай что-то». У нас есть вектор v и мы хотим вывести его элементы на экран:
v <- c(0, 1, NA, 0, 1)
for (i in v){
print(i)
}
## [1] 0
## [1] 1
## [1] NA
## [1] 0
## [1] 1
То, по чему итерируем (пробегаемся), указывается в круглых скобках, а то, что делаем в ходе цикла — в фигурных.
Для перебора можно задействовать последовательности:
for (n in 1:10){
print(n)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
А теперь совместим цикл и условные конструкции. Вспомним про вектор оценок grades
:
grades
## [1] 5 7 3 4 10 8
Выведем краткий комментарий на каждую из оценок:
for (g in grades){
if (g > 3) print("Pass")
if (g <= 3) print("Fail")
}
## [1] "Pass"
## [1] "Pass"
## [1] "Fail"
## [1] "Pass"
## [1] "Pass"
## [1] "Pass"