使用tidyr::complete函数时,需要提供一个列名称变量长度的向量。

3
我可以使用tidyr::complete来暴露缺失的行。
例如,对于以下数据框,我可以轻松地暴露缺失的第三季度:
suppressPackageStartupMessages({
  library(dplyr)
  library(tidyr)
})

set.seed(42)

df <- data.frame(
  id = c(rep(1, 3), rep(2, 3)),
  year = rep(2020, 3),
  quarter = c(1, 2, 4),
  data = runif(3)
)

df %>% complete(nesting(id, year), quarter = 1:4)
#> # A tibble: 8 x 4
#>      id  year quarter   data
#>   <dbl> <dbl>   <dbl>  <dbl>
#> 1     1  2020       1  0.915
#> 2     1  2020       2  0.937
#> 3     1  2020       3 NA    
#> 4     1  2020       4  0.286
#> 5     2  2020       1  0.915
#> 6     2  2020       2  0.937
#> 7     2  2020       3 NA    
#> 8     2  2020       4  0.286

本文档由reprex软件包(v0.3.0)于2020年03月02日创建

现在,我想为这个特定的用例创建一个包装器:它接受至少有这四列的数据框,并公开缺失的季度。

这很容易,只需在一个函数中包装complete调用:

expose <- function(df) {
  complete(df, nesting(id, year), quarter = 1:4)
}

expose(df)
#> # A tibble: 8 x 4
#>      id  year quarter   data
#>   <dbl> <dbl>   <dbl>  <dbl>
#> 1     1  2020       1  0.915
#> 2     1  2020       2  0.937
#> 3     1  2020       3 NA    
#> 4     1  2020       4  0.286
#> 5     2  2020       1  0.915
#> 6     2  2020       2  0.937
#> 7     2  2020       3 NA    
#> 8     2  2020       4  0.286

然而,传入的data.frame可能会有其他列是对于给定的id是常数。在这种情况下,函数将不起作用,因为它会在缺失的行上自然地将这些列设置为NA

df <- data.frame(
  id = c(rep(1, 3), rep(2, 3)),
  name = c(rep("A", 3), rep("B", 3)),
  country = c(rep("AU", 3), rep("BR", 3)),
  year = rep(2020, 3),
  quarter = c(1, 2, 4),
  data = runif(3)
)

expose(df)
#> # A tibble: 8 x 6
#>      id  year quarter name  country   data
#>   <dbl> <dbl>   <dbl> <fct> <fct>    <dbl>
#> 1     1  2020       1 A     AU       0.830
#> 2     1  2020       2 A     AU       0.642
#> 3     1  2020       3 <NA>  <NA>    NA    
#> 4     1  2020       4 A     AU       0.519
#> 5     2  2020       1 B     BR       0.830
#> 6     2  2020       2 B     BR       0.642
#> 7     2  2020       3 <NA>  <NA>    NA    
#> 8     2  2020       4 B     BR       0.519

为了避免这种情况,我需要将那些列添加到“nesting”调用中。如果只有一列,我可以向函数添加一个参数以获取该列的名称,然后再使用“nesting(...,.data [[colname]])”。但是,“.data”代词不能与向量一起使用(“.data [c(“name1”,“name2”])”无法正常工作)。那么,我如何将多个变量列添加到“nesting”调用中呢?

1
可以尝试使用 expose <- function(df, cols = NULL) { complete(df, nesting(!!! syms(cols)), quarter = 1:4) } - arg0naut91
2个回答

2

如果您查看tidyr::nesting,您会发现它依赖于tidyr:::dots_cols,后者又依赖于rlang来解释列名(特别是rlang::enquos)。

因此,与tidyr::nesting交互的最佳方法是使用一个rlang构造。

library(dplyr)
library(tidyr)

expose <- function(df, ...) {
  dots <- rlang::exprs(id, year, ...)
  complete(df, nesting(!!! dots), quarter = 1:4)
}

