【问题标题】:How to add multiple new columns with the same logic based on calculation of two columns with the same string in R如何根据R中具有相同字符串的两列的计算添加具有相同逻辑的多个新列
【发布时间】:2021-02-03 18:46:00
【问题描述】:

我有一张如下所示的表格

data <- data.frame(A = c(1,2,3,4,5),
                   B = c(1,2,3,4,5),
                   C = c(11,12,13,14,15),
                   trans_A = c(NA,1,2,3,4),
                   trans_B = c(NA,1,2,3,4),
                   trans_C = c(NA,11,12,13,14))

我需要使用 difference_A = A - trans_Adifference_B = B - trans_B 等逻辑在此数据框中创建/添加多个新列,新名称为 difference_Adifference_B 等。我该如何在 R 中执行此操作?

我试过了:

new_df[paste("difference", cols, sep = "_")]<- c(NA, new_df[cols]-new_df[paste("trans",cols,sep = "_")], na.rm=TRUE)

它给了我错误消息“列的重复下标”

【问题讨论】:

    标签: r


    【解决方案1】:

    dplyrpurrr 的一个解决方案可能是:

    map(.x = names(select(data, -starts_with("trans_"))),
        ~ data %>%
         mutate(across(all_of(.x), .names = "difference_{col}") - across(all_of(paste0("trans_", .x))))) %>%
     reduce(full_join)
    
      A B  C trans_A trans_B trans_C difference_A difference_B difference_C
    1 1 1 11      NA      NA      NA           NA           NA           NA
    2 2 2 12       1       1      11            1            1            1
    3 3 3 13       2       2      12            1            1            1
    4 4 4 14       3       3      13            1            1            1
    5 5 5 15       4       4      14            1            1            1
    

    【讨论】:

      【解决方案2】:

      我们可以使用pivot_longer/pivot_wider

      library(dplyr)
      library(tidyr)
      library(stringr)
      data %>% 
          rename_at(vars(which(!str_detect(names(.), '_'))), ~ str_c("orig_", .)) %>% 
          mutate(rn = row_number()) %>% 
          pivot_longer(cols = -rn, names_to = c(".value", "group"), names_sep = "_") %>%
          transmute(group = str_c('difference_', group), rn, difference = orig - trans) %>%
          pivot_wider(names_from = group, values_from = difference ) %>% 
          select(-rn) %>% 
          bind_cols(data, .)
      #  A B  C trans_A trans_B trans_C difference_A difference_B difference_C
      #1 1 1 11      NA      NA      NA           NA           NA           NA
      #2 2 2 12       1       1      11            1            1            1
      #3 3 3 13       2       2      12            1            1            1
      #4 4 4 14       3       3      13            1            1            1
      #5 5 5 15       4       4      14            1            1            1
       
      

      【讨论】:

        【解决方案3】:

        基本 R 选项

        cbind(
          data,
          lapply(
            split.default(
              data,
              gsub(".*(\\w)$", "difference_\\1", names(data))
            ), function(v) do.call("-", v)
          )
        )
        

        给予

          A B  C trans_A trans_B trans_C difference_A difference_B difference_C
        1 1 1 11      NA      NA      NA           NA           NA           NA
        2 2 2 12       1       1      11            1            1            1
        3 3 3 13       2       2      12            1            1            1
        4 4 4 14       3       3      13            1            1            1
        5 5 5 15       4       4      14            1            1            1
        

        【讨论】:

          【解决方案4】:

          另一个命题:

          df <- read.table(header = TRUE, text = "
            A  B  C trans_A trans_B trans_C
          1 1  1 11      NA      NA      NA
          2 2  2 12       1       1      11
          3 3  3 13       2       2      12
          4 4  4 14       3       3      13
          5 5  5 15       4       4      14
          ")
          
          for (x in c("A","B","C")) {
            varname <- paste0("difference_",x)
            df[[varname]] <- with(df, get(x) - get(paste0("trans_",x)))
          }
          
          df
          #>   A B  C trans_A trans_B trans_C difference_A difference_B difference_C
          #> 1 1 1 11      NA      NA      NA           NA           NA           NA
          #> 2 2 2 12       1       1      11            1            1            1
          #> 3 3 3 13       2       2      12            1            1            1
          #> 4 4 4 14       3       3      13            1            1            1
          #> 5 5 5 15       4       4      14            1            1            1
          
          # Created on 2021-02-03 by the reprex package (v0.3.0.9001
          

          for (x in c("A","B","C")) {
            df <- within (df, {
              assign(paste0("difference_",x), get(x) - get(paste0("trans_",x)))
            })
          }
          
          df
          #>   A B  C trans_A trans_B trans_C difference_A difference_B difference_C
          #> 1 1 1 11      NA      NA      NA           NA           NA           NA
          #> 2 2 2 12       1       1      11            1            1            1
          #> 3 3 3 13       2       2      12            1            1            1
          #> 4 4 4 14       3       3      13            1            1            1
          #> 5 5 5 15       4       4      14            1            1            1
          
          # Created on 2021-02-03 by the reprex package (v0.3.0.9001)
          

          (与Use dynamic variable names in `dplyr`相关)

          问候,

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多