首页 文章

计算时间间隔

提问于
浏览
4

我正在构建基于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$machine 下"M2"的值的原始数据帧 df 的部分时,我想我也会遇到麻烦,因为它也会计算这些 . 我最终会想要分别绘制每台机器 . 也许为每个"machine"使用 subset 将是一种快速分区数据的方法,但最后我会得到每个"machine"的数据帧 . 不是问题,但是有一种优雅的方法可以在上面的命令中构建"machine"吗?

问题3.在previous post中,他们的计数出现在"top of the hour",这可能是每小时间隔的"end time" . 但是用它们呈现的小数据集检查它并不容易 . 在我自己的数据中,计数似乎已经消失 . 休息时间=小时,我应该期待什么计数?

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

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

我的实际数据

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

  • 1

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

    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)]))
    
  • 3

    您可以使用 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)))
    
  • 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
    }
    

相关问题