簡體   English   中英

您可以使用 dplyr cross() 來遍歷成對的列嗎?

[英]Can you use dplyr across() to iterate across pairs of columns?

我有 18 對變量,我想對它們進行成對數學計算以計算 18 個新變量。 將公式應用於一列時,dplyr 中的 cross() function 非常方便。 有沒有辦法將 cross() 應用於成對的列?

簡單除法 2 個變量的小例子(我的實際代碼會更復雜,一些 ifelse,...):

library(tidyverse)
library(glue)

# filler data
df <- data.frame("label" = c('a','b','c','d'),
                 "A" = c(4, 3, 8, 9),
                 "B" = c(10, 0, 4, 1),
                 "error_A" = c(0.4, 0.3, 0.2, 0.1),
                 "error_B" = c(0.3, 0, 0.4, 0.1))

# what I want to have in the end 
# instead of just 2 (A, B), I have 18
df1 <- df %>% mutate(
  'R_A' = A/error_A,
  'R_B' = B/error_B
)

# what I'm thinking about doing to use both variables A and error_A to calculate the new column
df2 <- df %>% mutate(
  across(c('A','B'),
         ~.x/{HOW DO I USE THE COLUMN WHOSE NAME IS glue('error_',.x)}
         .names = 'R_{.col}'
)

一種選擇是map/reduce 指定感興趣的列('nm1'),在mapselect中循環它們,從數據集中這些列,通過除法reduce ,在列綁定( _dfc )之后rename列,並將這些列與原始數據集綁定

library(dplyr)
library(purrr)
library(stringr)
nm1 <- c('A', 'B')
map_dfc(nm1, ~ df %>% 
                select(ends_with(.x)) %>% 
                reduce(., `/`) ) %>%
    rename_all(~ str_c('R_', nm1)) %>%
    bind_cols(df, .)

-輸出

#  label A  B error_A error_B R_A      R_B
#1     a 4 10     0.4     0.3  10 33.33333
#2     b 3  0     0.3     0.0  10      NaN
#3     c 8  4     0.2     0.4  40 10.00000
#4     d 9  1     0.1     0.1  90 10.00000

或其他across

df %>% 
    mutate(across(c(A, B), ~ 
     ./get(str_c('error_', cur_column() )), .names = 'R_{.col}' ))
#  label A  B error_A error_B R_A      R_B
#1     a 4 10     0.4     0.3  10 33.33333
#2     b 3  0     0.3     0.0  10      NaN
#3     c 8  4     0.2     0.4  40 10.00000
#4     d 9  1     0.1     0.1  90 10.00000    

我喜歡上面的 akruns 回答,尤其是使用cur_column()的方法。 有趣的是, cur_column()不能與 {rlang} 的評估 ( ,! sym(paste0("error_", cur_column())) ) 一起使用,但get是一個很好的解決方法。

只是添加一種方法,它也適用於 dpylr < 1.0.0。 我通常將mutate自定義 function 與purrr::reduce()一起使用。 在這個 function x是你的字符串詞干,你構造你想用.. sym(paste0(...))訪問的所有變量。 在左側,您可以只使用 {rlang} 的粘合語法。

您可以通過在字符串向量上調用reduce()來應用此自定義 function,並且您的data.frame進入.init =. 爭論。

library(tidyverse)
library(glue)


# filler data
df <- data.frame("label" = c('a','b','c','d'),
                 "A" = c(4, 3, 8, 9),
                 "B" = c(10, 0, 4, 1),
                 "error_A" = c(0.4, 0.3, 0.2, 0.1),
                 "error_B" = c(0.3, 0, 0.4, 0.1))

gen_vars1 <- function(df, x) {
  
  mutate(df,
         "R_{x}" := !! sym(x) / !! sym(paste0("error_", x)))
}

df %>% 
  reduce(c("A", "B"), gen_vars1, .init = .)
#>   label A  B error_A error_B R_A      R_B
#> 1     a 4 10     0.4     0.3  10 33.33333
#> 2     b 3  0     0.3     0.0  10      NaN
#> 3     c 8  4     0.2     0.4  40 10.00000
#> 4     d 9  1     0.1     0.1  90 10.00000

代表 package (v0.3.0) 於 2021 年 1 月 2 日創建

我曾經針對此類問題打開過功能請求,但顯然它對於 {dplyr} 來說太特殊了。 當您點擊鏈接時,您還可以找到執行此類操作的另一個選項。

一種選擇可能是:

df %>%
 mutate(across(c(A, B), .names = "R_{col}")/across(starts_with("error")))

  label A  B error_A error_B R_A      R_B
1     a 4 10     0.4     0.3  10 33.33333
2     b 3  0     0.3     0.0  10      NaN
3     c 8  4     0.2     0.4  40 10.00000
4     d 9  1     0.1     0.1  90 10.00000

對於這種情況,我發現基本的 R 解決方案也直接有效。 它不需要遍歷列或唯一值。 您定義兩組列並直接划分它們。

對於您共享的示例,我們可以通過查找僅包含一個字符的列名稱來識別"A""B"列。

cols <- grep('^.$', names(df), value = TRUE)
error_cols <- grep('error', names(df), value = TRUE)

df[paste0('R_', cols)] <- df[cols]/df[error_cols]
df

#  label A  B error_A error_B R_A  R_B
#1     a 4 10     0.4     0.3  10 33.3
#2     b 3  0     0.3     0.0  10  NaN
#3     c 8  4     0.2     0.4  40 10.0
#4     d 9  1     0.1     0.1  90 10.0

暫無
暫無

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

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