【问题标题】:Create group label for chunks of rows using data.table使用 data.table 为行块创建组标签
【发布时间】:2019-08-30 06:00:54
【问题描述】:

我有类似以下数据集:

myDT <- structure(list(domain = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), id = 2:22, L1 = 2:22), row.names = c(NA, 
-21L), class = c("data.table", "data.frame"))

我想创建一个新列 L2,它为每 2 行 domain 创建一个索引。但是,如果有余数,例如 domain=2id=8,9,10,那么只要它们在同一个 domain 内,就应该将这些 ids 编入索引。请注意,玩具数据集中的特定 id 值是由组成的,并不总是如图所示连续。输出将是:

  structure(list(domain = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
                            3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), id = 2:22, L1 = 2:22, L2=c(1L,1L,2L,2L,3L,3L,4L,4L,4L,
                                                                                                        5L,5L,6L,6L,7L,7L,8L,8L,9L,9L,10L,10L)), 
            row.names = c(NA, -21L), class = c("data.table", "data.frame"))

在 data.table 中是否有有效的方法来执行此操作?

我尝试在子集调用中使用 .N/rowid 和整数除法运算符 %/%(因为每个 n 行应该给出相同的值),但它让我无处。例如,我尝试过类似的方法:

myDT[, L2 := rowid(domain)%/%2]

但显然这并不能满足 domain=2 中的最后 3 行具有相同索引以及索引应继续为 domain=3 递增的要求。

EDIT请查看修改后的所需输出数据表及相应说明。

编辑 2

这是myDT的附加版本:

myDT2 <- structure(list(domain = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), id = 2:40, 
    L1 = 2:40), row.names = c(NA, -39L), class = c("data.table", 
"data.frame"))

当我在上面运行@chinsoon12 的代码时,我得到:

structure(list(domain = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), id = 2:40, 
    L1 = 2:40, L2 = c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 4L, 5L, 
    5L, 6L, 6L, 7L, 7L, 8L, 8L, 9L, 9L, 10L, 10L, 11L, 11L, 11L, 
    11L, 12L, 12L, 13L, 13L, 14L, 14L, 15L, 15L, 16L, 16L, 17L, 
    17L, 18L, 18L)), row.names = c(NA, -39L), class = c("data.table", 
"data.frame"))

L2=11 似乎有 4 个值,而其中两个应该是 12,因为它们位于不同的域中。

【问题讨论】:

  • 是否需要泛化到 2 以外的 diff 窗口大小?

标签: r indexing data.table


【解决方案1】:

一个想法是创建一个自定义函数,该函数将根据每个组的长度以及除以 2 时该长度的余数创建顺序向量。函数是,

f1 <- function(x) {
    v1 <- length(x)
    i1 <- rep(seq(floor(v1 / 2)), each = 2)
    i2 <- c(i1, rep(max(i1), v1 %% 2))
    i2 + seq_along(i2)
}

我尝试通过data.table 应用它,但我收到了一个关于错误的错误,所以这里是基于 R 的,

cumsum(c(TRUE, diff(with(myDT2, ave(id, domain, FUN = f1))) != 1))
#[1]  1  1  2  2  3  3  4  4  4  5  5  6  6  7  7  8  8  9  9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19

【讨论】:

  • 当我用一些额外的观察扩展玩具数据集时,(非)基本 R 代码似乎也给出了与 @chinsoon12 的代码相同的问题 - 请参阅编辑 2。
  • 有趣。发生这种情况是因为有一个长度为 2 的组
  • @stats134711 再次编辑。请立即查看并告诉我。请注意,我更改了 f1 函数和应用它的方式
【解决方案2】:

这是针对已编辑问题更新的另一种方法(灵感来自 @Sotos 使用 cumsum):

  1. 对于每个domain id,创建一个重复序列1, 0, 1, 0, 1, ...,默认将最终序列元素设置为零。
  2. cumsum 置于domain id 的已创建序列之上。
library(data.table)

setDT(myDT2)