df <- data.frame(
  id = c(rep(1, 3), rep(2, 3)),
  name = c(rep("A", 3), rep("B", 3)),
  country = c(rep("AU", 3), rep("BR", 3)),
  year = rep(2020, 3),
  quarter = c(1, 2, 4),
  data = runif(3)
)

expose(df)
#> # A tibble: 8 x 6
#>      id  year quarter name  country    data
#>   <dbl> <dbl>   <dbl> <fct> <fct>     <dbl>
#> 1     1  2020       1 A     AU       0.0417
#> 2     1  2020       2 A     AU       0.365 
#> 3     1  2020       3 <NA>  <NA>    NA     
#> 4     1  2020       4 A     AU       0.690 
#> 5     2  2020       1 B     BR       0.0417
#> 6     2  2020       2 B     BR       0.365 
#> 7     2  2020       3 <NA>  <NA>    NA     
#> 8     2  2020       4 B     BR       0.690
expose(df, name)
#> # A tibble: 8 x 6
#>      id  year name  quarter country    data
#>   <dbl> <dbl> <fct>   <dbl> <fct>     <dbl>
#> 1     1  2020 A           1 AU       0.0417
#> 2     1  2020 A           2 AU       0.365 
#> 3     1  2020 A           3 <NA>    NA     
#> 4     1  2020 A           4 AU       0.690 
#> 5     2  2020 B           1 BR       0.0417
#> 6     2  2020 B           2 BR       0.365 
#> 7     2  2020 B           3 <NA>    NA     
#> 8     2  2020 B           4 BR       0.690
expose(df, name, country)
#> # A tibble: 8 x 6
#>      id  year name  country quarter    data
#>   <dbl> <dbl> <fct> <fct>     <dbl>   <dbl>
#> 1     1  2020 A     AU            1  0.0417
#> 2     1  2020 A     AU            2  0.365 
#> 3     1  2020 A     AU            3 NA     
#> 4     1  2020 A     AU            4  0.690 
#> 5     2  2020 B     BR            1  0.0417
#> 6     2  2020 B     BR            2  0.365 
#> 7     2  2020 B     BR            3 NA     
#> 8     2  2020 B     BR            4  0.690

本文是使用reprex软件包(v0.3.0)于2020年03月02日创建的。


啊,我刚想起来rlang,不过你的版本比我的好。+1 - Wasabi

0

rlang 库包含非常强大的 list2 对象,可以通过“大爆炸”运算符(!!!)进行拼接。这允许我们将 nesting 作为单个对象传递,由接收函数解释为一系列参数。

因此,我们可以为函数添加 dots 参数,以接收所有其他要嵌套的列,将名称转换为符号,然后将其传递给 nesting

suppressPackageStartupMessages({
  library(dplyr)
  library(rlang)
  library(tidyr)
})

set.seed(42)

expose <- function(df, ...) {
  x <- list2(...)
  x <- lapply(x, sym)
  complete(df, nesting(id, year, !!!x), quarter = 1:4)
}

df <- data.frame(
  id = c(rep(1, 3), rep(2, 3)),
  name = c(rep("A", 3), rep("B", 3)),
  country = c(rep("AU", 3), rep("BR", 3)),
  year = rep(2020, 3),
  quarter = c(1, 2, 4),
  data = runif(3)
)

expose(df, "name", "country")
#> # A tibble: 8 x 6
#>      id  year name  country quarter   data
#>   <dbl> <dbl> <fct> <fct>     <dbl>  <dbl>
#> 1     1  2020 A     AU            1  0.915
#> 2     1  2020 A     AU            2  0.937
#> 3     1  2020 A     AU            3 NA    
#> 4     1  2020 A     AU            4  0.286
#> 5     2  2020 B     BR            1  0.915
#> 6     2  2020 B     BR            2  0.937
#> 7     2  2020 B     BR            3 NA    
#> 8     2  2020 B     BR            4  0.286

2020年03月02日使用reprex package (v0.3.0)创建


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接