Фильтрация строк: логическая маска
Чтобы отфильтровать датафрейм в R, поместите условие в позицию строк внутри скобок: df[condition, ]. Условие вычисляется в вектор TRUE/FALSE, по одному значению на строку, и R оставляет строки с TRUE:
Читайте scores[scores$score > 80, ] изнутри наружу: scores$score > 80 даёт TRUE FALSE TRUE TRUE FALSE, и скобки оставляют строки 1, 3 и 4. Запятая в конце не опциональна. Скобки у датафрейма принимают [строки, столбцы]; пустой слот столбцов означает «все столбцы». Забудете запятую — и вы индексируете столбцы, а не строки: одна из самых частых ошибок новичков в R.
Обратите внимание, что напечатанные номера строк — 1 3 4, а не 1 2 3: фильтрация сохраняет исходные метки строк. Это безобидно, но людей удивляет.
Несколько условий: & и | (не &&)
Соединяйте условия через & (И) и | (ИЛИ). Каждому условию — своё полное сравнение:
Ловушка: в R есть ещё && и ||, и здесь они не взаимозаменяемы с & и |. Двойные формы работают с одиночными значениями (они существуют для условий if); получив целые столбцы, современный R (4.3+) останавливается с ошибкой вида 'length = 5' in coercion to 'logical(1)', а старый R молча сравнивал только первую строку — что, пожалуй, ещё хуже. Внутри скобок — всегда одиночные & и |. Разница полностью разобрана в статье про операторы.
%in%: сравнение с набором значений
Когда столбец должен совпадать с любым из нескольких значений, не сцепляйте == через | — используйте %in%:
x %in% set возвращает TRUE там, где x равен одному из значений в set. Это читается лучше, чем status == "pending" | status == "shipped", масштабируется на любое число значений и аккуратно отрицается: !(orders$status %in% c("refunded")).
Выбор столбцов
Слот столбцов в скобках принимает имена или позиции:
Два замечания. Выбор по имени переживает перестановку столбцов; выбор по позиции (scores[, c(1, 3)]) ломается в тот день, когда кто-то вставит новый столбец. А запрос одного столбца возвращает обычный вектор, а не датафрейм — поэтому второй print() показывает 91 88 без таблицы вокруг. Когда нужно сохранить форму датафрейма, добавьте drop = FALSE: scores[, "score", drop = FALSE].
subset(): дружелюбный однострочник базового R
Базовый R поставляется с обёрткой, которая обрабатывает строки и столбцы одним читаемым вызовом — без $ и без бухгалтерии запятых:
Внутри subset() вы пишете голые имена столбцов (score, а не scores$score) — они вычисляются относительно датафрейма. Это называется нестандартным вычислением, и у него есть задокументированная оговорка: имена разрешаются во время выполнения так, что внутри ваших собственных функций это может вести себя неправильно (переменную score в вашей функции может затенить столбец с именем score). Правило из ?subset: отлично в интерактивной работе, избегайте в программировании — там используйте индексацию скобками.
Ловушка NA
Сравнение с NA даёт NA, а не FALSE, — и фильтрация скобками оставляет строки с NA в маске как строки, целиком заполненные NA:
Первый результат содержит мусорную строку из NA, потому что условие для строки 2 не было ни TRUE, ни FALSE. Решение — явно потребовать !is.na(). И subset(), и filter() из dplyr молча отбрасывают строки с условием NA — удобно, но знайте, что это происходит. Почему NA так распространяется, объясняет статья про пропущенные значения.
Способ dplyr: filter() и select()
Пакет dplyr разбивает задачу на два глагола — filter() для строк, select() для столбцов — с голыми именами столбцов и без повторения df$ (статично; песочница выполняет только базовый R):
library(dplyr)
scores |> filter(score > 80)
scores |> filter(score > 80, team == "red") # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)
filter() автоматически отбрасывает строки с условием NA и всегда возвращает датафрейм (никогда — голый вектор), что снимает обе базовые ловушки выше. Плата — зависимость от пакета и те же оговорки нестандартного вычисления, что у subset(); полный обзор глаголов — во введении в dplyr.
Что вы уносите с собой
df[condition, ]— фундаментальная идиома, и запятая обязательна.- Соединяйте условия одиночными
&и|;&&на векторах даёт ошибку. %in%лучше цепочки==для сравнения с набором значений.- Выбирайте столбцы по имени и помните: одиночный столбец сваливается в вектор, если не указать
drop = FALSE. subset()— приятный интерактивный однострочник; скобки — программируемый вариант.- Сравнения с
NAпорождают строки-призраки в скобках — защищайтесь через!is.na().
Дальше: добавление и преобразование столбцов — df$new <- ..., ifelse() и mutate() из dplyr.
Часто задаваемые вопросы
Как отфильтровать строки датафрейма в R?
Поместите логическое условие в позицию строк внутри скобок: df[df$score > 80, ]. Условие даёт вектор TRUE/FALSE, и R оставляет строки с TRUE. Запятая важна — она отделяет фильтр строк от (пустого) фильтра столбцов. subset(df, score > 80) делает то же самое короче.
Как фильтровать по нескольким условиям в R?
Соединяйте условия через & (И) и | (ИЛИ): df[df$score > 80 & df$team == "red", ]. Используйте одиночный &, а не && — двойная форма работает только с одиночными значениями и в современном R выдаёт ошибку на векторах.
В чём разница между subset() и фильтрацией скобками в R?
Они оставляют одни и те же строки, но есть два отличия: subset() молча отбрасывает строки, где условие равно NA (скобки оставляют их как строки, заполненные NA), и subset() использует нестандартное вычисление — вы пишете голые имена столбцов, что удобно в интерактивной работе, но ненадёжно внутри собственных функций.
Как отфильтровать строки, где столбец совпадает со списком значений?
Используйте %in%: df[df$team %in% c("red", "blue"), ] оставляет строки, где team равен любому из перечисленных значений. Это заменяет цепочку сравнений ==, соединённых через |, и, в отличие от ==, никогда не возвращает NA.