我有一个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小时和计数)。有更有效的解决方案吗?
答案 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))]
csvdata[ csvdata[, .I[1L], by=rleid(signal.a, signal.b)]$V1 ]