【问题标题】:Expand a data.frame/table展开 data.frame/table
【发布时间】:2020-01-27 18:10:46
【问题描述】:

假设我有一个我想要“扩展”的 data.frame/table,这样每一行都会转换为一系列重复行(可以描述为一个组),除了一个新列,它将具有所有组中的值相同。

因此,采用以下数据框,我们希望将其扩展为 id 列,这样现在每一行都重复,但新列 q 每组从 1 到 4 重复。

我发现这样做的方法是基于第一个列 id 和新列值构建第二个数据框,然后将其加入原始数据框:

library(dplyr)

set.seed(42)

a <- data.frame(id = 1:5,
                value = runif(5))
a
#>   id     value
#> 1  1 0.9148060
#> 2  2 0.9370754
#> 3  3 0.2861395
#> 4  4 0.8304476
#> 5  5 0.6417455

b <- data.frame(id = rep(a$id, each = 4),
                q = 1:4)

left_join(a, b, by = "id")
#>    id     value q
#> 1   1 0.9148060 1
#> 2   1 0.9148060 2
#> 3   1 0.9148060 3
#> 4   1 0.9148060 4
#> 5   2 0.9370754 1
#> 6   2 0.9370754 2
#> 7   2 0.9370754 3
#> 8   2 0.9370754 4
#> 9   3 0.2861395 1
#> 10  3 0.2861395 2
#> 11  3 0.2861395 3
#> 12  3 0.2861395 4
#> 13  4 0.8304476 1
#> 14  4 0.8304476 2
#> 15  4 0.8304476 3
#> 16  4 0.8304476 4
#> 17  5 0.6417455 1
#> 18  5 0.6417455 2
#> 19  5 0.6417455 3
#> 20  5 0.6417455 4

reprex package (v0.3.0) 于 2020-01-27 创建

有没有更直接的方法?在上面的示例中,我使用了dplyr,但如果更简单的话,我也可以轻松地采用data.table 语法。

【问题讨论】:

  • 如果可以使用您问题的三个答案中的任何一个,那么您应该考虑将其中一个标记为已接受:)

标签: r dplyr data.table


【解决方案1】:

这很容易通过 tidyr 包中的函数 crossing 完成。

library(tidyr)

a <- tibble(
  id = 1:5, value = runif(5)
)

crossing(a, q = 1:4)
#> # A tibble: 20 x 3
#>       id value     q
#>    <int> <dbl> <int>
#>  1     1 0.222     1
#>  2     1 0.222     2
#>  3     1 0.222     3
#>  4     1 0.222     4
#>  5     2 0.262     1
#>  6     2 0.262     2
#>  7     2 0.262     3
#>  8     2 0.262     4
#>  9     3 0.284     1
#> # … with 10 more rows

reprex package (v0.3.0) 于 2020 年 1 月 27 日创建

【讨论】:

    【解决方案2】:

    如果我们需要replicate 行,可以通过uncount轻松完成

    library(dplyr)
    library(tidyr)
    library(data.table)
    uncount(a, 4) %>% 
         mutate(q = rowid(id))
    

    或者另一种选择是创建一个list 'q' 列,然后创建unnest

    a %>% 
       mutate(q = list(1:4)) %>%
       unnest(q)
    

    或在base R

    transform(a[rep(seq_len(nrow(a)), 4), ], q = sequence(table(id)))
    

    或使用data.table

    library(data.table)
    setDT(a)[, .(q = 1:4),.(id, value)]
    

    或者先复制行

    setDT(a)[rep(seq_len(.N), .N)][, q := rep(1:4, length.out = .N)][]
    

    【讨论】:

    • 我所说的“更直接”是指不需要构建另一个数据框/表,直接扩展a
    • @Wasabi uncount(a, 4) %&gt;% mutate(q = rowid(id)) 会不会更直接一些?
    • 啊,这些带有uncountunnest 的新方法非常完美。
    【解决方案3】:

    data.table 替代方案:

    setDT(a)
    a[CJ(id = id, q = 1:4), on = .(id)]
    

    基地R:

    expand_grid(a, q = 1:4)
    

    【讨论】:

      猜你喜欢
      • 2018-11-30
      • 1970-01-01
      • 2020-04-24
      • 2021-09-12
      • 2020-02-21
      • 1970-01-01
      • 2020-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多