计算时间间隔

时间:2014-01-27 08:37:00

标签: r

我正在构建基于this helpful post的内容。 我有三个与数据集df相关的问题:

    machine     ISOdatetime
1   M1      2013-08-21 18:16:39
2   M1      2013-08-21 18:20:44
3   M1      2013-08-21 18:21:42
4   M1      2013-08-21 18:46:09
5   M1      2013-08-21 18:46:27
6   M1      2013-08-21 19:01:13
etc

我想弄清楚在半小时内会出现多少个值并放入一个新的数据框,如下所示:

    machine     ISOdatetime     numberobs
1   M1      2013-08-21 18:30:00     3
2   M1      2013-08-21 19:00:00     2
3   M1      2013-08-21 19:30:00     1
etc

以下代码当然适用于整洁的每小时长度:

df2 <- data.frame(table(cut(df$ISOdatetime, breaks="hour")))

以下代码在30分钟的时间内计算,但不会在每小时/半小时点整齐地开始(它从第一个列出的时间开始,即18:16:39,并指定从18:16开始: 00):

df2 <-data.frame(table(cut(df$ISOdatetime, breaks = "30 mins")))

问题1.什么可能是一个优雅的解决方案?我应该用类似的东西指定所需的间隔 ints <-c("18:00", "18:30", "19:00" ...) ,还是没必要?

问题2.我认为当我到达df下具有“M2”值的原始数据帧df$machine的部分时,我也会遇到麻烦,因为它也会计算这些值。我最终会想要分别绘制每台机器。也许对每个“机器”使用subset将是一种快速分区数据的方法,但最后我会得到每个“机器”的数据帧。不是问题,但是有一种优雅的方法可以在上面的命令中构建“机器”吗?

问题3.在previous post中,他们的计数是在“最高时间”出现的,这可能是每小时间隔的“结束时间”。但是用它们呈现的小数据集检查它并不容易。在我自己的数据中,计数似乎已经消失。在休息时间=小时的情况下,我应该期待什么计数?

最近几个小时已阅读并尝试了很多但仍然卡住了,非常感谢。

根据要求,我添加了更多信息。

我的实际数据

    unit    nightof     time        date        isodatetime             time2
1   7849    2013-08-21  18:16:39    2013-08-21  2013-08-21 18:16:39     2013-08-22 04:00:00
2   7849    2013-08-21  18:20:44    2013-08-21  2013-08-21 18:20:44     2013-08-22 04:00:00
3   7849    2013-08-21  18:21:42    2013-08-21  2013-08-21 18:21:42     2013-08-22 04:00:00
etc
406 7849    2013-08-21  04:06:10    2013-08-22  2013-08-22 04:06:10     2013-08-22 14:00:00
407 7849    2013-08-21  04:06:12    2013-08-22  2013-08-22 04:06:12     2013-08-22 14:00:00
408 7849    2013-08-21  04:06:28    2013-08-22  2013-08-22 04:06:28     2013-08-22 14:00:00

当我str()

'data.frame':       408 obs. of  6 variables:
$ unit:         int  7849 7849 7849 7849 7849 7849 7849 7849 7849 7849 ...
$ nightof:  Date, format: "2013-08-21" "2013-08-21" "2013-08-21" "2013-08-21" ...
$ time:     List of 408
..$ : chr "18:16:39"
..$ : chr "18:20:44"
.. [list output truncated]
$ date:     Date, format: "2013-08-21" "2013-08-21" "2013-08-21" "2013-08-21" ...
$ isodatetime:  POSIXlt, format: "2013-08-21 18:16:39" "2013-08-21 18:20:44" "2013-08-21 18:21:42" "2013-08-21 18:21:48" ...
$ time2:        POSIXct, format: "2013-08-22 04:00:00" "2013-08-22 04:00:00" "2013-08-22 04:00:00" "2013-08-22 04:00:00" ...

我使用的修改代码:

`mon$time2 <- with(mon, as.POSIXct(ceiling(as.numeric(isodatetime)/(30*60)) * (30*60), origin = "1970-01-01"))
with(mon, data.frame(table(time2)))
by(mon, mon$unit, function(x){data.frame(table(x$time2))})`

输出。

mon$unit:   7849
                Var1        Freq
