Передать аргументы функции по позиции столбца в mutate_at - PullRequest
0 голосов
/ 13 ноября 2018

Я пытаюсь сжать рабочий поток %>%, в котором мне нужно применить одну и ту же функцию к нескольким столбцам, но каждый раз менялся один аргумент. Я чувствую, что функции purrr * map или invoke должны помочь, но я не могу обернуться вокруг этого.

В моем фрейме данных есть столбцы для ожидаемой продолжительности жизни, уровня бедности и среднего дохода домохозяйства. Я могу передать все эти имена столбцов в vars в mutate_at, использовать round в качестве функции, применяемой к каждому, и при желании предоставить аргумент digits. Но я не могу найти способ, если он существует, передавать различные значения для digits, связанные с каждым столбцом. Я бы хотел, чтобы ожидаемая продолжительность жизни была округлена до 1 цифры, бедность - до 2, а доход - до 0.

Я могу вызвать mutate для каждого столбца, но, учитывая, что у меня может быть больше столбцов, получающих одну и ту же функцию с измененным только дополнительным аргументом, я хотел бы что-то более краткое.

library(tidyverse)

df <- tibble::tribble(
        ~name, ~life_expectancy,          ~poverty, ~household_income,
  "New Haven", 78.0580437642378, 0.264221051111753,  42588.7592521085
  )

В своем воображении я мог бы сделать что-то вроде этого:

df %>%
  mutate_at(vars(life_expectancy, poverty, household_income), 
            round, digits = c(1, 2, 0))

Но получите ошибку

Ошибка в mutate_impl (.data, точки): Столбец life_expectancy должен иметь длину 1 (количество строк), а не 3

Использование mutate_at вместо mutate только для того, чтобы иметь тот же синтаксис, что и в моем идеальном случае:

df %>%
  mutate_at(vars(life_expectancy), round, digits = 1) %>%
  mutate_at(vars(poverty), round, digits = 2) %>%
  mutate_at(vars(household_income), round, digits = 0)
#> # A tibble: 1 x 4
#>   name      life_expectancy poverty household_income
#>   <chr>               <dbl>   <dbl>            <dbl>
#> 1 New Haven            78.1    0.26            42589

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

df %>%
  mutate_at(vars(life_expectancy, poverty, household_income), 
            function(x) map(x, round, digits = c(1, 2, 0))) %>%
  unnest()
#> # A tibble: 3 x 4
#>   name      life_expectancy poverty household_income
#>   <chr>               <dbl>   <dbl>            <dbl>
#> 1 New Haven            78.1    0.3            42589.
#> 2 New Haven            78.1    0.26           42589.
#> 3 New Haven            78      0              42589

Создано в 2018-11-13 пакетом Представ (v0.2.1)

Ответы [ 3 ]

0 голосов
/ 14 ноября 2018

2 решения


mutate с !!!

invoke была хорошей идеей, но теперь она вам нужна меньше, поскольку большинство функций tidyverse поддерживают оператор !!!, вот что вы можете сделать:

digits <- c(life_expectancy = 1, poverty = 2, household_income = 0)  
df %>% mutate(!!!imap(digits, ~round(..3[[.y]], .x),.))
# # A tibble: 1 x 4
#          name life_expectancy poverty household_income
#         <chr>           <dbl>   <dbl>            <dbl>
#   1 New Haven            78.1    0.26            42589

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

Написано более явно:

df %>% mutate(!!!imap(
  digits, 
  function(digit, name, data) round(data[[name]], digit),
  data = .))

Если вам нужно начать со старого интерфейса (хотя тот, который я предлагаю, будет более гибким), сначала выполните:

digits <- setNames(c(1, 2, 0), c("life_expectancy", "poverty", "household_income"))

mutate_at и <<-

Здесь мы немного отклонимся от хорошей практики избегать <<-, когда это возможно, но удобочитаемость имеет значение, и этот действительно легко читается.

digits <- c(1, 2, 0)
i <- 0
df %>%
  mutate_at(vars(life_expectancy, poverty, household_income), ~round(., digits[i<<- i+1]))
# A tibble: 1 x 4
#     name      life_expectancy poverty household_income
#     <chr>               <dbl>   <dbl>            <dbl>
#   1 New Haven            78.1    0.26            42589

(или просто df %>% mutate_at(names(digits), ~round(., digits[i<<- i+1])), если вы используете именованный вектор, как в моем первом решении)

0 голосов
/ 31 января 2019

Веселье с тидевалом:

prepared_pairs <- 
  map2(
    set_names(syms(list("life_expectancy", "poverty", "household_income"))),
    c(1, 2, 0), 
    ~expr(round(!!.x, digits = !!.y))
  )

mutate(df, !!! prepared_pairs)

# # A tibble: 1 x 4
#   name      life_expectancy poverty household_income
#   <chr>               <dbl>   <dbl>            <dbl>
# 1 New Haven            78.1    0.26            42589
0 голосов
/ 13 ноября 2018

Вот решение map2 в соответствии с комментариями Хенрика.Затем вы можете обернуть это внутри пользовательской функции.Я предоставил грубую первую попытку, но я провел минимальные тесты, поэтому, если оценка странная, она, вероятно, ломается при любых ситуациях.Он также не использует tidyselect для .at, но не использует modify_at ...

library(tidyverse)

df <- tibble::tribble(
  ~name, ~life_expectancy,          ~poverty, ~household_income,
  "New Haven", 78.0580437642378, 0.264221051111753,  42588.7592521085,
  "New York", 12.349685329, 0.324067934, 32156.230974623
)

rounded <- df %>%
  select(life_expectancy, poverty, household_income) %>%
  map2_dfc(
    .y = c(1, 2, 0),
    .f = ~ round(.x, digits = .y)
  )
df %>%
  select(-life_expectancy, -poverty, -household_income) %>%
  bind_cols(rounded)
#> # A tibble: 2 x 4
#>   name      life_expectancy poverty household_income
#>   <chr>               <dbl>   <dbl>            <dbl>
#> 1 New Haven            78.1    0.26            42589
#> 2 New York             12.3    0.32            32156


modify2_at <- function(.x, .y, .at, .f) {
  modified <- .x[.at] %>%
    map2(.y, .f)
  .x[.at] <- modified
  return(.x)
}

df %>%
  modify2_at(
    .y = c(1, 2, 0),
    .at = c("life_expectancy", "poverty", "household_income"),
    .f = ~ round(.x, digits = .y)
  )
#> # A tibble: 2 x 4
#>   name      life_expectancy poverty household_income
#>   <chr>               <dbl>   <dbl>            <dbl>
#> 1 New Haven            78.1    0.26            42589
#> 2 New York             12.3    0.32            32156

Создано в 2018-11-13 пакетом Представить (v0.2.1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...