我有类似于以下数据集的东西:
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
,为domain
内的每 2 行创建一个索引。但是,如果存在余数,例如在domain=2
和id=8,9,10
的情况下,那么只要它们在同一domain
内,这些id
就应该一起索引。请注意,玩具数据集中的特定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
。
编辑请参阅修订后的所需输出数据表和相应的说明。
编辑 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 时(创建顺序向量。函数是,
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
这是为编辑的问题更新的另一种方法(灵感来自@Sotoscumsum
的使用(:
- 对于每个
domain
id,创建一个重复的序列1, 0, 1, 0, 1, ...
,默认情况下将最终序列元素设置为零。 - 跨
domain
id 对创建的序列进行cumsum
。
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
以下是 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