Menu

Добавление и преобразование столбцов в R (mutate и базовый R)

Как добавлять, преобразовывать и удалять столбцы датафрейма: df$new <- ..., ifelse() для условных столбцов, transform() и mutate() из dplyr с case_when().

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

Добавление столбца: df$new <- value

Чтобы добавить столбец в базовом R, присвойте значение имени, которого ещё нет. Значение обычно вычисляется из существующих столбцов:

Произошло две вещи. orders$total получил полный вектор — price * qty вычисляется для всех строк сразу, потому что арифметика в R векторизована. orders$currency получил одиночное значение, которое R растиражировал на все четыре строки. Любая другая длина — ошибка (replacement has 3 rows, data has 4): так R защищает вас от рассинхронизированного столбца.

Это работает потому, что датафрейм — это список столбцов равной длины: присваивание нового именованного элемента наращивает список. Эта модель разобрана в статье про датафреймы.

Условные столбцы: ifelse()

Столбцу, значение которого зависит от условия, нужен ifelse()векторизованный родственник if. Он принимает целый вектор условий и возвращает значение для каждой строки:

Почему не обычный if? Потому что if вычисляет ровно одно TRUE/FALSE — получив столбец, он выдаёт ошибку (the condition has length > 1). ifelse(test, yes, no) проверяет каждый элемент и выбирает построчно. Для трёх и более исходов можно вкладывать:

Вложенность в два уровня — нормально; три и больше превращаются в пирамиду — ровно для этой работы и создан case_when() из dplyr (ниже). Сам одиночный if/else разобран в статье про if-else.

Несколько столбцов сразу: transform()

transform() из базового R добавляет несколько столбцов одним вызовом, с голыми именами столбцов:

Обратите внимание: transform() возвращает новый датафрейм — результат нужно присвоить обратно, тогда как df$new <- ... изменяет на месте. Одно ограничение: выражения внутри одного вызова transform() не видят друг друга, поэтому discount = ifelse(total > 50, ...) там не сработает (total ещё не существует). Делайте в два шага — или через mutate(), который это разрешает.

Изменение против создания

Тот же синтаксис присваивания перезаписывает существующий столбец — единственная разница в том, существовал ли столбец раньше:

На этом стоит задержаться: R никак не предупреждает, когда вы перезаписываете столбец. Опечатка вроде df$prise <- round(df$price, 2) молча создаёт новый столбец вместо исправления старого. После преобразования выведите датафрейм через print() или str() и убедитесь, что изменили именно то, что хотели.

Удаление столбца

Присвойте NULL, чтобы удалить:

Столбец исчез, без церемоний. Чтобы удалить несколько, df[, c("a", "b")] (оставить перечисленное) обычно понятнее, чем повторяющиеся NULL.

Способ dplyr: mutate()

Глагол dplyr для всего перечисленного — mutate(). Сниппеты ниже статичны — песочница выполняет только базовый R, — но вот как выглядят те же операции:

library(dplyr)

orders |>
    mutate(
        total    = price * qty,
        big      = total > 50        # can use total, defined one line up
    )

Два преимущества перед базовым R. Во-первых, столбцы, определённые в одном mutate(), могут ссылаться друг на друга по порядку — то, в чём отказывает transform(). Во-вторых, условные помощники лучше вложенных ifelse():

students |>
    mutate(
        grade = if_else(score >= 60, "pass", "fail"),
        band  = case_when(
            score >= 85 ~ "high",
            score >= 60 ~ "mid",
            .default    = "low"
        )
    )

if_else() — более строгий ifelse() (обе ветки должны быть одного типа — ловит настоящие баги). case_when() читается как плоский список пар условие ~ значение, проверяемых сверху вниз, с .default в качестве запасного варианта — читаемая замена пирамиды из ifelse(). Как и каждый глагол dplyr, mutate() возвращает новый датафрейм; как он сцепляется с остальными, показывает введение в dplyr.

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

  • df$new <- выражение добавляет столбец; выражение выполняется для всех строк сразу.
  • ifelse(test, yes, no) строит условные столбцы; обычный if — нет.
  • transform() добавляет несколько столбцов за вызов, но они не видят друг друга; mutate() — видят.
  • То же присваивание молча перезаписывает — проверяйте орфографию после преобразования.
  • df$col <- NULL удаляет столбец; case_when() заменяет пирамиды вложенных ifelse().

Дальше: переименование столбцов — names(), надёжная базовая идиома и rename() из dplyr.

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

Как добавить новый столбец в датафрейм в R?

Присвойте значение имени столбца, которого ещё нет: df$total <- df$price * df$qty. R создаст столбец на месте. Значением может быть одиночное значение (растиражированное на все строки) или вектор, вычисленный из других столбцов, — лишь бы его длина совпадала с числом строк.

Как создать условный столбец в R?

Используйте векторизованный ifelse(): df$grade <- ifelse(df$score >= 60, "pass", "fail") проверяет все строки сразу. Не используйте обычный if — он обрабатывает одно условие, а не столбец. Для более чем двух исходов вкладывайте вызовы ifelse() или используйте case_when() из dplyr.

Что делает mutate() в R?

mutate() — глагол dplyr для добавления и преобразования столбцов: df |> mutate(total = price * qty) возвращает копию датафрейма с новым столбцом. Он может определить несколько столбцов за один вызов, причём последующие столбцы могут использовать предыдущие, определённые в том же mutate.

Как удалить столбец из датафрейма в R?

Присвойте ему NULL: df$notes <- NULL удаляет столбец на месте. В dplyr select(-notes) возвращает копию без него.

Coddy programming languages illustration

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

НАЧАТЬ