我正在构建基于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
答案 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
:
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
}