同じ関数を複数の列に適用する必要があるが、毎回1つの引数を変更する%>%
パイプワークフローを強化しようとしています。 purrr
のmap
関数またはinvoke
関数が役立つと思いますが、頭を抱えることはできません。
私のデータフレームには、平均余命、貧困率、平均世帯収入の列があります。これらすべての列名をmutate_at
のvars
に渡し、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、dot)のエラー:列
life_expectancy
は3ではなく長さ1(行数)でなければなりません
mutate
の代わりにmutate_at
を使用すると、私の理想的なケースと同じ構文になります。
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
数字のマッピングでは、位置ではなくeach列の各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に reprexパッケージ (v0.2.1)によって作成されました
2ソリューション
mutate
with _!!!
_
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
_は、呼び出しの最後にあるドットを介して、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]))
)
これは、ヘンリックのコメントに沿ったmap2
ソリューションです。次に、これをカスタム関数内にラップできます。私は大まかな最初の試みを提供しましたが、最小限のテストを行ったので、評価がおかしい場合、それはおそらくあらゆる種類の状況で壊れます。また、.at
に対してtidyselectを使用しませんが、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に reprexパッケージ (v0.2.1)によって作成されました
Tidyevalの楽しみ:
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