r - 数据表中的条件差异计算

标签 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 中解决当前行的 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 a data.frame. See class(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/

相关文章:

r - 毫秒时间戳作为 data.table 中的键

R:键应该在 data.table 中以这种方式运行吗?

r - 将值映射到 data.table 的简洁明了的习语是什么

R - 将列表转换为数据帧

r - 如何获得R绘图窗口大小?

r - purrr::accumulate() 作用于两个累积变量,而不仅仅是 1

regex - 从 R 中的字符串中提取日期

r - 将 R 数据帧从长格式转换为宽格式,但组大小不相等,用于 qcc

r - 使用选择点绘制功效回归时 stat_smooth 出现错误

r - 数据表中的相关矩阵