数据表中的条件差计算

时间:2014-10-07 15:12:11

标签: r data.table

我有一百万行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 部分中当前行的opscounterdiff()的双重调用也许不是一种有效的用法:

dt[,opsdiff:=c(NA, ifelse(diff(opscounter)>0, diff(opscounter), opscounter)), by=type]

如何正确计算opsdiff列?

2 个答案:

答案 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