通过两个变量扩展数据集并计算现有匹配项的数量

Expand a dataset by two variables and count the number of existing matches

我有一个如下所示的数据集:

test_df <- tibble(
  category = c('a', 'a', 'b', 'b', 'b', 'c'),
  group = c("X", "Y", "Z", "X", "Y", "Z"),
  category_data_1 = c(rep("dataA", 2), rep("dataB", 3), rep("dataC", 1)),
  category_data_2 = c(rep("data2A", 2), rep("data2B", 3), rep("data2C", 1))
  
)
# A tibble: 6 x 4
  category group category_data_1 category_data_2
  <chr>    <chr> <chr>           <chr>          
1 a        X     dataA           data2A         
2 a        Y     dataA           data2A         
3 b        Z     dataB           data2B         
4 b        X     dataB           data2B         
5 b        Y     dataB           data2B         
6 c        Z     dataC           data2C  

我希望这个数据集发生两件事:

  1. 将其扩展 categorygroup(这是简单的一方,例如 tidyr::expand()),但将 category_data 变量保留在数据集——它们总是与 category variable 相关联。因此,category == "a" 将在整个数据集中有 category_data_1 == "dataA"category_data_2 == "data2A"

  2. 我想创建一个新的二进制变量来检查 categorygroup 的组合是否存在 (1) 或 (0).

所以,最后我想要这样的东西:

# A tibble: 9 x 5
  category group category_data_1 category_data_2 combination_existed
  <chr>    <chr> <chr>           <chr>                         <dbl>
1 a        X     dataA           data2A                            1
2 a        Y     dataA           data2A                            1
3 a        Z     dataA           data2A                            0
4 b        X     dataB           data2B                            1
5 b        Y     dataB           data2B                            1
6 b        Z     dataB           data2B                            1
7 c        X     dataC           data2C                            0
8 c        Y     dataC           data2C                            0
9 c        Z     dataC           data2C                            1

我想我可以通过科学怪人将几个临时数据集放在一起来实现这一点,但我想知道是否有更简单的方法?也许用 tidyverse?

这里是简单的解决方案,依赖于tidyr::expandtidyr::nestingtidyr::nesting 可用于防止创建新的变量组合。

test_df %>%
  expand(nesting(category, category_data_1, category_data_2), group) %>%
  left_join(test_df %>% mutate(x = 1), by = colnames(test_df)) %>%
  replace_na(list(x = 0))

# A tibble: 9 x 5
  category category_data_1 category_data_2 group     x
  <chr>    <chr>           <chr>           <chr> <dbl>
1 a        dataA           data2A          X         1
2 a        dataA           data2A          Y         1
3 a        dataA           data2A          Z         0
4 b        dataB           data2B          X         1
5 b        dataB           data2B          Y         1
6 b        dataB           data2B          Z         1
7 c        dataC           data2C          X         0
8 c        dataC           data2C          Y         0
9 c        dataC           data2C          Z         1

您需要 tidyr::complete 及其两个参数 fillnesting 才能很好地为您完成。但是在使用 complete 之前,您必须根据需要创建一个新列。所以一个完整的语法可以是

library(tibble)
test_df <- tibble(
  category = c('a', 'a', 'b', 'b', 'b', 'c'),
  group = c("X", "Y", "Z", "X", "Y", "Z"),
  category_data_1 = c(rep("dataA", 2), rep("dataB", 3), rep("dataC", 1)),
  category_data_2 = c(rep("data2A", 2), rep("data2B", 3), rep("data2C", 1))
  
)

library(tidyverse)
test_df %>% mutate(combination_existed = 1) %>%
  complete(group = unique(test_df$group), nesting(category, category_data_1, category_data_2), 
           fill = list(combination_existed = 0))
#> # A tibble: 9 x 5
#>   group category category_data_1 category_data_2 combination_existed
#>   <chr> <chr>    <chr>           <chr>                         <dbl>
#> 1 X     a        dataA           data2A                            1
#> 2 X     b        dataB           data2B                            1
#> 3 X     c        dataC           data2C                            0
#> 4 Y     a        dataA           data2A                            1
#> 5 Y     b        dataB           data2B                            1
#> 6 Y     c        dataC           data2C                            0
#> 7 Z     a        dataA           data2A                            0
#> 8 Z     b        dataB           data2B                            1
#> 9 Z     c        dataC           data2C                            1

reprex package (v2.0.0)

于 2021-05-26 创建

或者写得有点不同,以获得所需的输出

  • nesting中取出category并在其上添加group_by。两种语法都没有区别,但是 category 上的 group_by 导致它比其他列更早放置,这符合预期的输出。
test_df %>% mutate(combination_existed = 1) %>%
  group_by(category) %>%
  complete(group = unique(test_df$group), nesting(category_data_1, category_data_2), 
           fill = list(combination_existed = 0))

# A tibble: 9 x 5
# Groups:   category [3]
  category group category_data_1 category_data_2 combination_existed
  <chr>    <chr> <chr>           <chr>                         <dbl>
1 a        X     dataA           data2A                            1
2 a        Y     dataA           data2A                            1
3 a        Z     dataA           data2A                            0
4 b        X     dataB           data2B                            1
5 b        Y     dataB           data2B                            1
6 b        Z     dataB           data2B                            1
7 c        X     dataC           data2C                            0
8 c        Y     dataC           data2C                            0
9 c        Z     dataC           data2C                            1