【发布时间】:2021-02-06 02:16:20
【问题描述】:
tidyr 包有一个非常有用的complete 函数,它允许我们明确“丢失”行:你将所有相关列传递给函数,它确保所有可能的组合都存在,如果出现则创建新行缺少的组合需要。您还可以为其指定给定列的预期值(即calendar_quarter = 1:4)。
还有nesting(),可以在complete() 中使用对列进行分组,以便仅使用这些列的现有组合。
但是,“中间”案例呢?也就是说,我们想为每个组提供不同的期望值?最好用一个例子来说明这一点:
suppressPackageStartupMessages({
library(dplyr)
library(tidyr)
})
df <- tribble(
~id, ~year, ~semester,
1, 2000, 1,
1, 2001, 1,
1, 2001, 2,
2, 1999, 1,
2, 1999, 2,
2, 2001, 1
)
这里有一个表格,其中包含给定id 相关的年份和学期。但是,我们缺少一些学期(id=1 的 2000S1 和 id=2 的 2000S1、2000S2 和 2001S2)。
首先我们尝试使用nesting(),否则我们会为id=1, year=1999 创建行,而我们不需要:
complete(df, nesting(id, year), semester = 1:2)
#> # A tibble: 8 x 3
#> id year semester
#> <dbl> <dbl> <dbl>
#> 1 1 2000 1
#> 2 1 2000 2 # new
#> 3 1 2001 1
#> 4 1 2001 2
#> 5 2 1999 1
#> 6 2 1999 2
#> 7 2 2001 1
#> 8 2 2001 2 # new
没关系,为ids 填写一些缺失的学期。但是,它仍然为id=2 隐藏了缺失的 2000 年。这是很自然的,因为我们没有告诉 complete() 为 year 列使用任何额外的值。
那么让我们这样做吧。我们必须抛弃nesting(),然后我们可以告诉complete() 来检查整个已知年份范围的存在:
complete(df, id, year = min(year):max(year), semester = 1:2)
#> # A tibble: 12 x 3
#> id year semester
#> <dbl> <dbl> <dbl>
#> 1 1 1999 1 # new, unwanted
#> 2 1 1999 2 # new, unwanted
#> 3 1 2000 1
#> 4 1 2000 2 # new
#> 5 1 2001 1
#> 6 1 2001 2
#> 7 2 1999 1
#> 8 2 1999 2
#> 9 2 2000 1 # new
#> 10 2 2000 2 # new
#> 11 2 2001 1
#> 12 2 2001 2 # new
由reprex package (v0.3.0) 于 2020 年 10 月 22 日创建
这样更好,显示所有缺失的学期,包括 id=2 的 2000 年。
但是,这样做的代价是还暴露了 id=1 的 1999 年,这是我们不希望的。
那么,有没有一种优雅的方式来获得以下输出?
#> # A tibble: 10 x 3
#> id year semester
#> <dbl> <dbl> <dbl>
#> 1 1 2000 1
#> 2 1 2000 2 # new
#> 3 1 2001 1
#> 4 1 2001 2
#> 5 2 1999 1
#> 6 2 1999 2
#> 7 2 2000 1 # new
#> 8 2 2000 2 # new
#> 9 2 2001 1
#> 10 2 2001 2 # new
我想出的唯一解决方案是构建另一个表startEndY 来存储每个id 的初始和最后年份,运行complete(df, id, year = min(year):max(year), semester = 1:2),然后在df 和@987654348 之间执行连接@ 删除不需要的结果,但这似乎不优雅且缓慢,因为 complete() 会创建许多不必要的行(尤其是在我的实际用例中)。
【问题讨论】: