将列位置的函数参数传递给mutate_at

cam*_*lle 12 r dplyr purrr

我正在努力收紧%>%管道工作流程,我需要将相同的函数应用于多个列,但每次更改一个参数.我觉得自己purrrmapinvoke功能应该有所帮助,但我不能换我的头周围.

我的数据框有预期寿命,贫困率和家庭收入中位数的列.我可以将所有这些列名称传递给varsin 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
  )
Run Code Online (Sandbox Code Playgroud)

在我的想象中,我可以这样做:

df %>%
  mutate_at(vars(life_expectancy, poverty, household_income), 
            round, digits = c(1, 2, 0))
Run Code Online (Sandbox Code Playgroud)

但得到错误

mutate_impl(.data,dots)中的错误:列life_expectancy必须是长度1(行数),而不是3

使用mutate_atmutate不仅仅是在我的理想情况下使用相同的语法:

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
Run Code Online (Sandbox Code Playgroud)

映射在数字使用每个的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
Run Code Online (Sandbox Code Playgroud)

reprex包创建于2018-11-13 (v0.2.1)

Moo*_*per 8

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
Run Code Online (Sandbox Code Playgroud)

..3 是初始数据帧,通过调用结束时的点传递给函数作为第三个参数.

写得更明确:

df %>% mutate(!!!imap(
  digits, 
  function(digit, name, data) round(data[[name]], digit),
  data = .))
Run Code Online (Sandbox Code Playgroud)

如果你需要从旧界面开始(虽然我建议的那个会更灵活),首先要做:

digits <- setNames(c(1, 2, 0), c("life_expectancy", "poverty", "household_income"))
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

(或者只是df %>% mutate_at(names(digits), ~round(., digits[i<<- i+1]))在我的第一个解决方案中使用命名向量)