在“ pivot_wider()”之后从数据帧中删除冗余/重复的列

时间:2020-06-09 10:31:55

标签: r dplyr tidyverse tidyr

我有一个带有两个id变量和多个变量的数据框。在这些变量中,一些变量仅取决于id1而变化,而其他变量则取决于id1id2。现在,我想使用tidyr::pivot_wider()重塑数据框的范围。下面是一个代表,实际数据集包含更多的变量。

样本数据

library(tidyverse)
set.seed(42)
(d <- tibble(
  id1 = rep(LETTERS[1:4], each = 3),
  id2 = rep(letters[1:3], length.out = 12),
  x = rpois(12, 3),
  y = rep(rpois(4, 5), each = 3)
))
#> # A tibble: 12 x 4
#>    id1   id2       x     y
#>    <chr> <chr> <int> <int>
#>  1 A     a         5     9
#>  2 A     b         6     9
#>  3 A     c         2     9
#>  4 B     a         5     3
#>  5 B     b         3     3
#>  6 B     c         3     3
#>  7 C     a         4     5
#>  8 C     b         1     5
#>  9 C     c         4     5
#> 10 D     a         4     9
#> 11 D     b         3     9
#> 12 D     c         4     9

输出

透视示例框架将产生以下框架:

(d <- pivot_wider(d, names_from = id2, values_from = x:y))
#> # A tibble: 4 x 7
#>   id1     x_a   x_b   x_c   y_a   y_b   y_c
#>   <chr> <int> <int> <int> <int> <int> <int>
#> 1 A         5     6     2     9     9     9
#> 2 B         5     3     3     3     3     3
#> 3 C         4     1     4     5     5     5
#> 4 D         4     3     4     9     9     9

从输出中可以看到,y_ay_by_c都是相同的,因此是重复的。

所需的输出

我想得到的是一个没有冗余的数据帧:

d %>% 
  rename(y = y_a) %>% 
  select(-y_b, -y_c)
#> # A tibble: 4 x 5
#>   id1     x_a   x_b   x_c     y
#>   <chr> <int> <int> <int> <int>
#> 1 A         5     6     2     9
#> 2 B         5     3     3     3
#> 3 C         4     1     4     5
#> 4 D         4     3     4     9

该解决方案应产生一个没有重复列的数据帧,并且无需用户输入就可以产生多余的列。 tidyverse解决方案会很好,但是也欢迎其他解决方案。

到目前为止,我自己想解决的唯一方法是编写一个函数,该函数根据前缀识别列组,然后检查组中的列是否相同,删除冗余列并重命名剩下的变量删除后缀。我认为这一定是更简洁的方法。

我也对此问题进行了搜索,但结果往往是关于重复的列名或重复的行,并且没有为眼前的问题找到任何解决方案。

3 个答案:

答案 0 :(得分:2)

我找到了一个可行的解决方案,但这并不漂亮。它依赖于选择帮助器tidyselect::where()和一个lambda函数,如果存在至少一个TRUE的唯一值且id1中有多个唯一的对应元素,则该函数将返回.x其他FALSE

d %>%
  pivot_wider(
    names_from = id2,
    names_glue = "{.value}_{id2}",
    values_from = where(~ tibble(d$id1, .x) %>%
                          distinct() %>%
                          {
                            nrow(.) != length(unique(.[[1]])) & !identical(d$id2, .x)
                          })
  )
#> # A tibble: 4 x 5
#>   id1       y   x_a   x_b   x_c
#>   <chr> <int> <int> <int> <int>
#> 1 A         9     5     6     2
#> 2 B         3     5     3     3
#> 3 C         5     4     1     4
#> 4 D         9     4     3     4

答案 1 :(得分:1)

请勿在{{1​​}}中使用y。试试:

values_from

答案 2 :(得分:0)

此解决方案可提供所需的输出

pivot_wider(d, names_from = id2, names_glue = "{.value}_{id2}", values_from = x)

输出

#   id1       y   x_a   x_b   x_c
#   <chr> <int> <int> <int> <int>
# 1 A         9     5     6     2
# 2 B         3     5     3     3
# 3 C         5     4     1     4
# 4 D         9     4     3     4