簡體   English   中英

將列位置的函數參數傳遞給mutate_at

[英]Pass function arguments by column position to mutate_at

我正在嘗試收緊%>%管道工作流,我需要將相同的函數應用於多個列,但每次更改一個參數。 我覺得purrrmapinvoke函數應該有所幫助,但我無法繞過它。

我的數據框有預期壽命,貧困率和家庭收入中位數的列。 我可以將所有這些列名稱傳遞給mutate_at vars ,使用round作為要應用於每個vars的函數,並可選地提供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,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

數字上的映射使用每列的每個 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

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

..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]))如果你在我的第一個解決方案中使用命名向量)

這是Henrik評論中的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

reprex包創建於2018-11-13(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM