Menu

Операторы R: арифметические, сравнения, логические, %in% и %%

Все нужные операторы R — арифметические, включая %% и %/%, векторные сравнения, различие между & и && и %in% для проверки вхождения.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Какие операторы даёт R

Операторы R распадаются на четыре рабочие группы: арифметические (+ - * / ^ %% %/%), сравнения (== != < <= > >=), логические (& | && || ! xor) и проверка вхождения %in%. Две вещи отличают их от большинства языков: почти все они векторизованы — работают сразу над целыми векторами, поэлементно, — и в R есть два оператора И и два оператора ИЛИ, которые не взаимозаменяемы. Эта страница разбирает все из них, а также ловушки приоритета, дающие тихо неверные ответы.

Арифметика: +, -, *, /, ^, %% и %/%

Первые пять делают то, что вы ожидаете. Два оператора в процентах — %% (остаток) и %/% (целочисленное деление, частное) — это как раз то, что люди ищут:

Обратите внимание, что / всегда выполняет деление с плавающей точкой — 17 / 5 это 3.4, никогда не 3. Если нужна целая часть, для этого и существует %/%.

Повседневная работа %% — делимость. Число чётное, когда деление на 2 не даёт остатка:

На второй строке стоит остановиться: с отрицательным операндом %% в R возвращает результат со знаком делителя (-7 %% 3 это 2, потому что -7 = -3 * 3 + 2). В некоторых языках сделано наоборот; если переносите код, проверьте.

Операторы сравнения векторизованы

==, !=, <, <=, >, >= сравнивают поэлементно и возвращают логический вектор, а не один ответ:

Это движок почти всей фильтрации в R — вы сравниваете целый вектор со значением, получаете логическую маску и используете маску для выборки. Одно предостережение насчёт == для дробных чисел: числа с плавающей точкой хранятся приближённо, поэтому 0.1 + 0.2 == 0.3 даёт FALSE. Для сравнения дробей предпочитайте all.equal() или проверяйте abs(x - y) < 1e-9.

Логические операторы: & против && (классическая путаница)

В R два оператора И и два оператора ИЛИ, и выбор неправильного — обряд посвящения.

& и | векторизованы. Они комбинируют два логических вектора поэлементно:

Используйте их всякий раз, когда строите фильтр по данным: df[df$age > 30 & df$city == "Lisbon", ].

&& и || скалярны и используют сокращённое вычисление. Они принимают одиночные значения, возвращают один TRUE/FALSE и полностью пропускают второй операнд, если первый уже определяет ответ:

Вторая строка демонстрирует сокращённое вычисление: поскольку x < 0 даёт FALSE, R никогда не вычисляет вызов stop(). Именно поэтому && уместен в условиях if() — вы можете написать if (!is.na(x) && x > 10), и часть x > 10 безопасно пропускается, когда x равно NA.

Правило большого пальца: &/| — для векторов и фильтрации данных, &&/|| — для условий if(). И начиная с R 4.3 это подкреплено зубами: передача в && или || вектора длиннее 1 — ошибка (старые версии R молча брали только первый элемент, что годами скрывало настоящие баги).

xor(a, b) дополняет набор — TRUE, когда ровно одно из двух истинно:

%in%: проверка вхождения

x %in% table спрашивает для каждого элемента x: «встречается ли он где-нибудь в table?» Это один из самых используемых операторов в реальном коде на R:

Проверяемая сторона может быть целым вектором, что делает %in% естественным инструментом фильтрации строк по набору допустимых значений.

Он также выигрывает у альтернативы, которую иначе пришлось бы писать, — цепочки ==, склеенной через |:

С пятью допустимыми значениями цепочка == превращается в стену повторов; версия с %in% просто наращивает вектор. Есть и второе, более тонкое преимущество — %in% никогда не возвращает NA:

NA == 1 даёт NA, потому что R не может знать, равно ли неизвестное значение единице, — это поведение подробно разобрано в статье про пропущенные значения. Затем этот NA отравляет любой if(), до которого доберётся. %in% обходит проблему целиком, всегда отвечая TRUE или FALSE, — поэтому он безопаснее для условий над возможно пропущенными данными.

Ловушки приоритета

Две ловушки приоритета операторов дают непропорционально большую долю моментов «R сломан». Первая: ^ связывает сильнее унарного минуса:

Вторая: двоеточие связывает сильнее бинарной арифметики:

Сомневаетесь — ставьте скобки. Они ничего не стоят, и каждый читатель (включая вас в будущем) разберёт их так же, как интерпретатор.

$ и [ ]: операторы доступа

Вы также будете постоянно видеть $, [ ] и [[ ]] — формально это тоже операторы, применяемые для извлечения значений из структур, а не для вычислений:

Они подробно разобраны на страницах про векторы, списки и датафреймы — здесь достаточно узнавать их как членов того же семейства операторов.

Что вы уносите с собой

  • %% даёт остаток, %/% — целую часть частного; x %% 2 == 0 проверяет чётность.
  • Сравнения векторизованы — они возвращают логический вектор, которым можно фильтровать.
  • &/| комбинируют векторы поэлементно; &&/|| — для одиночных значений в if() и с сокращённым вычислением. Начиная с R 4.3, && на векторе длиннее 1 — ошибка.
  • x %in% table заменяет цепочки == и никогда не возвращает NA.
  • -2^2 это -4, а 1:n - 1 начинается с 0 — сомневаетесь, ставьте скобки.

Дальше: как заставить эти операторы работать внутри if, else и ifelse() — условных конструкций R.

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

Что делает %% в R?

%% — оператор взятия остатка: он возвращает остаток от деления. 17 %% 5 это 2. Его напарник %/% выполняет целочисленное деление и возвращает частное без остатка: 17 %/% 5 это 3. Классическое применение %% — проверка на чётность: x %% 2 == 0.

В чём разница между & и && в R?

& векторизован: он сравнивает два вектора поэлементно и возвращает вектор той же длины. && работает только с одиночными значениями, использует сокращённое вычисление (пропускает второй операнд, если первый уже определяет результат) и возвращает ровно один TRUE или FALSE. Используйте & при фильтрации векторов и && внутри условий if(). Начиная с R 4.3, передача в && или || вектора длиннее 1 — ошибка, а не предупреждение.

Что делает %in% в R?

x %in% table проверяет, встречается ли каждый элемент x где-либо в table, возвращая TRUE или FALSE для каждого элемента. "mango" %in% basket заменяет цепочку сравнений ==, соединённых через |, и, в отличие от ==, никогда не возвращает NA — пропущенное значение с проверяемой стороны просто даёт FALSE.

Почему -2^2 возвращает -4 в R?

Потому что ^ связывает сильнее унарного минуса, и R читает -2^2 как -(2^2), то есть -4. Если вы имеете в виду квадрат минус двух, пишите (-2)^2, что даёт 4. У двоеточия похожая ловушка: 1:n - 1 означает (1:n) - 1, а не 1:(n - 1).

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