Итерация по нескольким (но не всем) столбцам в фрейме данных с purrr

Я ищу лаконичный способ работы с несколькими столбцами одновременно внутри трубы. Проблема в том, что мне не нужно работать со всеми столбцами: только с несколькими.

library(tidyverse)
mtcars <- mtcars %>% rownames_to_column(var = 'car')
str(mtcars)

'data.frame':   32 obs. of  12 variables:
 $ car : chr  "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

Представь, что я хочу выполнить какое-то действие с колонками drat, qsec а также gear, (Например, преобразовать в символ. Кто знает почему)

Как можно сделать это без написания действия 3 раза? Возможно используя purrr()?

4 ответа

Решение

2 ключевые функции здесь map_at (или же map_if если вместо того, чтобы знать столбцы, мы знаем что-то о столбцах, но не знаем, какие из них нам нужны) и map_df (который возвращает фрейм данных вместо списка).

К сожалению, я не вижу функцию, которая сочетает в себе оба. Но мы можем обойти это. Глядя под капот на map_df, это обычный map с добавлением bind_rows() в конце.

Вот и все, что нам нужно:

mtcars2 <- mtcars %>% 
  map_at(c('drat', 'qsec', 'gear'), as.character) %>% 
  bind_rows()

Базовое решение R. Мы можем использовать lapply цикл по именам столбцов и разработка функции для преобразования целевых столбцов в символ.

mtcars[] <- lapply(colnames(mtcars),
                    function(x) {
                      y <- mtcars[[x]]
                      if (x %in% c("drat", "qsec", "gear")){
                        y <- as.character(y)
                      }
                      return(y)
                    })

str(mtcars)
# 'data.frame': 32 obs. of  12 variables:
#   $ car : chr  "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
# $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
# $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
# $ disp: num  160 160 108 258 360 ...
# $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
# $ drat: chr  "3.9" "3.9" "3.85" "3.08" ...
# $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
# $ qsec: chr  "16.46" "17.02" "18.61" "19.44" ...
# $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
# $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
# $ gear: chr  "4" "4" "4" "3" ...
# $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

Пытаться mutate_at в дплыр:

mtcars %>% mutate_at(c("drat", "qsec", "gear"), as.character)

Это также можно записать так:

mtcars %>% mutate_at(vars(drat, qsec, gear), as.character)

Вы также можете использовать modify или же modify_at от purrr, modify функции похожи map за исключением того, что вывод форматируется как ввод.

modify_at будет использоваться так же, как mutate_at в решении @g-grothendieck:

mtcars %>% modify_at(c("drat", "qsec", "gear"), as.character)

Если вы используете magrittr Вы также можете сделать это (этот перезаписывает mtcars):

mtcars[, c("drat", "qsec", "gear")] %<>% modify(as.character)
Другие вопросы по тегам