Menu

Фильтрация и выборка данных в R (subset, [ ], dplyr filter)

Все способы оставить нужные строки и столбцы: логические маски со скобками, однострочник subset(), %in%, ловушки NA и filter() с select() из dplyr.

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

Фильтрация строк: логическая маска

Чтобы отфильтровать датафрейм в 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.

Coddy programming languages illustration

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

НАЧАТЬ