Reputation: 311
Consider the following code, that solves a system of DE such as Lotka–Volterra. It stores the solution in a list called "out" for 4 different cases. I have 2 questions:
(1) How can I calculate the sum of rows at each time step for 4 cases and store into a vector? I tried to use, apply(out[[i]][,1:2],1,sum)
but it produces an error as follows
Error in FUN(newX[, i], ...) : invalid 'type' (list) of
(2) Can you please explain the structure of output? and why it is not working while it works with matrices. I tried to create a similar list using random numbers, but could no reproduce the similar structure.
Thanks.
rm(list=ls())
library("foreach")
library("deSolve")
library(doParallel)
cl<-makeCluster(2, outfile = "debug.txt")
registerDoParallel(cl)
CASES = 4
LVmod <- function(Time, State, Pars) {
with(as.list(c(State, Pars)), {
Ingestion <- rIng * Prey * Predator
GrowthPrey <- rGrow * Prey * (1 - Prey/K)
MortPredator <- rMort * Predator
dPrey <- GrowthPrey - Ingestion
dPredator <- Ingestion * assEff - MortPredator
return(list(c(dPrey, dPredator)))
})
}
solveODE<-function(times, LVmod, pars, yini, CASES){
output<-foreach(x=1:CASES, .packages=c('deSolve')) %dopar%
{
if (x<CASES) ode(yini[[x%%CASES]], times, LVmod, pars)
else ode(yini[[CASES]], times, LVmod, pars)
}
}
pars <- c(rIng = 0.2, # /day, rate of ingestion
rGrow = 1.0, # /day, growth rate of prey
rMort = 0.2 , # /day, mortality rate of predator
assEff = 0.5, # -, assimilation efficiency
K = 10) # mmol/m3, carrying capacity
yini<-list()
yini[[1]]<-c(Prey = 1, Predator = 2)
yini[[2]]<-c(Prey = 5, Predator = 5)
yini[[3]]<-c(Prey = 2, Predator = 3)
yini[[4]]<-c(Prey = 4, Predator = 2)
out<-list()
for (i in 1:CASES) out[[i]]<-list()
for (i in 0:20){
times <- seq(10*i, 10*(i+1), by = 1)
output<-solveODE(times, LVmod, pars, yini, CASES)
for (j in 1:CASES){
out[[j]]<-rbind(out[[j]],output[[j]])
ic11<-out[[j]][length(out[[j]][,1]),2]
ic12<-out[[j]][length(out[[j]][,1]),3]
yini[[j]] <- c(Prey = as.numeric(ic11), Predator = as.numeric(ic12))
}
}
stopCluster(cl)
Upvotes: 0
Views: 106
Reputation: 50668
Use lapply
instead of apply
to loop through list
elements; for example, to calculate the sum of values in the second column Prey
for every list element you can do:
lapply(out, function(x) sum(as.numeric(x[, 2])))
#[[1]]
#[1] 468.3304
#
#[[2]]
#[1] 461.0533
#
#[[3]]
#[1] 464.6915
#
#[[4]]
#[1] 469.421
As for your second question: "Can you please explain the structure of output?" Well, considering that this is your code, that really is something you should know, isn't it. According to your code, you are constructing a list
of list
s:
out<-list()
for (i in 1:CASES) out[[i]]<-list()
PS. You really should format your code properly. Use proper indentations, align matching brackets, etc. It will make your code a lot easier to read!
If you want to calculate the sum of Prey
and Predator
for every time
, you can use rowSums
inside lapply
:
lst <- lapply(out, function(x) rowSums(as.data.frame(matrix(unlist(x), ncol = 3))[, 2:3]))
as.data.frame(matrix(unlist(x), ncol = 3))
converts your list
into a data.frame
.
You can column-bind the list
entries using cbind
:
df <- do.call(cbind, lst));
head(df);
# [,1] [,2] [,3] [,4]
#[1,] 3.000000 10.000000 5.000000 6.000000
#[2,] 3.490136 9.051351 5.445284 7.034600
#[3,] 4.359623 8.130653 5.915932 7.644949
#[4,] 5.467660 7.246250 6.317925 7.842548
#[5,] 6.517990 6.444182 6.589044 7.730863
#[6,] 7.255411 5.759818 6.711389 7.420815
The rows correspond to the different time
values, the columns to the different CASES
.
Upvotes: 2