Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing negative values in a model (system of ODEs) with zero

I'm currently working on solving a system of ordinary differential equations using deSolve, and was wondering if there's any way of preventing differential variable values from going below zero. I've seen a few other posts about setting negative values to zero in a vector, data frame, etc., but since this is a biological model (and it doesn't make sense for a T cell count to go negative), I need to stop it from happening to begin with so these values don't skew the results, not just replace the negatives in the final output.

like image 849
Dorian Avatar asked Jan 14 '17 10:01

Dorian


People also ask

How do I replace negative numbers with zeros in R?

To convert negative values in a matrix to 0, we can use pmax function. For example, if we have a matrix called M that contains some negative and some positive and zero values then the negative values in M can be converted to 0 by using the command pmax(M,0).

How do I remove negative values from a Dataframe in R?

This can be done by using abs function. For example, if we have a data frame df with many columns and each of them having some negative values then those values can be converted to positive values by just using abs(df).


1 Answers

My standard approach is to transform the state variables to an unconstrained scale. The most obvious/standard way to do this for positive variables is to write down equations for the dynamics of log(x) rather than of x.

For example, with the Susceptible-Infected-Recovered (SIR) model for infectious disease epidemics, where the equations are dS/dt = -beta*S*I; dI/dt = beta*S*I-gamma*I; dR/dt = gamma*I we would naively write the gradient function as

gfun <- function(time, y, params) {
   g <- with(as.list(c(y,params)),
       c(-beta*S*I,
          beta*S*I-gamma*I,
          gamma*I)
       )
   return(list(g))
}

If we make log(I) rather than I be the state variable (in principle we could do this with S as well, but in practice S is much less likely to approach the boundary), then we have d(log(I))/dt = (dI/dt)/I = beta*S-gamma; the rest of the equations need to use exp(logI) to refer to I. So:

gfun_log <- function(time, y, params) {
   g <- with(as.list(c(y,params)),
       c(-beta*S*exp(logI),
          beta*S-gamma,
          gamma*exp(logI))
       )
   return(list(g))
}

(it would be slightly more efficient to compute exp(logI) once and store/re-use it rather than computing it twice ...)

like image 71
Ben Bolker Avatar answered Sep 27 '22 22:09

Ben Bolker