# Go back to Flu Mortality # #

MLE fitting

# parameters and return values see the wiki # this returns a list containing named pairs: # fit=mls object decribing best fit # conf=the 95% confidence interval

exp_fit_given_logL ← function(times, data, theta0, model, logL) {

# construct a general negative log-likelyhood function
L <- function() {
	# reconstruct the vector of named pairs of 
	# parameters from the list of arguments
	l=length(theta0)
	theta=c()
	vars=names(theta0)
	for (i in 1:l) {
		item=c(x=get(vars[i]))
		names(item) <- vars[i]
		theta <-c(theta, item)
	}
	# compute the mean from the model
	mean <- model(times=times, data=data, theta=theta)
	# compute the negative log-likelihood
	L = -logL(theta, data, mean)
	# if not a number, return a very small likelihood
	if (is.na(L)) return(1e10)
	return(L)
}
# replace the input arguments of L by the list of parameters
formals(L)<-as.list(theta0)
# mle2
# sometimes confint may find a better solution. 
# In this case we need to refit the model with the better
# solution as a starting paoint, because the parameter
# names in the returned better fit can be wrong
fit=mle2(L, method='Nelder-Mead', start=as.list(theta0), control=list(maxit=1e6*length(theta0), ndeps=1e-4, reltol=1e-10))
# fit=mle2(L, method='BFGS', start=as.list(theta0), control=list(maxit=1e5*length(theta0), reltol=1e-10))
# if there is only one parameter to be fitted
# the returned confidence interval is a vector
# change it to a matrix
return(fit)

}

exp_fit ← function(times, data, theta0, model) {

# we start with negative binomial
# if theta0 contains no r, 
if (is.na(theta0['r']))
	theta0 = c(theta0, r=0.0001)
while (TRUE) {
	no_r = is.na(theta0['r']);
	if (!no_r)
	 	p = exp_fit_given_logL(times, data, theta0, model, loglik_negbin)
	# if the fitted shape parameter r is too small (<0.001)
	# then it is approximately poisson 
	# in this case we use poisson
	if (no_r || coef(p)['r'] < 0.001) {
		# we need to remove r from theta
		if (!no_r) {
			old_theta0 = coef(p)
			theta0 = c()
			for (i in 1:length(old_theta0))
				if (names(old_theta0[i]) != 'r')
					theta0 = c(theta0, old_theta0[i])
		}
		p = exp_fit_given_logL(times, data, theta0, model, loglik_poisson)
	}
	conf = confint(p)
	if (is.vector(conf)) conf = matrix(conf, nrow=1)
	if (is.matrix(conf)) break 
	# if we reach here, confint must have found a 
	# better solution. we need to repeat
	theta0 = coef(conf)
	names(theta0) <- names(coef(p))
}
return(list(fit=p, conf=conf, r=coef(p)['r']))

}

#

Log-likelihood: Negative Binomial

loglik_negbin ← function(theta, data, mean) {

# for neative bimonial, mean = r p /(1-p)
r = 1 / theta['r'];
# if r < 0, return a tiny likelihood
if (r<0)
	return(-1e10)
sum(dnbinom(x=data, size=r, mu=mean, log=TRUE))

}

#

Log-likelihood function: Poisson

loglik_poisson ← function(theta, data, mean) {

sum(dpois(x=data, lambda=mean, log=TRUE))

}

#

The SIR model: the exponential curve

model_SIR ← function(times, data, theta) {

SIR <- function(t, x, theta) {
	with(as.list(c(x, theta)), {
		DecreaseS = -1 * beta * S * I / N
		DecreaseI = -1 * alpha * I
		dS = DecreaseS
		dI = -1 * DecreaseS + DecreaseI
		return(list(c(dS, dI)))
	})
}

with(as.list(theta), {
	N = S+I
	y = ode(c(S=S, I=I), times, SIR, c(beta=beta, alpha=alpha, N=N), method='ode45')
	return(-diff(c(N,y[, 'S'])))
})

}