【问题标题】:Binning data across interval boundaries跨区间边界对数据进行分箱
【发布时间】:2015-09-06 10:34:02
【问题描述】:

假设我有这些数据:

      start       end duration
1   2.67026  2.903822 0.233562
2   4.40529  5.606470 1.201180
3   9.24340 10.010818 0.767418
4  11.87930 13.414140 1.534840
5  14.78210 15.182492 0.400392
6  16.51720 16.817494 0.300294
7  22.08930 25.125610 3.036310
8  32.13240 33.667240 1.534840
9  45.47880 45.912558 0.433758
10 52.85270 54.454270 1.601570
11 55.62210 56.389518 0.767418

它们代表一分钟内发生的 11 个事件。每个都有一个开始和结束时间(以秒为单位)以及该事件的持续时间(以秒为单位)。

我要计算的是在每 10 秒的 bin/epoch 中花费了多少秒来处理这些事件。

data.table 中对数据进行分箱的标准方法是:

as.data.table(df)[, .(total = sum(duration)), by = .(INTERVAL = cut(end, seq(0,60,10)))]

   INTERVAL    total
1:   (0,10] 1.434742
2:  (10,20] 3.002944
3:  (20,30] 3.036310
4:  (30,40] 1.534840
5:  (40,50] 0.433758
6:  (50,60] 2.368988

但是,请注意,事件 3 开始于 9.24340 秒,结束于 10.010818 秒。此方法仅将区间 (0,10) 中前两个事件的持续时间相加。我希望第一个间隔包括 10-9.24340 = 0.7566 秒,即它应该是 2.19132 秒。这个数字应该从第二个间隔中减去,应该是 2.246344 秒。

在此示例中,0-10 / 10-20 秒是事件跨越切点的唯一时间,但是,显然我需要找到一个可以推广到任意数量的潜在切点的解决方案。

我认为一个解决方案可能是将时间转换为日期时间格式(包括毫秒?)并将其用于cut 数据,但是,我无法做到这一点。

编辑遵循@Arun 的回答:

@Arun 的回答很好地解决了上述问题。但是,如果我们想要包含所有区间——即使是总持续时间 = 0 的区间。

例子:

set.seed(1)
df<-
  data.frame(
    start=c(2.3, 3.5,6.7,9.4,10.4,13.5,16.3,18.1),
    duration=runif(8,0,1)
  )
df$end<-df$start+df$duration
dt<-data.table(df)
dt


   start  duration       end
1:   2.3 0.2655087  2.565509
2:   3.5 0.3721239  3.872124
3:   6.7 0.5728534  7.272853
4:   9.4 0.9082078 10.308208
5:  10.4 0.2016819 10.601682
6:  13.5 0.8983897 14.398390
7:  16.3 0.9446753 17.244675
8:  18.1 0.6607978 18.760798

按照 Arun 的解决方案:

lookup = data.table(start = seq(0, 18, by = 2), end = seq(2, 20, by = 2))
ans = foverlaps(dt, setkey(lookup, start, end))
ans[, sum(pmin(i.end, end) - pmax(i.start, start)), by=.(start,end)]

结果:

1:     2   4 0.6376326
2:     6   8 0.5728534
3:     8  10 0.6000000
4:    10  12 0.5098897
5:    12  14 0.5000000
6:    14  16 0.3983897
7:    16  18 0.9446753
8:    18  20 0.6607978

请注意,区间 0-2 和 4-6 不包括在结果中。显然,我们可以将它们绑定回去 - 但我想知道这是否可以通过调整 data.table 代码来完成?

【问题讨论】:

  • 为什么不将跨越两个 bin 的事件拆分为仅在一个 bin 中的两个事件?另外我建议不要对毫秒数据使用日期时间格式,因为存在一些问题:stackoverflow.com/questions/7726034/…

标签: r data.table


【解决方案1】:

这是我能想到的foverlaps() 的一种方式。

require(data.table) # v1.9.5+ (due to bug fixes in foverlaps for double)
lookup = data.table(start = seq(0, 50, by = 10), end = seq(10, 60, by = 10))
#    start end
# 1:     0  10
# 2:    10  20
# 3:    20  30
# 4:    30  40
# 5:    40  50
# 6:    50  60

ans = foverlaps(dt, setkey(lookup, start, end))
ans[, sum(pmin(i.end, end) - pmax(i.start, start)), by=.(start,end)]
#    start end       V1
# 1:     0  10 2.191342
# 2:    10  20 2.246344
# 3:    20  30 3.036310
# 4:    30  40 1.534840
# 5:    40  50 0.433758
# 6:    50  60 2.368988

我觉得那里可能有更好的选择..

【讨论】:

  • 这似乎工作得很好 - 但是,如果总持续时间为零,它会降低间隔。例如尝试将间隔更改为每 2 秒。有没有办法保持 V1 的零值?
  • IIUC,只需交换参数(并键入 dt 代替)应该可以让您到达那里,并相应地更改 j
  • 我编辑了我的问题,希望能更清楚一点。
  • 谢谢。但这个提示仍然成立。您所要做的就是扭转论点,然后从那里拿走它。我会把这点留给你去试验和弄清楚。
  • 好的,这似乎有效:ans = foverlaps(lookup, setkey(dt, start, end)); ans[, sum(pmin(i.end, end) - pmax(i.start, start)), by=.(i.start,i.end)]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-22
  • 1970-01-01
  • 2017-11-24
  • 1970-01-01
相关资源
最近更新 更多