仿真时间很长,如何提高性能?
Simulation takes very long, how could performance be improved?
我目前正在使用 markovchain
包以及内部和外部循环进行马尔可夫链模拟。总共应将 1.752 亿个值插入到数据框中,可重现的示例代码如下。现在已经 运行 40 多个小时了,我想知道如何才能加快速度?我很好奇是否有人可以告诉我完成计算可能需要多长时间。
我已经使用 profvis
包改进了代码。
library(markovchain)
library(dplyr)
library(expss)
#States and creation of Markov transition matrix
Locations <- c("Home", "Bakery", "Grocery", "Home-Bakery", "Home-Grocery", "Bakery-Home", "Bakery-Grocery", "Grocery-Home", "Grocery-Bakery")
matrixExample <- matrix(sample(runif(81, min = 0 , max =1), replace = FALSE ), nrow = 9, ncol = 9)
matrixExample <- matrixExample / rowSums(matrixExample)
colnames(matrixExample) <- Locations
rownames(matrixExample) <- Locations
matrixExample <- as(matrixExample, "markovchain")
mcListLoop <- rep(list(matrixExample), 96)
mcList <- new("markovchainList", markovchains = mcListLoop)
z <- 10
numDays <- 365
k <- numDays * 96
battery <- 72.5
km <- runif(9, min = 5, max =120)
Locations <- c("Home", "Bakery", "Grocery", "Home-Bakery", "Home-Grocery", "Bakery-Home", "Bakery-Grocery", "Grocery-Home", "Grocery-Bakery")
averageDistance <- data.frame(cbind(Locations, km))
averageDistance$km <- as.numeric(averageDistance$km)
Iteration <- rep(seq(1:96), 365)
#Recreate dataframe
df <- data.frame(Iteration, sample(Locations, k, replace = TRUE))
df <- rmarkovchain(n=365, object = mcList, t0= "Home", include.t0 = TRUE)
#To estimate the size of list
allDf<- rep(list(df), z)
#Start of the loop
for(y in 1:z){
df <- rmarkovchain(n=365, object = mcList, t0= "Home", include.t0 = TRUE)
df$Begin <- 0
df[1,3] <- battery
df$Still <- ifelse(df$values == "Home", 1, 0)
df$KM <- vlookup(df$values, averageDistance, lookup_column = 1, result_column = 2)
df$Load <- ifelse(df$Still == 1, 2.75, 0)
df$costDistance <- df$KM * 0.21
df$End <- 0
df[is.na(df)] <- 0
df$reduce <- rep(seq(1:97), numDays)
df <- df %>% filter(reduce != 97)
df$Load <- ifelse(df$reduce <= 69 | df$reduce >= 87, df$Load, 0)
for(i in 1:k) {
mainVector <- df[i,3]
extra <- df[i,6]
subtractingVector <- df[i,7]
mainVector <- ifelse(mainVector < battery, pmin(mainVector + extra, battery), mainVector )
newMain <- mainVector - subtractingVector
j <- i + 1
df[j,3] <- newMain
}
allDf[[y]] <- df
}
在内循环中发生以下情况:
在对数据帧的相同观察中,我有电池 [i,3] 的启动容量以及它是充电 [i,6](停车时)还是放电 [i,7](驾驶时)。下一个观察 [j,3] 应该有第一个观察 [i,3] 中的起始容量校正(dis)电荷量([i,6] 或 [i,7])
我是 运行 我是 i7-8665CPU @ 1.90GHz 和 16gb RAM
您的代码似乎没有 运行 预期的那样,有多个变量定义不正确和两个相同的循环。不过估计是内循环写的不好
如果你有一些 df
和 charges/discharges:
df <- data.table(charge = c(0, 0, 1, 2), discharge = c(1, 2, 0, 0))
一些初始状态:
b <- 1
然后您想计算所有状态:
df$change <- df$charge - df$discharge
df$cumchange <- cumsum(df$change)
df$battery <- df$cumchange + b
df
# charge discharge change cumchange battery
# 1: 0 1 -1 -1 0
# 2: 0 2 -2 -3 -2
# 3: 1 0 1 -2 -1
# 4: 2 0 2 0 1
我认为你想要这样的内循环。
如果根据您的需要正确调整,这应该会快得多。
P.S。正如罗兰在这次改进后提到的那样 rmarkovchain
可能会成为瓶颈。
如果你想匹配你当前的计算,你可以用这个替换内部循环:
mainVector <- rep(0, nrow(df) + 1L) # pre-allocate resulting vector
state <- battery # state at each iteration
extra <- df[, 6]
subtractingVector <- df[, 7]
mainVector[1] <- state # add to resulting vector
for (i in 1:k) {
if (state < battery) state <- min(state + extra[i], battery)
state <- state - subtractingVector[i]
j <- i + 1L
mainVector[j] <- state
}
df[nrow(df) + 1, ] <- NA # add NA row, so we can add longer vector to df
df[, 3] <- mainVector
这里我们在循环之前将 data.frame
列分离为向量,并将结果存储在向量中。
我们在循环后将结果向量添加到 df
,因为循环中的大量时间花在了这个操作上 + 在 df
.
末尾添加新的 NA
行
这应该会快得多,但还可以进行其他改进。
我目前正在使用 markovchain
包以及内部和外部循环进行马尔可夫链模拟。总共应将 1.752 亿个值插入到数据框中,可重现的示例代码如下。现在已经 运行 40 多个小时了,我想知道如何才能加快速度?我很好奇是否有人可以告诉我完成计算可能需要多长时间。
我已经使用 profvis
包改进了代码。
library(markovchain)
library(dplyr)
library(expss)
#States and creation of Markov transition matrix
Locations <- c("Home", "Bakery", "Grocery", "Home-Bakery", "Home-Grocery", "Bakery-Home", "Bakery-Grocery", "Grocery-Home", "Grocery-Bakery")
matrixExample <- matrix(sample(runif(81, min = 0 , max =1), replace = FALSE ), nrow = 9, ncol = 9)
matrixExample <- matrixExample / rowSums(matrixExample)
colnames(matrixExample) <- Locations
rownames(matrixExample) <- Locations
matrixExample <- as(matrixExample, "markovchain")
mcListLoop <- rep(list(matrixExample), 96)
mcList <- new("markovchainList", markovchains = mcListLoop)
z <- 10
numDays <- 365
k <- numDays * 96
battery <- 72.5
km <- runif(9, min = 5, max =120)
Locations <- c("Home", "Bakery", "Grocery", "Home-Bakery", "Home-Grocery", "Bakery-Home", "Bakery-Grocery", "Grocery-Home", "Grocery-Bakery")
averageDistance <- data.frame(cbind(Locations, km))
averageDistance$km <- as.numeric(averageDistance$km)
Iteration <- rep(seq(1:96), 365)
#Recreate dataframe
df <- data.frame(Iteration, sample(Locations, k, replace = TRUE))
df <- rmarkovchain(n=365, object = mcList, t0= "Home", include.t0 = TRUE)
#To estimate the size of list
allDf<- rep(list(df), z)
#Start of the loop
for(y in 1:z){
df <- rmarkovchain(n=365, object = mcList, t0= "Home", include.t0 = TRUE)
df$Begin <- 0
df[1,3] <- battery
df$Still <- ifelse(df$values == "Home", 1, 0)
df$KM <- vlookup(df$values, averageDistance, lookup_column = 1, result_column = 2)
df$Load <- ifelse(df$Still == 1, 2.75, 0)
df$costDistance <- df$KM * 0.21
df$End <- 0
df[is.na(df)] <- 0
df$reduce <- rep(seq(1:97), numDays)
df <- df %>% filter(reduce != 97)
df$Load <- ifelse(df$reduce <= 69 | df$reduce >= 87, df$Load, 0)
for(i in 1:k) {
mainVector <- df[i,3]
extra <- df[i,6]
subtractingVector <- df[i,7]
mainVector <- ifelse(mainVector < battery, pmin(mainVector + extra, battery), mainVector )
newMain <- mainVector - subtractingVector
j <- i + 1
df[j,3] <- newMain
}
allDf[[y]] <- df
}
在内循环中发生以下情况: 在对数据帧的相同观察中,我有电池 [i,3] 的启动容量以及它是充电 [i,6](停车时)还是放电 [i,7](驾驶时)。下一个观察 [j,3] 应该有第一个观察 [i,3] 中的起始容量校正(dis)电荷量([i,6] 或 [i,7])
我是 运行 我是 i7-8665CPU @ 1.90GHz 和 16gb RAM
您的代码似乎没有 运行 预期的那样,有多个变量定义不正确和两个相同的循环。不过估计是内循环写的不好
如果你有一些 df
和 charges/discharges:
df <- data.table(charge = c(0, 0, 1, 2), discharge = c(1, 2, 0, 0))
一些初始状态:
b <- 1
然后您想计算所有状态:
df$change <- df$charge - df$discharge
df$cumchange <- cumsum(df$change)
df$battery <- df$cumchange + b
df
# charge discharge change cumchange battery
# 1: 0 1 -1 -1 0
# 2: 0 2 -2 -3 -2
# 3: 1 0 1 -2 -1
# 4: 2 0 2 0 1
我认为你想要这样的内循环。 如果根据您的需要正确调整,这应该会快得多。
P.S。正如罗兰在这次改进后提到的那样 rmarkovchain
可能会成为瓶颈。
如果你想匹配你当前的计算,你可以用这个替换内部循环:
mainVector <- rep(0, nrow(df) + 1L) # pre-allocate resulting vector
state <- battery # state at each iteration
extra <- df[, 6]
subtractingVector <- df[, 7]
mainVector[1] <- state # add to resulting vector
for (i in 1:k) {
if (state < battery) state <- min(state + extra[i], battery)
state <- state - subtractingVector[i]
j <- i + 1L
mainVector[j] <- state
}
df[nrow(df) + 1, ] <- NA # add NA row, so we can add longer vector to df
df[, 3] <- mainVector
这里我们在循环之前将 data.frame
列分离为向量,并将结果存储在向量中。
我们在循环后将结果向量添加到 df
,因为循环中的大量时间花在了这个操作上 + 在 df
.
NA
行
这应该会快得多,但还可以进行其他改进。