如何将 R 代码移动到函数中以概括行为

Posted

技术标签:

【中文标题】如何将 R 代码移动到函数中以概括行为【英文标题】:How to move R code into functions to generalise behaviour 【发布时间】:2022-01-23 06:27:10 【问题描述】:

我有一大段杂乱无章的 R 代码,其中包含大量难看的重复。有机会大规模减少它。从这段代码开始:

table <-
  risk_assigned %>%
  group_by(rental_type, room_type) %>%
  summarise_all(funs( sum(!is.na(.)) / length(.) ) ) %>%
  select(-c(device_id, ts, room, hhi, temp)) %>%
  adorn_pct_formatting()

我想将它概括为一个函数,以便它可以重复使用。

   LayKable = function(kableDetails) 
     table <-
       risk_assigned %>%
       group_by(kableDetails$group1 , kableDetails$group2) %>%
       summarise_all(funs( sum(!is.na(.)) / length(.) ) ) #%>%
       select(-c(device_id, ts, room, hhi, temp)) %>%
       adorn_pct_formatting()

    ...

    kable <- table
    return(kable)
   

   kableDetails <- list(
     group1 = "rental_type", 
     group2 = "room_type"
   )

   newKable <- LayKable(kableDetails)

这种相当半心半意的尝试有助于解释我想要做什么。如何将内容传递给列表中的这个函数(我是 C 程序员,假装它是一个结构)。

【问题讨论】:

如果您总是要使用group1group2 列表元素,为什么还要一个参数kableDetails?为什么不使用LayKable("rental_type", "room_type") 之类的显式参数呢?还有,为什么risk_assigned是全局变量而不是传入函数? 这是一个最小的例子。我有 6 或 7 个参数要传入。它在列表中更整洁。分配的风险是一个全局变量。 【参考方案1】:

将函数参数传递给函数内的 dplyr 动词时,您必须使用 rlang 术语。但是定义一个函数应该很简单,您可以将许多分组术语传递给:

library(dplyr)

test_func <- function(..., data = mtcars) 
# Passing `data` as a default argument as it's nice to be flexible!  


  data %>% 
    group_by(!!!enquos(...)) %>% 
    summarise(across(.fns = sum), .groups = "drop")


test_func(cyl, gear)

#> # A tibble: 8 x 11
#>     cyl  gear   mpg  disp    hp  drat    wt  qsec    vs    am  carb
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     4     3  21.5  120.    97  3.7   2.46  20.0     1     0     1
#> 2     4     4 215.   821    608 32.9  19.0  157.      8     6    12
#> 3     4     5  56.4  215.   204  8.2   3.65  33.6     1     2     4
#> 4     6     3  39.5  483    215  5.84  6.68  39.7     2     0     2
#> 5     6     4  79    655.   466 15.6  12.4   70.7     2     2    16
#> 6     6     5  19.7  145    175  3.62  2.77  15.5     0     1     6
#> 7     8     3 181.  4291.  2330 37.4  49.2  206.      0     0    37
#> 8     8     5  30.8  652    599  7.76  6.74  29.1     0     2    12

更新 - 添加列表

我认为您的理想是为每个函数调用编写一个参数列表并传递这些参数,而不是在每个调用中写出参数。您可以使用do.call 将命名参数列表传递给函数来执行此操作。同样,当使用dplyr 动词时,您可以在构造列表时使用quote 变量名(这样R 在编译列表时不会尝试在全局环境中找到它们)和!!enquo 每个调用 then在那里使用它们:

library(dplyr)
test_func2 <- function(.summary_var, .group_var, data = mtcars) 
  
  data %>% 
    group_by(!!enquo(.group_var)) %>% 
    summarise(mean  = mean(!!enquo(.summary_var)))
  


# Test with bare arguments
test_func2(hp, cyl)

#> # A tibble: 3 x 2
#>     cyl  mean
#>   <dbl> <dbl>
#> 1     4  82.6
#> 2     6 122. 
#> 3     8 209.


# Construct and pass list
args <- list(.summary_var = quote(hp), .group_var = quote(cyl))

do.call(test_func2, args = args)

#> # A tibble: 3 x 2
#>     cyl  mean
#>   <dbl> <dbl>
#> 1     4  82.6
#> 2     6 122. 
#> 3     8 209.

handy guide to tidy evaluation,其中大部分想法都得到了更清楚的解释。

由reprex package (v2.0.1) 于 2021 年 12 月 21 日创建

【讨论】:

以上是关于如何将 R 代码移动到函数中以概括行为的主要内容,如果未能解决你的问题,请参考以下文章

用于设置变量的移动参数-模型行为更改

将对象的键移动到其值中以创建对象数组

默认复制/移动构造函数时 GDB 中的奇怪行为

我们如何将位图图像存储到移动内存中?

如何将此 javascript 和 HTML 代码添加到 Angular 项目中?我可以从 javascript 函数中以角度呈现 html 吗?

如何在 ios 应用程序中以编程方式移动到第二个视图?