根据列创建data.table中的序列

时间:2014-08-20 22:50:33

标签: r data.table

说我有以下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

思想?

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

在这个示例中,只有一分之一秒的时间,具有一千万行。