1   2013-08-22 04:00:00     27
2   2013-08-22 04:30:00     13
3   2013-08-22 05:00:00     16
4   2013-08-22 05:30:00     5
5   2013-08-22 06:00:00     8
6   2013-08-22 06:30:00     10
7   2013-08-22 07:00:00     25
8   2013-08-22 07:30:00     22
9   2013-08-22 08:00:00     61
10  2013-08-22 08:30:00     93
11  2013-08-22 09:00:00     54
12  2013-08-22 09:30:00     42
13  2013-08-22 10:00:00     11
14  2013-08-22 10:30:00     2
15  2013-08-22 11:00:00     2
16  2013-08-22 11:30:00     3
17  2013-08-22 12:00:00     2
18  2013-08-22 13:00:00     1
19  2013-08-22 14:00:00     11

3 个答案:

答案 0 :(得分:3)

您可以使用lubridate包从日期对象中提取小时,分钟等。如果你知道活动时间的那一刻,你知道事件发生的半小时。我用两台机器采样了一些数据。我添加了一个变量的“整个”半小时之后事件发生的地方,然后你可以算这些。希望这就是你所追求的,祝你好运。

require(lubridate)
set.seed(1234)
example.dat <- data.frame(
  machine = paste("M", sample(1:2, 100, replace = T), sep = ""),
  dates = sort(as.POSIXct(sample(1377100000:1377110000, 100), origin = "1960-01-01"))
  )
example.dat <- example.dat[order(example.dat$machine), ]

halfHours <- ifelse(minute(example.dat$dates) < 30, 0, 30)
example.dat$datesHH <- example.dat$dates
minute(example.dat$datesHH) <- halfHours; second(example.dat$datesHH) <- 0

data.frame(table(example.dat[ ,c(1,3)]))

答案 1 :(得分:1)

您可以使用ceiling

将时间的数字表示舍入到最接近的30分钟
df$time <- with(df, as.POSIXct(ceiling(as.numeric(ISOdatetime)/(30*60)) * (30*60),
                                origin = "1970-01-01"))

# counts for each combination of time and machine
with(df, data.frame(table(time, machine)))

答案 2 :(得分:0)

以下是一个旨在生成此类计数的函数。以下是其使用示例:

crashDate <- as.Date(c("1908-09-17","1912-07-12","1913-08-06",
                        "1913-09-09","1913-10-17"))
df <- data.frame(date=crashDate)
byYears <- DAAGviz::eventCounts(data=df, dateCol="date",
                                 from=as.Date("1908-01-01"),
                                 by="1 year")

输出是:

> byYears
            Date n_
    1 1908-01-01  1
    2 1909-01-01  0
    3 1910-01-01  0
    4 1911-01-01  0
    5 1912-01-01  1
    6 1913-01-01  3

参数categoryCol(字符)可选地指定 包含要对计数进行分类的类别的列的名称 (每个类别一列)。列takeOnly可选地包含文本 在数据框data的环境中计算时的字符串, 产生一个逻辑向量,限制要计数的行。 有效by参数的示例包括:"1 day""1 week""4 weeks", 或"1 month""1 quarter""1 year""10 years"。看到 help(seq.Date)

如果确实在基地或推荐中没有这样的功能 包裹,我可以提交以上内容,可能会稍加修改, 包括在内。

eventCounts <-
function (data, dateCol = "Date", from = NULL, to = NULL, by = "1 month", 
          categoryCol = NULL, takeOnly = NULL, prefix = "n_") 
{
    checkCols <- c(dateCol, categoryCol) %in% names(data)
    if (!is.null(categoryCol) & !all(checkCols)) {
        txt <- paste("Name(s)", c(dateCol, categoryCol)[!checkCols], 
                     "not found in", deparse(data))
        stop(txt)
    }
    if (!is.null(takeOnly)) {
        subdat <- eval(parse(text = takeOnly), data)
        data <- subset(data, subdat)
    }
    date <- data[, dateCol]
    if (!is(date, "Date")) {
        date <- try(as.Date(date), silent = TRUE)
        if (class(date) == "try-error") 
            stop(paste("Column", dateCol, "must hold a date object"))
    }
    if (is.null(from)) 
        from <- min(date)
    if (is.null(to)) 
        to <- max(date)
    dateBreaks <- seq(from = from, to = to, by = by)
    dateBreaks <- c(dateBreaks, max(dateBreaks) + diff(dateBreaks[1:2]))
    countDF <- data.frame(Date = dateBreaks[-length(dateBreaks)])
    if (!is.null(categoryCol)) 
        categs <- names(table(data[, categoryCol]))
    else categs <- ""
    for (cat in categs) {
        if (!is.null(categoryCol)) 
            select <- data[, categoryCol] == cat
        else select <- rep(TRUE, nrow(countDF))
        cutDates <- cut(date[select], dateBreaks, right = FALSE)
        countNam <- paste0(prefix, gsub(" ", "", cat))
        countDF[, countNam] <- as.vector(table(cutDates))
    }
    countDF
}