Poisson versus NB

建立於 差異永不過期
12 刪除
165 行
22 新增
170 行
# ---- fit poisson model with optim() ----
# ---- fit negative binomial model with optim() ----


# packages
# packages
library(tidyverse) # for glimpse() and ggplot()
library(tidyverse) # for glimpse() and ggplot()


# data; see ?crdata::holland2015
# data; see ?crdata::holland2015
holland <- crdata::holland2015 |>
holland <- crdata::holland2015 |>
filter(city == "santiago")
filter(city == "santiago")


# formula corresponds to model 1 for each city in holland (2015) table 2
# formula corresponds to model 1 for each city in holland (2015) table 2
f <- operations ~ lower + vendors + budget + population
f <- operations ~ lower + vendors + budget + population


# ---- create a function to fit the model ----
# ---- create a function to fit the model ----


# log-likelihood function
# log-likelihood function (NB2: Var(y|X)=mu + mu^2/theta)
poisson_ll <- function(beta, y, X) {
nb_ll <- function(par, y, X) {
beta <- par[1:ncol(X)]
theta <- par[ncol(X) + 1]
linpred <- X%*%beta # perhaps denoted eta
linpred <- X%*%beta # perhaps denoted eta
lambda <- exp(linpred)
mu <- exp(linpred)
ll <- sum(dpois(y, lambda = lambda, log = TRUE))
ll <- sum(dnbinom(y, mu = mu, size = theta, log = TRUE))
return(ll)
return(ll)
}
}


# function to fit model
# function to fit model
est_poisson <- function(f, data) {
est_nb <- function(f, data) {
# make X and y
# make X and y
mf <- model.frame(f, data = data)
mf <- model.frame(f, data = data)
X <- model.matrix(f, data = mf)
X <- model.matrix(f, data = mf)
y <- model.response(mf)
y <- model.response(mf)
# create starting values
# create starting values
par_start <- rep(0, ncol(X))
par_start <- c(rep(0, ncol(X)), 1) # append theta start (>0)
# run optim()
# run optim()
est <- optim(par_start,
est <- optim(par_start,
fn = poisson_ll,
fn = nb_ll,
y = y,
y = y,
X = X,
X = X,
hessian = TRUE, # for SEs!
hessian = TRUE, # for SEs!
control = list(fnscale = -1),
control = list(fnscale = -1),
method = "BFGS")
method = "BFGS")
# check convergence; print warning if not
# check convergence; print warning if not
if (est$convergence != 0) print("Model did not converge!")
if (est$convergence != 0) print("Model did not converge!")
# create list of objects to return
# create list of objects to return
res <- list(beta_hat = est$par,
k <- ncol(X)
var_hat = solve(-est$hessian))
res <- list(beta_hat = est$par[1:k],
var_hat = solve(-est$hessian)[1:k, 1:k],
theta_hat = est$par[k + 1],
var_theta_hat = solve(-est$hessian)[k + 1, k + 1])
# return the list
# return the list
return(res)
return(res)
}
}


# fit model
# fit model
fit <- est_poisson(f, data = holland)
fit <- est_nb(f, data = holland)
print(fit, digits = 2) # print estimates w/ reasonable digits
print(fit, digits = 2) # print estimates w/ reasonable digits


# ---- compute the expected value given X_c ----
# ---- compute the expected value given X_c ----


# create chosen values for X
# create chosen values for X
# note 1: naming columns helps a bit later
# note 1: naming columns helps a bit later
# note 2: can also do with f, model.matrix(..., newdata = ...)
# note 2: can also do with f, model.matrix(..., newdata = ...)
X_c <- cbind(
X_c <- cbind(
"constant" = 1, # intercept
"constant" = 1, # intercept
"lower" = median(holland$lower),
"lower" = median(holland$lower),
"vendors" = median(holland$vendors),
"vendors" = median(holland$vendors),
"budget" = median(holland$budget),
"budget" = median(holland$budget),
"population" = median(holland$population)
"population" = median(holland$population)
)
)


# function to compute qi
# function to compute qi
ev_fn <- function(beta, X) {
ev_fn <- function(beta, X) {
exp(X%*%beta)
exp(X%*%beta)
}
}


# invariance property
# invariance property
ev_hat <- ev_fn(fit$beta_hat, X_c)
ev_hat <- ev_fn(fit$beta_hat, X_c)


# delta method
# delta method
library(numDeriv) # for grad()
library(numDeriv) # for grad()
grad_ev <- grad(
grad_ev <- grad(
func = ev_fn, # what function are we taking the derivative of?
func = ev_fn, # what function are we taking the derivative of?
x = fit$beta_hat, # what variable(s) are we taking the derivative w.r.t.?
x = fit$beta_hat, # what variable(s) are we taking the derivative w.r.t.?
X = X_c) # what other values are needed?
X = X_c) # what other values are needed?
se_ev_hat <- sqrt(grad_ev %*% fit$var_hat %*% grad_ev)
se_ev_hat <- sqrt(grad_ev %*% fit$var_hat %*% grad_ev)


# ---- compute the ev given X_c (w/ range of values) ----
# ---- compute the ev given X_c (w/ range of values) ----


# create chosen values for X
# create chosen values for X
X_c <- cbind(
X_c <- cbind(
"constant" = 1, # intercept
"constant" = 1, # intercept
"lower" = seq(min(holland$lower), max(holland$lower), by = 1),
"lower" = seq(min(holland$lower), max(holland$lower), by = 1),
"vendors" = median(holland$vendors),
"vendors" = median(holland$vendors),
"budget" = median(holland$budget),
"budget" = median(holland$budget),
"population" = median(holland$population)
"population" = median(holland$population)
)
)


# containers for estimated quantities of interest and ses
# containers for estimated quantities of interest and ses
ev_hat <- numeric(nrow(X_c))
ev_hat <- numeric(nrow(X_c))
se_ev_hat <- numeric(nrow(X_c))
se_ev_hat <- numeric(nrow(X_c))


# loop over each row of X_c and compute qi and se
# loop over each row of X_c and compute qi and se
for (i in 1:nrow(X_c)) { # for the ith row of X...
for (i in 1:nrow(X_c)) { # for the ith row of X...