【问题标题】:Create (dplyr::mutate) and select (dplyr::select) new variables that paste two existing columns by means of a user-defined function通过用户定义的函数创建 (dplyr::mutate) 并选择 (dplyr::select) 粘贴两个现有列的新变量
【发布时间】:2017-07-09 16:12:26
【问题描述】:

使用用户定义的函数,我必须加入数据框中所选列数的置信区间的下限和上限(命名为CIlowCIhigh)。数据框有CIlowCIhigh 用于多个组(命名为abc)和一个数字行(在此示例中只有两个)。看看下面数据框的样子。

dataframe<-data.frame(CIlow_a=c(1.1,1.2),CIlow_b=c(2.1,2.2),CIlow_c=c(3.1,3.2),
CIhigh_a=c(1.3,1.4),CIhigh_b=c(2.3,2.4),CIhigh_c=c(3.3,3.4))

我希望在现有组(abc)中的选定数量的组(例如ab)中为每个组添加一个连接列。

因此,预期的输出应该如下:

output<-data.frame(CI_a=c("(1.1,1.3)","(1.2,1.4)"),
                  CI_b=c("(2.1,2.3)","(2.2,2.4)"))

为了构建我自己的用户定义函数,我尝试了以下代码:

f<-function(df,gr){

enquo_gr<-enquo(gr)

r<-df%>%
   dplyr::mutate(UQ(paste("CI",quo_name(gr),sep="_")):=
                   sprintf("(%s,%s)",
                           paste("CIlow",UQ(enquo_gr),sep="_"),
                           paste("CIhigh",UQ(enquo_gr),sep="_")))%>%
   dplyr::select(paste("CI",UQ(enquo_gr),sep="_"))

return(r)
}

但是当以这种方式使用上述功能时

library(dplyr)
group<-c("a","b")
dataframe<-data.frame(CIlow_a=c(1.1,1.2),CIlow_b=c(2.1,2.2),CIlow_c=c(3.1,3.2),CIhigh_a=c(1.3,1.4),CIhigh_b=c(2.3,2.4),CIhigh_c=c(3.3,3.4))

f(df=dataframe,gr=group)

我收到以下错误消息:

错误:expr 必须引用符号、标量或调用

我该如何解决这个问题?

PS1:这个问题类似于a previous one。但是,这个问题更进一步,因为它需要选择要合并的列。

PS2:我将不胜感激按照这个问题的方法提出的代码建议。

【问题讨论】:

    标签: r function dplyr paste


    【解决方案1】:

    如果我们传递带引号的字符串,则使用 sym(对于多个元素 - syms 返回 list

    f <- function(df, gr){
       sl <-  rlang::syms(paste("CIlow", gr, sep="_"))
       sh <-  rlang::syms(paste("CIhigh", gr, sep="_"))
       nmN <- paste("CI", gr, sep= "_")
    
    
       df %>%
           dplyr::mutate(!!(nmN[1]) := sprintf("(%s,%s)",
                                   !!(sl[[1]]), !!(sh[[1]])),
                         !!(nmN[2]) := sprintf("(%s,%s)",
                                   !!(sl[[2]]), !!(sh[[2]]))) %>%
           dplyr::select(paste("CI", gr, sep="_"))
    
    
    
     }
    
    group <- c("a","b")
    f(dataframe, group)
    #      CI_a      CI_b
    #1 (1.1,1.3) (2.1,2.3)
    #2 (1.2,1.4) (2.2,2.4)
    

    【讨论】:

    • 谢谢@akrun!很好的解决方案!但是,我需要一个启用未定义数量的组的脚本。我的意思是,我想加入 CI 有时为a,有时为ab,有时(为什么不)为abc。您的脚本将组数固定为 2(请参阅 [[1]][[2]])。如果有任何进一步的想法,我将不胜感激。
    • 我试过了,但没用(“LHS 必须是名称或字符串)f ")) sh ")) nmN ") df %>% dplyr::mutate(!!(nmN) := sprintf("(%s,%s)", !!(sl), !!(sh)))%>% dplyr::select(paste("CI", gr, sep="")) }`
    • @ungatoverde 我之前尝试过类似的方法,但它可能不起作用。有时间我会查的
    【解决方案2】:

    我可能会根据问题做出不同的回答,但在检查了您的答案后,我准备了以下代码。它从这里dplyr::unite across column patterns 使用lapply 的技巧。我不确定使用dplyr/tidyr 是否是这里的最佳选择,也许简单的for 会更简单。

    output <- data.frame(CI_a=c("(1.1,1.3)","(1.2,1.4)"),
                         CI_b=c("(2.1,2.3)","(2.2,2.4)"),
                         stringsAsFactors = F)
    
    dataframe <- data.frame(CIlow_a=c(1.1,1.2),CIlow_b=c(2.1,2.2),CIlow_c=c(3.1,3.2),
                            CIhigh_a=c(1.3,1.4),CIhigh_b=c(2.3,2.4),CIhigh_c=c(3.3,3.4))
    
    
    tricky <- function(input_data, group_ids){
    
      # convert columns to character
    
      input_data <- input_data %>%
        mutate_each(funs(as.character(.)))
    
      # unite selected groups
    
      output <- group_ids %>%
        lapply(function(group_id) {unite_(input_data, 
                                          paste0("CI_", group_id), 
                                          paste0(c("CIlow_", "CIhigh_"), group_id), 
                                          sep = ',') %>% select_(paste0("CI_", group_id))}) %>%
        bind_cols() %>%
        mutate_each(funs(paste0("(", ., ")")))
    
      return(output)
    
    }
    
    identical(tricky(dataframe, list("a", "b")), output)
    

    【讨论】:

      【解决方案3】:

      我自己找到了解决问题的方法。下面的代码有效:

      output<-data.frame(CI_a=c("(1.1,1.3)","(1.2,1.4)"), CI_b=c("(2.1,2.3)","(2.2,2.4)"))
      
      dataframe<-data.frame(CIlow_a=c(1.1,1.2),CIlow_b=c(2.1,2.2),CIlow_c=c(3.1,3.2),
                            CIhigh_a=c(1.3,1.4),CIhigh_b=c(2.3,2.4),CIhigh_c=c(3.3,3.4))
      
      f <- function(df, gr){
      
         sl <<-  rlang::syms(paste("CIlow", gr, sep="_"))
         sh <<-  rlang::syms(paste("CIhigh", gr, sep="_"))
         nmN <<- paste("CI", gr, sep= "_")
         r<-df
      
      for(i in 1:length(gr)){
              r<-dplyr::mutate(r,UQ(nmN[i]) := sprintf("(%s;%s)", UQ(sl[[i]]),UQ(sh[[i]])))
      }
         r<- dplyr::select(r,nmN)
      return(r)
      
       }
      
      group <- c("a","b")
      
      x<-f(df=dataframe, gr=group)
      

      该代码适用于group 中未定义数量的元素。因此,它适用于 c("a","b")c("a")c("a","b","c")

      我知道不推荐使用循环。任何更好的解决方案表示赞赏。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-11
        • 2016-05-22
        • 2021-10-29
        • 2020-07-05
        • 1970-01-01
        • 2018-11-14
        • 2020-04-28
        • 1970-01-01
        相关资源
        最近更新 更多