我有一百万行长的data.table
,其中有大约 20 个计数器样式的列。这些列显示各种存储系统操作的计数器随时间的增加。然而,有时,受监控系统上的计数器会重置,并且单个观测值低于前一个观测值。
我需要计算一个 opsdiff
列,其中包含基于列 type
的相同类型的后续值的算术差值(预期为正)。当识别出计数器重置情况时 - 即。差值为负数,应使用计数器的实际值。
> dt <- data.table(type=rep(c("a","b"),each=6),opscounter=c(105609,106316,106705,489,723,1250))
> dt
type opscounter
1: a 105609
2: a 106316
3: a 106705
4: a 489
5: a 723
6: a 1250
7: b 105609
8: b 106316
9: b 106705
10: b 489
11: b 723
12: b 1250
我希望得到的结果:
> dt
type opscounter opsdiff
1: a 105609 NA
2: a 106316 707
3: a 106705 389
4: a 489 489
5: a 723 234
6: a 1250 527
7: b 105609 NA
8: b 106316 707
9: b 106705 389
10: b 489 489
11: b 723 234
12: b 1250 527
>
我尝试构建一个基于 ifelse()
的构造,但我不知道如何在 else 中解决当前行的 opscounter
值> 部分,并且 diff()
的双重调用可能都不是有效的用法:
dt[,opsdiff:=c(NA, ifelse(diff(opscounter)>0, diff(opscounter), opscounter)), by=type]
如何正确计算 opsdiff
列?
最佳答案
首选解决方案是:
dt[, opsdiff := c(NA, diff(opscounter)),
by = type][opsdiff < 0, opsdiff := opscounter][]
# type opscounter opsdiff
# 1: a 105609 NA
# 2: a 106316 707
# 3: a 106705 389
# 4: a 489 489
# 5: a 723 234
# 6: a 1250 527
# 7: b 105609 NA
# 8: b 106316 707
# 9: b 106705 389
# 10: b 489 489
# 11: b 723 234
# 12: b 1250 527
Note that I've added additional
[]
in order to print results on the fly and in order to illustrate that you can add more than one of these.
一般来说,最好避免 ifelse
(特别是在您拥有如此大数据集的情况下),如 it can to be slow (although vectorized) due to it evaluating both yes and no cases 。在您的情况下,您发现了另一个“缺陷”,您需要告诉它您想要从中提取 opscounter 的确切位置,这增加了复杂性(请参阅 @Aruns comment 以了解可能的覆盖)。
关于评论中的问题, DT[...]
形式的 data.table
操作仅调用函数 [.data.table( DT,...)
。在 data.frame
上没有什么不同;还有一个类似的函数[.data.frame
。
Note that a
data.table
is also adata.frame
. Seeclass(dt)
and also read?data.table
.
为了更清楚地说明,在 data.table 中,一个接一个地固定 [...]
称为链接。这是免费的。您也可以在 data.frame 中执行相同的操作(如下所示),但是您可以在 data.frame
上执行的操作是有限的,因此与数据不同,链接本身的使用是有限的。表。
df <- as.data.frame(dt) # or `setDF(dt)` in 1.9.4+ to do this by reference
df[df$type == "a", ][2:3, ]
# type opscounter
# 2 a 106316
# 3 a 106705
最后,为了说明ifelse
的无效性,这里有一个基准:
set.seed(123)
n <- 1e6
dt <- data.table(type = rep(c("a","b"), each = n),
opscounter = sample(1:1e5, n*2, replace = TRUE))
library(microbenchmark)
microbenchmark(
dt[, opsdiff := c(NA, diff(opscounter)), by = type][opsdiff < 0, opsdiff := opscounter],
dt[, opsdiff := c(NA, ifelse(diff(opscounter) > 0, diff(opscounter), tail(opscounter, -1L))), by=type]
)
# Unit: milliseconds
# expr
# dt[, `:=`(opsdiff, c(NA, diff(opscounter))), by = type][opsdiff < 0, `:=`(opsdiff, opscounter)]
# dt[, `:=`(opsdiff, c(NA, ifelse(diff(opscounter) > 0, diff(opscounter), tail(opscounter, -1L)))), by = type]
# min lq mean median uq max neval
# 228.0445 255.4006 285.8163 281.1388 307.4195 508.3841 100
# 899.1222 990.1478 1085.5492 1048.3704 1095.7179 1740.5704 100
ifelse
解决方案速度慢约 4 倍。
关于r - 数据表中的条件差异计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26239328/