我正在努力收紧%>%管道工作流程,我需要将相同的函数应用于多个列,但每次更改一个参数.我觉得自己purrr的map或invoke功能应该有所帮助,但我不能换我的头周围.
我的数据框有预期寿命,贫困率和家庭收入中位数的列.我可以将所有这些列名称传递给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_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
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)
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]))在我的第一个解决方案中使用命名向量)