[英]dplyr column selection with placeholder . and paste in mutate_at
[英]dplyr: access column name in mutate_at function
我想通過從其中減去另一列名稱幾乎相同的列來更正 data.frame 中的列,但另一列有后綴。 我想為此使用mutate_at
function。
試圖弄清楚這一點,我一直在努力訪問 mutate_at 的 function 部分中的列名稱,以使用它來訪問另一列。
我在下面的一個小例子中展示了這一點,但基本上我想訪問目前使用的列的名稱.
然后 select 來自 pipe 列中的數據,該列與.
但有一個后綴(下面是"_new"
)。
謝謝你的幫助!
這是我希望如何做的一個例子 - 但這不起作用。
library(tidyverse)
data("mtcars")
new <- mtcars/4
names(new) <-paste0(names(new),"_new")
df <- bind_cols(mtcars,new)
df %>%
mutate_at(.vars = vars(carb,disp),
.funs = list(corrected = ~ . - df %>% pull(paste0(names(.),"_new"))))
df %>% pull(paste0("carb","_new"))
而不是使用mutate_at
為什么不使用mutate
結合cur_column
across
:
df %>%
mutate( across( c(carb,disp), ~ . - pull(df, paste0(cur_column(), "_new") ), .names = "{.col}_corrected") )
我們無法names
.
在mutate_at
內部,因為它是一個vector
並且沒有列名信息。 一個選項是map2
library(purrr)
library(dplyr)
library(stringr)
nm1 <- c('carb', 'disp')
map_dfc(nm1, ~ df %>%
transmute(!!str_c(.x, '_corrected') :=
!! rlang::sym(.x) - !! rlang::sym(str_c(.x, "_new"))))%>%
bind_cols(df, .) %>%
head
# mpg cyl disp hp drat wt qsec vs am gear carb mpg_new cyl_new disp_new hp_new drat_new wt_new qsec_new
#1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 5.250 1.5 40.00 27.50 0.9750 0.65500 4.1150
#2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 5.250 1.5 40.00 27.50 0.9750 0.71875 4.2550
#3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 5.700 1.0 27.00 23.25 0.9625 0.58000 4.6525
#4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 5.350 1.5 64.50 27.50 0.7700 0.80375 4.8600
#5 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 4.675 2.0 90.00 43.75 0.7875 0.86000 4.2550
#6 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 4.525 1.5 56.25 26.25 0.6900 0.86500 5.0550
# vs_new am_new gear_new carb_new carb_corrected disp_corrected
#1 0.00 0.25 1.00 1.00 3.00 120.00
#2 0.00 0.25 1.00 1.00 3.00 120.00
#3 0.25 0.25 1.00 0.25 0.75 81.00
#4 0.25 0.00 0.75 0.25 0.75 193.50
#5 0.00 0.00 0.75 0.50 1.50 270.00
#6 0.25 0.00 0.75 0.25 0.75 168.75
或者我們可以使用for
循環進行更新
for(nm in nm1) {
df <- df %>%
mutate(!! str_c(nm, '_corrected') :=
!! rlang::sym(nm) - !! rlang::sym(str_c(nm, '_new')))
}
或使用帶 lapply 的base R
lapply
df[paste0(nm1, "_corrected")] <- lapply(nm1, function(nm)
df[nm] - df[paste0(nm, "_new")])
正如其他人已經指出的那樣,變量名稱不能在mutate_at
中訪問,這對於即將到來的mutate(across())
也是如此。 我在這里將這個問題作為dplyr
的功能請求來解決,但顯然,這種數據整理任務對於dplyr
來說太專業了。 下面我為這種數據整理問題提供了我最喜歡的解決方法,它包括兩個步驟:
:: rlang::sym()
定義自定義變異 function 以基於變量名稱的字符向量生成變量purrr::reduce
應用此自定義 function 。library(tidyverse)
# your toy data
df <- mtcars %>%
as_tibble %>%
mutate_all(list(new =~ ./4))
# step 1: generate helper function, in this case a simple `mutate` call
gen_corrected <- function(df, x) {
mutate(df,
"{x}_corrected" := !! rlang::sym(x) - !! rlang::sym(str_c(x, "_new"))
)
}
# step 2:
# use purrr's `reduce` on the vector of vars you want to change
# the vector of variables can be defined in a separate step
# important: you need to set `.init = .`
df %>%
purrr::reduce(c('carb', 'disp'), gen_corrected, .init = .)
#> # A tibble: 32 x 24
#> mpg cyl disp hp drat wt qsec vs am gear carb mpg_new
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4 5.25
#> 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4 5.25
#> 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1 5.7
#> 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 5.35
#> 5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 4.68
#> 6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1 4.53
#> 7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4 3.58
#> 8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2 6.1
#> 9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2 5.7
#> 10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4 4.8
#> # … with 22 more rows, and 12 more variables: cyl_new <dbl>, disp_new <dbl>,
#> # hp_new <dbl>, drat_new <dbl>, wt_new <dbl>, qsec_new <dbl>, vs_new <dbl>,
#> # am_new <dbl>, gear_new <dbl>, carb_new <dbl>, carb_corrected <dbl>,
#> # disp_corrected <dbl>
由代表 package (v0.3.0) 於 2020 年 5 月 21 日創建
在上面提到的 github 問題中, @Romain Francois 提供了另一個解決此問題的方法。
您可以在基礎 R 或map2
中使用Map
purrr
實現此目的:
cols <- c('carb', 'disp')
df[paste0(cols, '_corrected')] <- Map(`-`, df[cols], df[paste0(cols, '_new')])
使用map2
library(purrr)
df[paste0(cols, '_corrected')] <- map2(df[cols], df[paste0(cols, '_new')], `-`)
這是一個基本的 R 解決方案。 我們可以定義一個 function, diff_col
來創建操作,然后使用 for 循環重復應用這個 function 來修改數據幀。
diff_col <- function(col, dat){
dat[[paste0(col, "_corrected")]] <- dat[[col]] - dat[[paste0(col, "_new")]]
return(dat)
}
for (name in c("carb", "disp")){
df <- diff_col(col = name, dat = df)
}
我得出了這個答案,並想根據上面提到的技巧來捕捉一個濃縮的解決方案。
the_clauses <- c("carb", "disp") %>%
set_names(., str_c(., "_new")) %>%
map(.f = ~quo(!!sym(.x)/4))
# Equivalent to:
# quos(carb_new = carb/4, disp_new = disp/4)
mtcars %>% mutate(!!!the_clauses)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.