我有一百万行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
列?
答案 0 :(得分:2)
首选解决方案是:
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
请注意,我已添加了额外的
[]
,以便即时打印结果,并说明您可以添加多个这些结果。
一般情况下,最好避免使用ifelse
opscounter
(特别是在您的情况下使用如此大的数据集)it can to be slow (although vectorized) due to it evaluating both yes and no cases。在您的情况下,您发现了另一个&#34;缺陷&#34;,您需要告诉它您要从中提取data.table
的确切位置,这会增加复杂性(请参阅@Aruns comment可能的覆盖)。
关于您在评论中的问题,DT[...]
形式的[.data.table(DT, ...)
操作只调用函数data.frame
。它在[.data.frame
上没有任何不同;有一个类似的函数data.table
。
请注意,
data.frame
也是class(dt)
。请参阅?data.table
并阅读[...]
。
为了使其更清晰,在data.table中,一个接一个地添加data.frame
称为 chaining 。这是免费的。您也可以在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
执行的操作是有限的,因此使用链接本身,与data.table不同。
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
{{1}}解决方案慢了约4倍。
答案 1 :(得分:0)
由于这不是data.table的方法,因此这不是理想的方法。但是,以下是另一种方法。
library(dplyr)
df <- data.frame(type=rep(c("a","b"),each=6),opscounter=c(105609,106316,106705,489,723,1250))
df %>%
group_by(type) %>%
mutate(opsdiff = opscounter - lag(opscounter)) %>%
mutate(opsdiff = ifelse(opsdiff < 0, opscounter, opsdiff))
# 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