Блог Samoedd > Научный Софт > Учимся программировать в R: логические операторы, if else, for и while
Учимся программировать в R: логические операторы, if else, for и while
Создание скриптов и функций в R зачастую требует навыки программирования, а именно: использования логических операторов (например, >= "больше или равно") и управляющих структур (if else, for и while). Благодаря им мы можем задавать условия, при которых будет выполняться то или иное действие, а также определять порядок выполнения действий и их повторяемость.
Другими словами, управляющие структуры автоматизируют процессы анализа данных, прописав возможные сценарии и условия их выполнения. Программирование на языке R позволяет не только уменьшить код скрипта/функции, но и существенно сэкономить время, доверив всю рутинную работу компьютеру.
Логические операторы в R
Операторы в R можно разделить на две категории: арифметические и логические. Арифметическими операторами являются знакомые нам со школы знаки сложения, вычитания, умножения и деления, а также знак возведения в степень и модульные операции (+, -, *, /, ^, %% и %/%, соответственно). Логические операторы обычно используются при проверке условий и выдают значения: TRUE или FALSE.
В языке R существует 9 логических операторов, без знания которых программирование не представляется возможным.
Оператор | Описание |
---|---|
> | Больше |
>= | Больше или равно |
< | Меньше |
<= | Меньше или равно |
== | Равно |
!= | Не равно |
& | Логическое И |
| | Логическое ИЛИ |
! | Логическое НЕ |
Обратите внимание, что "=" и "==" - это два разных оператора: в то время как первый присваивает значение переменной, второй сравнивает их на предмет равенства и выдает результат в виде TRUE или FALSE. Давайте напишем несколько примеров используя логические операторы, чтобы понять как с ними работать.
# Верно ли утверждение, что 11 в третьей степени не равняется 1111? 11^3 != 1111 [1] TRUE # 11 в третьей степени меньше 1111? 11^3 < 1111 [1] FALSE # То есть 11 в третьей степени это 11*11*11 # и оба этих выражения равняются 1331? a = 11^3 b = 11*11*11 a & b == 1331 [1] TRUE
В целом принцип простой: на левой стороне от логического оператора находится "значение/переменная 1", на правой - "значение/переменная 2", в то время, как сам оператор является критерием, по которому R "судит" о правильности утверждения. Если утверждение верно, то в командной строке будет выведено TRUE, если утверждение ложно - FALSE. Следует добавить, что логические операторы работают со всеми типами данных: от векторов до таблиц, что делает их незаменимым инструментом в стат. анализе.
a <- c(1,2,3,5,8,10)
a >= 5
[1] FALSE FALSE FALSE TRUE TRUE TRUE
b <- a[a >= 5]
b
[1] 5 8 10
Теперь мы знаем, что такое логические операторы и готовы к изучению второй части этой статьи - работе с управляющими структурами в R.
Программирование и управляющие структуры
Существует около десятка управляющих структур на которых базируется программирование в R. Среди них можно выделить три наиболее используемые: оператор условий if else и два типа циклов - for и while.
Оператор условий if else используется, когда есть два и более варианта развития сценария: если условие выполняется - "делай это", если не выполняется - "делай то". Суть же циклов в том, что они повторяют одно и то же действие несколько раз: в цикле while действие повторяется пока не выполнится условие цикла, а в цикле for - определенное пользователем количество раз.
На рисунке изображены три вида управляющих структур, где стрелки отображают поток данных. Если условие выполняется (TRUE), то поток данных движется вниз от условия, если нет (FALSE), то вправо и вниз. Как можно заметить в структурах типа while и for при выполнении условия, поток данных циркулирует по кругу: именно по этой причине их и называют циклами. Давайте разберем каждую из этих структур на практике!
Оператор условий if else в R
В языке программирования R оператор условий if else состоит из трех элементов:
- индикатор структуры: if, else или else if (в случае, когда условий больше одного)
- условие структуры, заключенного в круглые скобки (где находится условие для выполнения действия).
- тело структуры, заключенного в фигурные скобки (где находится код самого действия)
Пример 1: покупай больше, плати меньше - if без else
Давайте создадим простейший вариант структуры if else, когда есть только одно условие при соблюдении которого, требуется выполнить дополнительное действие в сценарии. Допустим, в магазине акция: при покупке на сумму от 100$, предоставляется 12.5% скидка. Сколько мы в итоге потратим если наша покупка (x) была на сумму 120$?
x = 120 if(x >= 100){ x = x - x*12.5/100 print(x) } [1] 105
Итак, в скобках находится условие, что общая стоимость покупок будет меняться только в случае, если x >= 100. Внутри фигурных скобок отображен код, иллюстрирующий механизм изменения финальной стоимости. Как Вы видите, индикатор else был не указан в конструкции. Мы его опустили, так как в случае, если x < 100, то никаких действий производиться не будет.
Следует также отметить, что для того, чтобы изменить показатель x, и проверить финальную цену, нам придется запускать весь код конструкции заново. Это непрактично, именно поэтому конструкцию if else чаще всего используют внутри функции. Давайте создадим и запустим функцию с оператором условий if else внутри.
shop <- function(x){ if(x >= 100){ x = x - x*12.5/100 print(x) } } shop(120) [1] 105 shop(50) [1] 50
Пример 2: прогрессивная система скидок - индикатор else if
Добавим второе условие: если сумма покупок больше или равна 1000$, то магазин предоставит 25% скидку. Для этого условия мы будем использовать индикатор else if. В этом случае, нужно также изменить параметры первого условия, где x должно быть больше или равно 100, но меньше 1000. Если же ни первое, ни второе условие не соблюдается, то выведем на экран сообщение "No discounts" после финальной цены при помощи индикатора else.
shop <- function(x){ if(x >= 100 && x < 1000){ x = x - x*12.5/100 print(x) } else if(x >= 1000){ x = x - x*20/100 print(x) } else{ print(c(x, "No discounts")) } } shop(20) [1] 20 "No discounts" shop(200) [1] 175 shop(2000) [1] 1600
Также внутрь оператора условий if else можно вставить другой оператор if else, либо циклы while или for. Подобное свойство вложения управляющих структур позволяет реализовывать сложные многоуровневые сценарии (алгоритмы) на практике, создавая функции с несколькими аргументами, и множеством условий и циклов внутри.
Циклы while и for в R
Ранее мы упоминали, что при неоднократном повторении кода в скрипте следует использовать R функции, чтобы уменьшить размер кода и сделать его более читабельным. Однако, в большинстве ситуаций это будет сделать невозможно без использования циклов внутри функции. Если есть условие, при исполнении которого потребуется повторить действие, используйте цикл while (перевод с англ.: "до тех пор, пока"). Если условия нет, но надо выполнить действие определенное количество раз, воспользуйтесь циклом for.
Пример 3: уникальная методика бега - цикл for
Допустим у нас есть друг который решил заняться бегом. До этого он не бегал и находится в ужасной физической форме: максимум сколько он смог пробежать за первую тренировку - 100 метров. Друг пообещал, что через 100 дней он за тренировку будет пробегать больше 10 км, так как он разработал собственную методику: он будет заниматься ежедневно и прибавлять по 5% к дистанции от предыдущей нагрузки.
Проверим при помощи цикла for сработает ли его методика в теории. Для этого создадим функцию run.10km и переменную y, обозначающую дистанцию тренировки (в км). Внутри круглых скобок цикла for напишем что круг будет повторяться 100 раз, а внутри квадратных код вычислений дистанции для каждого дня. Дистанция последнего дня будет выделена на экран при использовании функции.
run.10km <- function(y){ for(i in 1:100){ y<-y+y*0.05 } print(y) } run.10km(0.1) [1] 13.15013
Оказалось, Ваш друг действительно прав: благодаря этой методике он сможет пробежать через 100 дней более 13 км за тренировку! Теоретически...
Пример 4: может тренироваться реже, но интенсивнее - цикл while
Однако, тренироваться ежедневно без выходных для начинающего - это неминуемый путь к физическому и психическому истощению. Чтобы у друга дни нагрузок чередовались с днями отдыха, давайте предложим ему альтернативную методику: тренироваться через день, но прибавляя к дистанции по 10% от предыдущей нагрузки (вместо 5%).
Рассчитаем, используя цикл while, через сколько дней друг начнет пробегать более 10 км за тренировку и выведем результат в виде таблицы каждая строчка которой отображает день тренировки и предполагаемую дистанцию.
alter.10km <- function(y){ i <- 1 Day <- i Distance <- y while(y <= 10){ i <- i + 2 y<-y+y*0.1 Day <- append(Day,i) Distance <- append(Distance,y) } DF <- data.frame(Day, Distance) return(DF) } results <- alter.10km(0.1) tail(results, 3) Day Distance 48 95 8.819749 49 97 9.701723 50 99 10.671896
Таким образом, наш друг с 99-го дня станет пробегать более 10 км за тренировку занимаясь реже, но интенсивнее! Выглядит, как более реалистичный вариант, но что скажет друг?
Заключение
Сегодня мы использовали простые и наглядные примеры, чтобы понять принцип и суть программирования на языке R. Знания логических операторов и структур управления позволят Вам реализовывать любые идеи в статистическом анализе, не ограничиваясь существующими решениями в R пакетах и интернете. Программирование на R не только экономит Ваше время, но и делает статистический анализ увлекательным и творческим занятием. Дерзайте!
Комментарии: 17
fn4dau
Добрый день!:)
Являются ли необходимыми фигурные скобки в случае, когда цикл или условный оператор содержит только одно выражение? Что говорит об этом стиль программирования на R?
Здравствуйте. Подскажите, пожалуйста, как в R вывести нелинейное уравнение (степенное, логарифмическое, параболу разных порядков и т.д.) и получить значения его коэффициентов и их статистические показатели?
Здравствуйте, Андрей! К сожалению, на сайте я отвечаю в основном на вопросы по темам статей. Однако, кое-что могу сказать: мои коллеги предпочитают работать с уравнениями в Matlab или его бесплатных open-source аналогах (например, Octave). Язык R создан статистиками для статистиков, но и в нем скорее всего это можно сделать мат.моделирование, просто это будет менее удобно, чем в Matlab.
Спасибо за ответ и ценную информацию.
Добрый день! Есть дата фрейм по ковиду по нескольким странам. Хочу проанализировать конкретную страну и вывести его данные на отдельную таблицу. Как это сделать?
Добрый день, Кирилл! Рекомендую прочитать статьи про R на этом или других сайтах и научиться загружать и сохранять таблицы. Подумайте какой именно анализ Вы хотите провести и запустите его в R. Если будут конкретные вопросы с кодом и подробным описанием проблемы, пишите, буду рад помочь.
На данный момент я провожу анализ по ковиду, точнее пытаюсь. Есть данные 14 тыс. людей, заболевших в промежутке с 01.01.2020 по 17.02.2020 из разных стран (около 30). Хочу посмотреть заболеваемость отдельно взятой страны и вывести его на отдельную таблицу, если это возможно. Как мне это сделать? Через логические операторы типа «!=» не получается. К примеру я хочу посмотреть заболеваемость в Китае, сколько мужчин, женщин заболели, возраст инфицированных.
«df_China <- df(df$country != China )» — вот скрипт. Пишет: Ошибка в df(df$country != China) :объект 'China' не найден. Спасибо
Чтобы вывести на отдельную таблицу, просто присвойте ей имя. Также,
"!="
— это «не равно». Если Вы хотите выбрать Китай, то использовать надо"=="
. С текстовыми значениями таблицы не забывайте использовать кавычки: не China, а"China"
. Ваш код должен выглядеть примерно так:new.df < - df[which(df$country == "China")]
Вот ресурс, на котором кратко описано как отбирать данные (я на этом сайте не писал об этом еще), раздел Selecting Observations:
https://www.statmethods.net/management/subset.html
Спасибо! Через ваш код не получилось выбрать наблюдение, но получилось с помощью функции «subset». Подскажите, а как посмотреть среднее число заболевших по всем странам? Через функцию «mean» можно посмотреть только среднее число заболевших по всем странам.
Для этого надо использовать функцию
aggregate
.aggregate(df[, "Название колонки с наблюдениями"], list(df$Country), mean)
Если в таблицу хотите вывести, то просто присвойте имя (например
mean.df
):mean.df < - aggregate(df[, "Название колонки с наблюдениями"], list(df$Country), mean)
Здравствуйте! Спасибо за статью! В примере с else if вы сказали что x должно быть больше или равно 100, но меньше 1000. А в коде нет такого. Второе условие else if у меня не срабатывает.
Здравствуйте, Евгений! Спасибо за замечание, исправил:
Пример 2.
Было: if(x >= 100)
Стало: if(x >= 100 && x < 1000)
Добрый день! А вы ещё работаете в среде R ? Извините за вопрос (возможно наглость) смогли бы вы помочь мне с двумя практическими работами. Благодаря вашим темам 3 штуки я сделала. Спасибо заранее
Добрый день, Татьяна! Спасибо за отзыв. Да, пока еще работаю. Присылайте свои практические работы на почту sergey@samoedd.com
Здравствуйте! Пожскажите, пожалуйста, почему в задаче про бег (for) в конце в скобке стоит 0.1
run.10km(0.1)
[1] 13.15013
Спасибо!)
Здравствуйте, Анастасия!
«Для этого создадим функцию run.10km и переменную y, обозначающую дистанцию тренировки (в км).»
Т.к. друг начинал со 100 метров, а по условию мы договорились, что работаем с километрами, то вводим 0.1 км вместо 100 метров.
Но можно ввести и 100 метров, просто программа тогда выдаст ответ тоже в метрах: на сотый день наш друг пробежит 13150.13 метров;-)