有几种方法可以解决这个问题,但让我们从一个已知点开始:
dat <- data.frame(
hour = c("5:00:00", "6:00:00", "7:00:00"),
attraction = c(1, 3, 6)
)
dat$hour <- as.POSIXct(dat$hour, format = "%H:%M:%S")
dat
# hour attraction
# 1 2020-01-12 05:00:00 1
# 2 2020-01-12 06:00:00 3
# 3 2020-01-12 07:00:00 6
由于您希望进行基于时间的计算,我将hour 设置为POSIXt 类型。 (如果您的数据中也有“日期”部分,则需要将其包含在转换中,但如果总是在同一天,那么它似乎并不重要。)
从这里,我们可以为每次到达引入随机分钟数:
set.seed(42)
dat2 <- do.call(
"rbind.data.frame",
Map(function(hr, n) data.frame(hour = hr, min = round(runif(n, min = 0, max = 59))),
dat$hour, dat$attraction)
)
dat2
# hour min
# 1 2020-01-12 05:00:00 54
# 2 2020-01-12 06:00:00 55
# 3 2020-01-12 06:00:00 17
# 4 2020-01-12 06:00:00 49
# 5 2020-01-12 07:00:00 38
# 6 2020-01-12 07:00:00 31
# 7 2020-01-12 07:00:00 43
# 8 2020-01-12 07:00:00 8
# 9 2020-01-12 07:00:00 39
# 10 2020-01-12 07:00:00 42
我不知道你是单独需要分钟还是实时,所以也许
dat2$arrival_time <- dat2$hour + (60 * dat2$min)
dat2
# hour min arrival_time
# 1 2020-01-12 05:00:00 54 2020-01-12 05:54:00
# 2 2020-01-12 06:00:00 55 2020-01-12 06:55:00
# 3 2020-01-12 06:00:00 17 2020-01-12 06:17:00
# 4 2020-01-12 06:00:00 49 2020-01-12 06:49:00
# 5 2020-01-12 07:00:00 38 2020-01-12 07:38:00
# 6 2020-01-12 07:00:00 31 2020-01-12 07:31:00
# 7 2020-01-12 07:00:00 43 2020-01-12 07:43:00
# 8 2020-01-12 07:00:00 8 2020-01-12 07:08:00
# 9 2020-01-12 07:00:00 39 2020-01-12 07:39:00
# 10 2020-01-12 07:00:00 42 2020-01-12 07:42:00
我应该注意,您使用 rnorm "can" 会导致负分钟数,因为它是渐近无限的;使用sd=10 当然会降低可能性,但是如果您需要随机到达时间“始终”在指定的小时内,那么您使用runif 会更好,或者您可以考虑截断正态分布,例如提供通过truncnorm 包。
注意:我使用Map,它是lapply 的多参数版本。使用 R 的 apply 系列中的函数通常具有优势(有时在性能方面,有时在可读性方面),虽然性能优势大部分已被减轻(历史上 for 通常比 sapply 慢),但仍有一些人发现 @987654339 @ 更好的。对于Map,我写了一些答案来解释(通过“展开”它)它是如何工作的:https://stackoverflow.com/a/57367292 和https://stackoverflow.com/a/54485425。
要获得入住率(给定时间段内有多少辆车),我建议您使用cut 来分类到达时间。我们可以通过以下方式创建 bin 边界:
myseq <- round(range(dat2$arrival_time) + c(-1800,1800), "hour")
myseq
# [1] "2020-01-12 05:00:00 PST" "2020-01-12 08:00:00 PST"
myseq <- seq.POSIXt(myseq[1], myseq[2], by = "min")
length(myseq)
# [1] 181
myseq <- myseq[seq_along(myseq) %% 10 == 1]
myseq
# [1] "2020-01-12 05:00:00 PST" "2020-01-12 05:10:00 PST" "2020-01-12 05:20:00 PST"
# [4] "2020-01-12 05:30:00 PST" "2020-01-12 05:40:00 PST" "2020-01-12 05:50:00 PST"
# [7] "2020-01-12 06:00:00 PST" "2020-01-12 06:10:00 PST" "2020-01-12 06:20:00 PST"
# [10] "2020-01-12 06:30:00 PST" "2020-01-12 06:40:00 PST" "2020-01-12 06:50:00 PST"
# [13] "2020-01-12 07:00:00 PST" "2020-01-12 07:10:00 PST" "2020-01-12 07:20:00 PST"
# [16] "2020-01-12 07:30:00 PST" "2020-01-12 07:40:00 PST" "2020-01-12 07:50:00 PST"
# [19] "2020-01-12 08:00:00 PST"
first 命令 查找时间范围并将其out 舍入到下一小时。 (+c(-1800,1800) 的使用确保回合将分别给我们一个地板和天花板。这可能会发现不完美的极端情况,但它应该在大多数情况下工作。) 第二个命令创建一个每分钟的序列,此处为 181 长(三个小时)。 第三条命令 将其缩短为每 10 分钟一次。
您应该能够根据需要轻松调整这三个命令。
从这里,你可以使用
cut(dat2$arrival_time, myseq)
# [1] 2020-01-12 05:50:00 2020-01-12 06:50:00 2020-01-12 06:10:00 2020-01-12 06:40:00
# [5] 2020-01-12 07:30:00 2020-01-12 07:30:00 2020-01-12 07:40:00 2020-01-12 07:00:00
# [9] 2020-01-12 07:30:00 2020-01-12 07:40:00
# 18 Levels: 2020-01-12 05:00:00 2020-01-12 05:10:00 2020-01-12 05:20:00 ... 2020-01-12 07:50:00
它会告诉您每次到达属于哪个 10 分钟垃圾箱。快速总结可以用
table(cut(dat2$arrival_time, myseq))
# 2020-01-12 05:00:00 2020-01-12 05:10:00 2020-01-12 05:20:00 2020-01-12 05:30:00
# 0 0 0 0
# 2020-01-12 05:40:00 2020-01-12 05:50:00 2020-01-12 06:00:00 2020-01-12 06:10:00
# 0 1 0 1
# 2020-01-12 06:20:00 2020-01-12 06:30:00 2020-01-12 06:40:00 2020-01-12 06:50:00
# 0 0 1 1
# 2020-01-12 07:00:00 2020-01-12 07:10:00 2020-01-12 07:20:00 2020-01-12 07:30:00
# 1 0 0 3
# 2020-01-12 07:40:00 2020-01-12 07:50:00
# 2 0