删除data.table中的行,其中列不会更改为前一行

时间:2017-01-24 11:34:16

标签: r data.table

我有一个5M行的data.table对象。它可能看起来像这样:

csvdata <- data.table(timestamp = c(1:6),
                      signal.a=c(12, 12, 13, 12, 12, 14),
                      signal.b=c(7, 7, 7, 7, 8, 8))

timestamp  signal.a  signal.b
        1        12         7
        2        12         7
        3        13         7
        4        12         7
        5        12         8
        6        14         8

我要做的是删除表中的每一行,这不会记录任何信号变化。所以我想最终得到:第2行被删除,因为signal.a和signal.b都没有改变。

timestamp  signal.a  signal.b
        1        12         7
        3        13         7
        4        12         7
        5        12         8
        6        14         8

我对R的经验不多,所以我尝试了一种for循环的常用方法,意图将每一行标记为删除,然后过滤掉我想要保留的行:

for (i in 1:nrow(csvdata)) {
    if (i > 1 && csvdata[i]$signal.a == csvdata[i-1]$signal.a &&
       csvdata[i]$signal.b == csvdata[i-1]$signal.b) {
        csvdata[i]$Drop <- 1
    }
}

代码似乎有效,但是对于5M行,这段代码需要永远运行(2小时和计数)。有更有效的解决方案吗?

2 个答案:

答案 0 :(得分:3)

csvdata[csvdata[, c(TRUE, #always keep first row
                    Reduce("|", #at least one column needs to change
                            Map("!=", 
                                shift(.(signal.a, signal.b)), #shift the columns by one row
                                .(signal.a, signal.b)) #and compare with preceding row
                            )[-1])] #always keep first row
        ,]
#   timestamp signal.a signal.b
#1:         1       12        7
#2:         3       13        7
#3:         4       12        7
#4:         5       12        8
#5:         6       14        8

答案 1 :(得分:3)

一种常见的解决方法是使用rleid,就像其中一样(感谢@ Arun的评论)......

csvdata[!duplicated(rleid(signal.a, signal.b))]

using @eddi's approach ...

csvdata[ csvdata[, .I[1L], by=rleid(signal.a, signal.b)]$V1 ]