【问题标题】:Remove redundant / duplicate colums from data frame after `pivot_wider()`在 `pivot_wider()` 之后从数据框中删除冗余/重复的列
【发布时间】:2020-06-09 10:31:55
【问题描述】:

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

样本数据

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 解决方案会很好,但也欢迎其他解决方案。

到目前为止,尝试自己解决这个问题,我能想出的唯一方法是编写一个函数,根据前缀识别列组,然后检查组中的列是否相同,删除冗余列并重命名剩下的变量去掉后缀。我觉得必须是一种更简洁的方式来做到这一点。

我也用谷歌搜索了这个问题,但结果往往是关于重复的列名或重复的行,并且没有为手头的问题找到任何解决方案。

【问题讨论】:

    标签: r dplyr tidyverse tidyr


    【解决方案1】:

    我找到了一个可行的解决方案,但它并不漂亮。它依赖于选择助手tidyselect::where() 和一个lambda 函数,如果id1 至少有一个唯一值,则返回TRUE,该值在.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
    

    【讨论】:

      【解决方案2】:

      不要在values_from 中使用y。试试看:

      (d <- pivot_wider(d, names_from = id2, values_from = x, names_prefix = '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
      

      【讨论】:

      • 是的,如果我知道x 依赖于id1id2y 不是,这就是我会做的。但是实际的数据框有很多变量,不知道取决于id2。那么是否有类似dplyr 选择助手的东西可以帮助我识别取决于id2 的变量?
      • 我不知道是否有什么可以帮助您识别这些变量。如果您检查id1xy 列中唯一值的数量并仅包含values_from 中具有比id1 更多唯一值的变量,它会起作用吗?否则我不确定你将如何“识别”这些变量。
      • 我找到了一个解决方案,它使用where() 加上一个 lamda 函数,它可以满足我的需求,并将其作为答案发布在下面。感谢您的帮助。
      【解决方案3】:

      此解决方案提供您想要的输出

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-23
        • 2016-07-08
        • 1970-01-01
        • 2019-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多