我的每一行都有一个包含时间事件的数据框。在一行中,我有发送者的事件类型(typeid = 1),另一行是接收者的事件(typeid = 2)。我想计算发送方和接收方之间的延迟(时差)。
我的数据以data.frame的形式组织,如下面的快照所示:
dd[1:10,]
timeid valid typeid
1 18,00035 1,00000 1
2 18,00528 0,00493 2
3 18,02035 2,00000 1
4 18,02116 0,00081 2
5 18,04035 3,00000 1
6 18,04116 0,00081 2
7 18,06035 4,00000 1
8 18,06116 0,00081 2
9 18,08035 5,00000 1
10 18,08116 0,00081 2
calc_DelayVIDEO <- function (dDelay ){
pktProcess <- TRUE
nLost <- 0
myDelay <- data.frame(time=-1, delay=-1, jitter=-1, nLost=-1)
myDelay <- myDelay[-1, ]
tini <- 0
tend <- 0
for (itr in c(1:length(dDelay$timeid))) {
aRec <- dDelay[itr,]
if (aRec$typeid == 1){
tini <- as.numeric(aRec$timeid)
if (!pktProcess ) {
nLost <- (nLost + 1)
myprt(paste("Packet Lost at time ", aRec$timeid, " lost= ", nLost, sep=""))
}
pktProcess <- FALSE
}else if (aRec$typeid == 2){
tend <- as.numeric(aRec$timeid)
dd <- tend - tini
jit <- calc_Jitter(dant=myDelay[length(myDelay), 2], dcur=dd)
myDelay <- rbind(myDelay, c(aRec$timeid, dd, jit, nLost))
pktProcess <- TRUE
#myprt(paste("time=", aRec$timeev, " delay=", dd, " Delay Var=", jit, " nLost=", nLost ))
}
}
colnames(myDelay) <- c("time", "delay", "jitter", "nLost")
return (myDelay)
}
要执行延迟计算,我使用calc_DelayVideo函数,对于具有大量记录(~60000)的数据帧,它需要花费大量时间。
如何用更优化的R函数替换for循环? 我可以用lapply来做这样的计算吗?如果是这样,你能举个例子吗?
提前致谢,
答案 0 :(得分:4)
通常的解决方案是仔细思考问题以找到矢量化的东西。
如果失败了,我有时会尝试用C ++重写循环; Rcpp包可以帮助界面。
答案 1 :(得分:2)
*apply
函数套件未针对循环进行优化。此外,我已经解决了for循环速度超过apply
的问题,因为apply
使用了更多内存并导致我的机器交换。
我建议完全初始化myDelay
对象并避免使用rbind
(必须重新分配内存):
init <- rep(NA, length(dDelay$timeid))
myDelay <- data.frame(time=init, delay=init, jitter=init, nLost=init)
然后替换:
myDelay <- rbind(myDelay, c(aRec$timeid, dd, jit, nLost))
与
myDelay[i,] <- c(aRec$timeid, dd, jit, nLost)
答案 2 :(得分:2)
正如Dirk所说:矢量化将有所帮助。一个例子是将调用移到as.numeric
循环(因为这个函数适用于向量)。
dDelay$timeid <- as.numeric(dDelay$timeid)
其他可能有用的事情
没有打扰aRec <- dDelay[itr,]
行,因为您只需访问dDelay
行,而无需创建新变量。
预分配myDelay
,因为它在循环中增长可能是一个瓶颈。有关此问题的更多信息,请参阅约书亚的答案。
答案 3 :(得分:0)
另一个优化:如果我正确读取你的代码,你可以使用:
轻松计算向量nLostnLost <-cumsum(dDelay$typeid==1)
在循环之外。那个你最后可以添加到数据帧中。为您节省了大量时间。如果我使用您的数据框,那么:
> nLost <-cumsum(dd$typeid==1)
> nLost
[1] 1 1 2 2 3 3 4 4 5 5
同样,丢失包裹的时间可以计算为:
> dd$timeid[which(dd$typeid==1)]
[1] 18,00035 18,02035 18,04035 18,06035 18,08035
如果您想在某处报告它们。
为了测试,我使用了:
dd <- structure(list(timeid = structure(1:10, .Label = c("18,00035",
"18,00528", "18,02035", "18,02116", "18,04035", "18,04116", "18,06035",
"18,06116", "18,08035", "18,08116"), class = "factor"), valid = structure(c(3L,
2L, 4L, 1L, 5L, 1L, 6L, 1L, 7L, 1L), .Label = c("0,00081", "0,00493",
"1,00000", "2,00000", "3,00000", "4,00000", "5,00000"), class = "factor"),
typeid = c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L)), .Names = c("timeid",
"valid", "typeid"), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6", "7", "8", "9", "10"))