【问题标题】:How to calculate difference in time between variable rows in R?如何计算R中变量行之间的时间差?
【发布时间】:2017-03-10 01:01:36
【问题描述】:

我希望根据开始工作时间和结束工作时间计算不同组的时间差异。我如何告诉 R 根据它们在一组中的标签计算两行之间的差异时间?下面是一个样本数据集:

library(data.table)


latemail <- function(N, st="2012/01/01", et="2012/02/01") {
  st <- as.POSIXct(as.Date(st))
  et <- as.POSIXct(as.Date(et))
  dt <- as.numeric(difftime(et,st,unit="sec"))
  ev <- sort(runif(N, 0, dt))
  rt <- st + ev

}

#create our data frame
set.seed(42)
dt = latemail(20)
work = setDT(as.data.frame(dt))
work[,worker:= stringi::stri_rand_strings(2, 5)]  
work[,dt:= as.POSIXct(as.character(work$dt), tz = "GMT")]
work[,status:=NA]

#order
setorder(work, worker, dt)

#add work times
work$status[1] = "start"
work$status[5] = "end"
work$status[6] = "start"
work$status[10] = "end"
work$status[11] = "start"
work$status[15] = "end"
work$status[16] = "start"
work$status[20] = "end"

现在的表格是这样的:

                    dt worker status
 1: 2012-01-04 23:11:31  VOuRp  start
 2: 2012-01-09 15:53:16  VOuRp     NA
 3: 2012-01-15 02:56:45  VOuRp     NA
 4: 2012-01-16 21:12:26  VOuRp     NA
 5: 2012-01-20 16:27:31  VOuRp    end
 6: 2012-01-22 15:34:05  VOuRp  start
 7: 2012-01-23 15:01:18  VOuRp     NA
 8: 2012-01-29 03:36:56  VOuRp     NA
 9: 2012-01-29 20:11:02  VOuRp     NA
10: 2012-01-31 02:48:01  VOuRp    end
11: 2012-01-04 10:24:38  u8zw5  start
12: 2012-01-08 17:02:20  u8zw5     NA
13: 2012-01-14 23:33:35  u8zw5     NA
14: 2012-01-15 12:23:52  u8zw5     NA
15: 2012-01-18 03:53:15  u8zw5    end
16: 2012-01-21 03:48:08  u8zw5  start
17: 2012-01-23 02:01:10  u8zw5     NA
18: 2012-01-26 12:51:10  u8zw5     NA
19: 2012-01-29 18:23:46  u8zw5     NA
20: 2012-01-29 22:22:14  u8zw5    end

我正在寻找的答案: 最终我想获得底部值(标记为工人 1 和工人 2 只是因为不确定如何为 stringi 执行set.seed() 的并行)。以下代码为工人 1 提供了第一行,但我希望每个工人的每个班次:

difftime(as.POSIXct("2012-01-20 16:27:31"), as.POSIXct("2012-01-04 23:11:31"), units = "hours")
    Work time   time difference in hours  
    worker 1         377.2667 hours
    worker 2         . . . . 

在这个例子中,我在工人之间有一组偶数的值,但是假设我在不同的工人之间有可变的行,那会是什么样子?我假设某种 difftime 公式?当我处理大数据时,我会更喜欢数据表解决方案。

【问题讨论】:

  • 你如何得到这样的数字? (172.6158 和 388.6102)。对我来说,不清楚你想得到什么。
  • 对不起,我算错了。我正在寻找从每个开始的每个结束的差异,例如:difftime(as.POSIXct("2012-01-20 16:27:31"), as.POSIXct("2012-01-04 23:11: 31"), units = "hours") 用于工人 1 的第一个班次,然后在下一个班次相同

标签: r data.table difftime


【解决方案1】:

这是使用data.table的解决方案:

 work[status %in% c("start", "end"), 
        time.diff := ifelse(status == "start", 
        difftime(shift(dt, fill = NA, type = "lead"), dt, units = "hours"), NA), 
        by = worker][status == "start", sum(time.diff), worker]

我们得到:

 worker       V1
1:  VOuRp 580.4989
2:  u8zw5 540.0453
> 

其中V1 是每个工作人员从开始到结束间隔的所有小时数的总和。

让我们一步一步地解释它以便更好地理解。

步骤 1. 选择所有具有startend 状态的行:

work.se <- work[status %in% c("start", "end")]

                    dt worker status
1: 2012-01-04 23:11:31  VOuRp  start
2: 2012-01-20 16:27:31  VOuRp    end
3: 2012-01-22 15:34:05  VOuRp  start
4: 2012-01-31 02:48:01  VOuRp    end
5: 2012-01-04 10:24:38  u8zw5  start
6: 2012-01-18 03:53:15  u8zw5    end
7: 2012-01-21 03:48:08  u8zw5  start
8: 2012-01-29 22:22:14  u8zw5    end
> 

STEP 2:创建一个函数,用于计算当前行与下一行之间的时间差。此函数将在 data.table 对象内调用。我们使用同一个包中的shift 函数:

getDiff <- function(x) {
    difftime(shift(x, fill = NA, type = "lead"), x, units = "hours")
}

getDiff 计算下一条记录(组内)与当前记录的时间差。它为最后一行分配NA,因为没有下一个值。然后我们从计算中排除NA 值。

第 3 步:在 data.table 语法中调用它:

work.result <- work.se[, time.diff := ifelse(status == "start", 
    getDiff(dt), NA), by = worker]

我们明白了:

                    dt worker status time.diff
1: 2012-01-04 23:11:31  VOuRp  start  377.2667
2: 2012-01-20 16:27:31  VOuRp    end        NA
3: 2012-01-22 15:34:05  VOuRp  start  203.2322
4: 2012-01-31 02:48:01  VOuRp    end        NA
5: 2012-01-04 10:24:38  u8zw5  start  329.4769
6: 2012-01-18 03:53:15  u8zw5    end        NA
7: 2012-01-21 03:48:08  u8zw5  start  210.5683
8: 2012-01-29 22:22:14  u8zw5    end        NA

第 4 步:对每个工作人员的 time.diff 列的非 NA 值求和:

> work.result[status == "start", sum(time.diff), worker]
   worker       V1
1:  VOuRp 580.4989
2:  u8zw5 540.0453
> 

data.table 对象可以通过附加的[] 连接,因此可以合并为一个句子作为最后一部分:

work.se[, time.diff := ifelse(status == "start", 
    getDiff(dt), NA), by = worker][status == "start", sum(time.diff), worker]

FINAL:将所有内容放在一个句子中:

work[status %in% c("start", "end"), 
    time.diff := ifelse(status == "start", 
    difftime(shift(dt, fill = NA, type = "lead"), dt, units = "hours"), NA), 
    by = worker][status == "start", sum(time.diff), worker]

查看link 了解data.table 基本语法。 我希望这会有所帮助,如果这是您想要的,请告诉我们

【讨论】:

  • 谢谢大卫!这对于数据集的第一个版本是有意义的。我想知道如何处理我的编辑版本?每个驱动程序有两组或多组起点和终点?
  • 这非常有帮助,正是我所需要的。谢谢大卫!
  • 当我尝试运行函数 )getDiff &lt;- function(x) { difftime(shift(x, fill = NA, type = "lead"), x, units = "hours") } 时,出现错误:Error in shift(x, fill = NA, type = "lead") : object 'x' not found
猜你喜欢
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 2016-04-23
  • 1970-01-01
相关资源
最近更新 更多