【问题标题】:Using string vectors as variables in a function using dplyr::summarise()使用 dplyr::summarise() 在函数中使用字符串向量作为变量
【发布时间】:2020-07-01 09:40:34
【问题描述】:

我最近开始使用 R 来处理我的研究数据(并且绝对没有后悔离开 SPSS)并且找不到解决以下问题的方法: 我创建了一个函数,该函数通过二进制变量对我的数据进行分组(患者是否患有某种类型的并发症是/否?-> reg_var)并在与二进制变量相关联的连续变量上运行 dplyr 的汇总函数(提到的并发症的估计风险有多高 -> reg_yr)。 我现在想为多对变量(例如 compare(reg_var1, reg_yr1)、compare(reg_var2, reg_yr2) 和 compare(reg_var3, reg_yr3))运行这个函数,并创建多个我可以稍后合并的小标题。 我创建了两个包含变量名称的向量(v_reg_var 和 v_reg_yr)。

    library(tidyverse)
    # Create a function to calculate and compare est. risk percentages
    # of patients with/without actual complications
    compare <-function(reg_var, reg_yr) {
    datatable %>%
    group_by(.data[[reg_var]]) %>%
    summarise(
    n(), mean(.data[[reg_yr]]), sd(.data[[reg_yr]]), median(.data[[reg_yr]]), min(.data[[reg_yr]]), max(.data[[reg_yr]]),
    "25%" = quantile(.data[[reg_yr]], probs = 0.25),
    "50%" = quantile(.data[[reg_yr]], probs = 0.5),
    "75%" = quantile(.data[[reg_yr]], probs = 0.75))
    }
    v_reg_var <- c[reg_var1, reg_var2, reg_var3, …)
    v_reg_yr <- c[reg_yr1, reg_yr2, reg_yr3, …)
    # Now if I run compare() using two vectors which only contain one character string it works just
    # fine but unfortunately if I run compare(v_reg_var, v_reg_yr), I receive the following error:

    compare(v_reg_var, v_reg_yr)

   Error: Problem with \mutate()` input `..1`.`
   x Must subset the data pronoun with a string
   ℹ Input \..1` is `<unknown>`.`

如果有人能提示我在这里做错了什么,或者有更优雅的解决方案,那就太好了。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    compare 函数一次取一个值v_reg_varv_reg_yr。要并行传递它们,您可以使用Map

    Map(compare, v_reg_var, v_reg_yr)
    

    或者由于您主要使用tidyverse,因此相当于map2 来自purrr

    purrr::map2(v_reg_var, v_reg_yr, compare)
    

    map2 将返回数据帧列表。如果您想在一个数据框中获取所有数据,可以使用purrr::map2_df

    【讨论】:

    • 非常感谢!地图功能解决了我的问题。只是出于好奇而问:map() 是基础 R 的一部分还是只有在安装 purrr 时才可用?
    • Map 在基础 R 中,而 map 来自 purrr。注意m 的大小写。 R 区分大小写。
    【解决方案2】:

    您拥有的函数仅适用于 1 个变量,并且不会遍历所有变量。首先,我们通过调用基本 R 汇总函数来简化函数,并使用 !!as.name() 而不是从 data.frame 调用它(这是完全正确的):

    fn = function(V){
       c(n=length(V),sd=sd(V),summary(V))
    }
    
    library(tidyverse)
    
    datatable = data.frame(y1=sample(1:5,100,replace=TRUE),
    y2=sample(1:5,100,replace=TRUE),
    v1=runif(100),v2=runif(100))
        
    compare <-function(df,reg_var,reg_yr) {
        df %>%
        group_by(!!as.name(reg_yr)) %>%
        summarise(res=list(fn( !!as.name(reg_var) ) ) )%>% 
        unnest_wider(res)
        }
    
    compare(datatable,"v1","y1")
    # A tibble: 5 x 9
         y1     n    sd   Min. `1st Qu.` Median  Mean `3rd Qu.`  Max.
      <int> <dbl> <dbl>  <dbl>     <dbl>  <dbl> <dbl>     <dbl> <dbl>
    1     1    18 0.267 0.0241    0.185   0.276 0.373     0.568 0.814
    2     2    24 0.288 0.0443    0.243   0.396 0.470     0.664 0.986
    3     3    20 0.330 0.0446    0.234   0.474 0.501     0.777 0.987
    4     4    14 0.203 0.0171    0.0566  0.208 0.247     0.408 0.600
    5     5    24 0.299 0.0138    0.235   0.457 0.491     0.742 0.948
    

    现在我们遍历你的配对:

    v_reg_var <- c("v1","v2")
    v_reg_yr <- c("y1","y2")
    
    1:length(v_reg_var) %>% 
    map(~compare(datatable,v_reg_var[.x],v_reg_yr[.x]))
    

    这最后一部分类似于@RonakShah 的解决方案,只是我倾向于避免从全局环境调用。

    我也怀疑你的原始表格可以做成长格式,这样会更容易

    【讨论】:

    • 非常感谢您的回答!您使用 base::summary 函数的变体确实更优雅。我的数据看起来更像这样:datatable &lt;- data.frame(y1 = sample(0:1,100,replace = TRUE), v1 = runif(100), y2=sample(0:1,100,replace = TRUE),v2 = runif(100)) 你还会认为长格式表更容易处理吗?我也非常感激,如果你能在这种情况下,summary 函数中的 res=list()unnest_wider(res) 做什么?您是否正在定义一个列表并在以后扩展它?无论如何,通过重新创建您的解决方案,我学到了很多关于 R 的知识。谢谢!
    • 是的,长格式更容易。如果您重新格式化 data.frame 以具有列 v(variables = 1,2) 和相应的 y (variables =1,2),那么您可以使用 group_by 执行上述操作。 dplyr() 更适合长格式。
    • 对于列表的作用,当您进行汇总时,输出的长度应为 1,因此,如果您为其提供一个列表,其中包含许多元素,它将起作用。是的,第二部分是扩展这个列表。这真的不仅仅是优雅,我发现将 5 或 6 个函数编码到一个汇总调用中非常容易出错,因此我更喜欢这种方法
    猜你喜欢
    • 2018-08-28
    • 2015-08-03
    • 2021-03-31
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多