myDT2[, L2 := c(head(rep_len(c(1, 0), .N), -1), 0), by = domain][, L2 := cumsum(L2)][]
#>     domain id L1 L2
#>  1:      2  2  2  1
#>  2:      2  3  3  1
#>  3:      2  4  4  2
#>  4:      2  5  5  2
#>  5:      2  6  6  3
#>  6:      2  7  7  3
#>  7:      2  8  8  4
#>  8:      2  9  9  4
#>  9:      2 10 10  4
#> 10:      3 11 11  5
#> 11:      3 12 12  5
#> 12:      3 13 13  6
#> 13:      3 14 14  6
#> 14:      3 15 15  7
#> 15:      3 16 16  7
#> 16:      3 17 17  8
#> 17:      3 18 18  8
#> 18:      3 19 19  9
#> 19:      3 20 20  9
#> 20:      3 21 21 10
#> 21:      3 22 22 10
#> 22:      4 23 23 11
#> 23:      4 24 24 11
#> 24:      5 25 25 12
#> 25:      5 26 26 12
#> 26:      5 27 27 13
#> 27:      5 28 28 13
#> 28:      5 29 29 14
#> 29:      5 30 30 14
#> 30:      5 31 31 15
#> 31:      5 32 32 15
#> 32:      5 33 33 16
#> 33:      5 34 34 16
#> 34:      5 35 35 17
#> 35:      5 36 36 17
#> 36:      5 37 37 18
#> 37:      5 38 38 18
#> 38:      5 39 39 19
#> 39:      5 40 40 19
#>     domain id L1 L2

【讨论】:

  • 谢谢。抱歉,我一定是在您尝试代码时编辑了我的帖子。修改后的输出没有随着每个新的 domain 值重新启动索引。这段代码似乎也给了我一个错误:Type of RHS ('double') must match LHS ('integer').
【解决方案3】:

这里是可变重复次数的另一种选择,而不是 2:

n <- 4
setDT(myDT)[, L2 := 
        myDT[, {
            x <- ceiling(seq_along(id)/n)
            if (sum(x==x[.N]) < n) x[x==x[.N]] <- floor(.N/n)
            x
        }, domain][, rleid(domain, V1)]
    ]

或递归方法:

n <- 4
s <- 0
setDT(myDT)[, L2 := 
        myDT[, {
            x <- s + ceiling(seq_along(id)/n)
            if (sum(x==x[.N]) < n) x[x==x[.N]] <- s + floor(.N/n)
            s <- if (s<max(x)) max(x) else s + 1
            x
        }, domain]$V1
    ]

n=2 的输出:

    domain id L1 L2
 1:      2  2  2  1
 2:      2  3  3  1
 3:      2  4  4  2
 4:      2  5  5  2
 5:      2  6  6  3
 6:      2  7  7  3
 7:      2  8  8  4
 8:      2  9  9  4
 9:      2 10 10  4
10:      3 11 11  5
11:      3 12 12  5
12:      3 13 13  6
13:      3 14 14  6
14:      3 15 15  7
15:      3 16 16  7
16:      3 17 17  8
17:      3 18 18  8
18:      3 19 19  9
19:      3 20 20  9
20:      3 21 21 10
21:      3 22 22 10
22:      4 23 23 11
23:      4 24 24 11
24:      5 25 25 12
25:      5 26 26 12
26:      5 27 27 13
27:      5 28 28 13
28:      5 29 29 14
29:      5 30 30 14
30:      5 31 31 15
31:      5 32 32 15
32:      5 33 33 16
33:      5 34 34 16
34:      5 35 35 17
35:      5 36 36 17
36:      5 37 37 18
37:      5 38 38 18
38:      5 39 39 19
39:      5 40 40 19
    domain id L1 L2

n=4 的输出:

    domain id L1 L2
 1:      2  2  2  1
 2:      2  3  3  1
 3:      2  4  4  1
 4:      2  5  5  1
 5:      2  6  6  2
 6:      2  7  7  2
 7:      2  8  8  2
 8:      2  9  9  2
 9:      2 10 10  2
10:      3 11 11  3
11:      3 12 12  3
12:      3 13 13  3
13:      3 14 14  3
14:      3 15 15  4
15:      3 16 16  4
16:      3 17 17  4
17:      3 18 18  4
18:      3 19 19  5
19:      3 20 20  5
20:      3 21 21  5
21:      3 22 22  5
22:      4 23 23  6
23:      4 24 24  6
24:      5 25 25  7
25:      5 26 26  7
26:      5 27 27  7
27:      5 28 28  7
28:      5 29 29  8
29:      5 30 30  8
30:      5 31 31  8
31:      5 32 32  8
32:      5 33 33  9
33:      5 34 34  9
34:      5 35 35  9
35:      5 36 36  9
36:      5 37 37 10
37:      5 38 38 10
38:      5 39 39 10
39:      5 40 40 10
    domain id L1 L2

【讨论】:

  • @JorisChau,为什么不将rleid 添加到您的代码中,然后我将其删除。
  • @chinsoon12,当我向当前数据表添加更多观察结果时,它似乎给了我奇怪的行为(参见上面的编辑 2)。
  • @stats134711 你是否更改了编辑 2 中的数据?我没有看到任何差异
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多