说我有以下data.table:
library(data.table)
DT <- data.table(R=sample(0:1, 10000, rep=TRUE), Seq=0)
返回类似的内容:
R Seq
1: 1 0
2: 1 0
3: 0 0
4: 0 0
5: 1 0
---
9996: 1 0
9997: 0 0
9998: 0 0
9999: 0 0
10000: 1 0
我想生成一个序列(1,2,3,...,n),只要R从前一行改变,它就会重置。想想看,就像我在计算一连串随机数。
所以上面会是这样的:
R Seq
1: 1 1
2: 1 2
3: 0 1
4: 0 2
5: 1 1
---
9996: 1 5
9997: 0 1
9998: 0 2
9999: 0 3
10000: 1 2
思想?
答案 0 :(得分:6)
这是一个选项:
set.seed(1)
DT <- data.table(R=sample(0:1, 10000, rep=TRUE), Seq=0L)
DT[, Seq:=seq(.N), by=list(cumsum(c(0, abs(diff(R)))))]
DT
我们创建一个计数器,每当您使用cumsum(abs(diff(R)))
更改0-1变量时,该计数器会递增。 c(0,
部分是为了确保我们得到正确的长度向量。然后我们用by
分割它。这会产生:
R Seq
1: 0 1
2: 0 2
3: 1 1
4: 1 2
5: 0 1
---
9996: 1 1
9997: 0 1
9998: 1 1
9999: 1 2
10000: 1 3
编辑:解决澄清请求:
让我们看看我在by
中使用的计算,细分为两个新列:
DT[, diff:=c(0, diff(R))]
DT[, cumsum:=cumsum(abs(diff))]
print(DT, topn=10)
产地:
R Seq diff cumsum
1: 0 1 0 0
2: 0 2 0 0
3: 1 1 1 1
4: 1 2 0 1
5: 0 1 -1 2
6: 1 1 1 3
7: 1 2 0 3
8: 1 3 0 3
9: 1 4 0 3
10: 0 1 -1 4
---
9991: 1 2 0 5021
9992: 1 3 0 5021
9993: 1 4 0 5021
9994: 1 5 0 5021
9995: 0 1 -1 5022
9996: 1 1 1 5023
9997: 0 1 -1 5024
9998: 1 1 1 5025
9999: 1 2 0 5025
10000: 1 3 0 5025
每次R改变时,您都可以看到diff的绝对值的累积和如何递增1。然后,我们可以使用cumsum
列将data.table
拆分为块,并为每个块使用seq(.N)
生成一个序列,该序列计入块中的项目数({{ 1}}恰好代表每个.N
组中有多少项。)
答案 1 :(得分:1)
旧问题,但以防万一有人需要更快,更轻松的方法:
DT[, Seq := rowid(rleid(R))]
说明:
rleid
创建一个索引,该索引在每次遇到新的一组连续值时递增。因此rleid(c('a','a','b','b','a','a'))
返回1 1 2 2 3 3
rowid
为每个值创建一个索引,每次重复该值(但不一定是连续的),该索引都会递增。因此rowid(c('a','a','b','b','a','a'))
返回1 2 1 2 3 4
在这个示例中,只有一分之一秒的时间,具有一千万行。