1)根据样本数据,我们假设数据的格式为 hh:mm:00,其中 hh
读入测试数据。创建两个函数,将 hh:mm:00 形式的字符串转换为分钟数,以及一个将分钟数转换为时间的函数"times"
目的。为每行数据创建分钟序列,给出Intervals
列表。联合那些对应于给出列表的相同开关的序列Intervals.u
然后将该列表的组件相交以给出序列Intersection
。计算运行次数,r
, in Intersection
给出一组起点和终点。最后计算分钟数并将其转换为"times"
班级持续时间。 (分钟数和持续时间仅取决于r
and Intersection
所以我们可以跳过以##结尾的行 ifintervals.df
不需要。)
# test data
Lines <- "Switches,State,Intime,Outtime
sw3,1,9:00:00,10:40:00
sw2,1,9:30:00,10:15:00
sw1,1,10:00:00,11:00:00
sw2,1,10:20:00,10:30:00"
DF <- read.csv(text = Lines, as.is = TRUE)
library(chron)
to.num <- function(x) floor(as.numeric(times(x)) * 24 * 60 + 1e-6)
to.times <- function(x) times(x / (24 * 60))
Seq <- function(r) seq(to.num(DF$Intime[r]), to.num(DF$Outtime[r]))
Intervals <- lapply(1:nrow(DF), Seq)
Intervals.u <- lapply(split(Intervals, DF$Switches),
function(L) Reduce(union, L))
Intersection <- Reduce(intersect, Intervals.u)
r <- rle(c(FALSE, diff(Intersection) == 1))
i.ends <- cumsum(r$lengths)[r$values] ##
ends <- to.times(Intersection[i.ends]) ##
starts <- ends - to.times(r$lengths[r$values]) ##
intervals.df <- data.frame(start = starts, end = ends); intervals.df ##
## start end
## 1 10:00:00 10:15:00
## 2 10:20:00 10:30:00
mins <- length(Intersection) - sum(r$values); mins
## [1] 25
duration <- to.times(mins); duration
## [1] 00:25:00
2)关于与速度有关的注释,我们可以使用 IRanges 包,它可以有效地对范围进行编码,并且还可以稍微减少代码大小:
library(IRanges)
Intervals <- IRanges(to.num(DF$Intime), to.num(DF$Outtime))
Intersection <- Reduce(intersect, split(Intervals, DF$Switches))
intervals.df <- data.frame(start = to.times(start(Intersection)),
end = to.times(end(Intersection)))
intervals.df
## start end
## 1 10:00:00 10:15:00
## 2 10:20:00 10:30:00
mins <- sum(width(Intersection) - 1); mins
## [1] 25
duration <- to.times(mins); duration
## [1] 00:25:00
Updates一些修复和更好的变量名称。进一步改进。添加了(2)。