DR = function (data,
Z.states,
vcovfun = c ("vcovHAC" , "NeweyWest" )) {
vcovfun = match.arg (vcovfun)
T = data$ T
T0 = data$ T0
t = data$ t
nW = ncol (data$ W)
nZ = ncol (data$ Z[, Z.states, drop = FALSE ])
# confounding bridge functions
evalh = \(theta, data) as.numeric (cbind (1 , data$ W) %*% theta[1 : (nW + 1 )])
evalq = \(theta, data) {
as.numeric (
exp (
cbind (1 , data$ Z[, Z.states, drop = FALSE ]) %*% theta[(nW + 2 ): (nW + nZ + 2 )]
)
)
}
gh = cbind (1 , data$ Z)
ngh = ncol (gh)
gq = cbind (1 , data$ W)
ngq = ncol (gq)
######################################################################
# moment function
g = function (theta, data) {
h = evalh (theta, data)
q = evalq (theta, data)
ϕ = theta[nW + nZ + ngq + 3 ]
# centering parameters
ψ = matrix (theta[(nW + nZ + 3 ): (nW + nZ + ngq + 2 )], nrow = T, ncol = ngq, byrow = TRUE )
ψm = theta[nW + nZ + ngq + 4 ]
# h regresses y on W
g1 = (t <= T0) * (data$ Y - h) * gh
g2 = (t > T0) * (ψ - gq)
g3 = (t <= T0) * (q * gq - ψ)
g4 = (t > T0) * (ϕ - (data$ Y - h) + ψm)
g5 = (t <= T0) * (ψm - q * (data$ Y - h))
cbind (g1, g2, g3, g4, g5)
}
# gradient - try autodiff?
gradv = function (theta, data) {
h = evalh (theta, data)
q = evalq (theta, data)
out = matrix (0 , ngh + 2 * ngq + 2 , nW + nZ + ngq + 4 )
# g1
out[1 : ngh, 1 : (nW + 1 )] = - t (gh) %*% (cbind (1 , data$ W) * (t <= T0)) / T
# g2
out[(ngh + 1 ): (ngh + ngq), (nW + nZ + 3 ): (nW + nZ + ngq + 2 )] = diag ((T - T0) / T, ngq)
# g3
out[(ngh + ngq + 1 ): (ngh + 2 * ngq), (nW + nZ + 3 ): (nW + nZ + ngq + 2 )] = diag (- T0 / T, ngq)
M1 = t (gq)
M2 = q * (t <= T0) * cbind (1 , data$ Z[, Z.states, drop = FALSE ]) / T
out[(ngh + ngq + 1 ): (ngh + 2 * ngq), (nW + 2 ): (nW + nZ + 2 )] = M1 %*% M2
# g4
out[ngh + 2 * ngq + 1 , nW + nZ + ngq + 3 ] = out[ngh + 2 * ngq + 1 , nW + nZ + ngq + 4 ] = (T - T0) / T
out[ngh + 2 * ngq + 1 , 1 : (nW + 1 )] = colMeans (cbind (1 , data$ W) * (t > T0))
# g5
out[ngh + 2 * ngq + 2 , nW + nZ + ngq + 4 ] = T0 / T
out[ngh + 2 * ngq + 2 , 1 : (nW + 1 )] = colMeans (q * cbind (1 , data$ W) * (t <= T0))
out[ngh + 2 * ngq + 2 , (nW + 2 ): (nW + nZ + 2 )] = colMeans (- q * (data$ Y - h) * cbind (1 , data$ Z[, Z.states, drop = FALSE ]) * (t <= T0))
out
}
######################################################################
# warm start
init.model.h = lm (data$ Y ~ ., data = as.data.frame (data$ W), subset = t <= T0)
init.alpha = coef (init.model.h)
init.model.q = glm (I (t > T0) ~ .,
data = as.data.frame (data$ Z[, Z.states, drop = FALSE ]), family = binomial ())
init.beta = coef (init.model.q)
init.beta[1 ] = init.beta[1 ] + log ((T - T0) / T0)
init.psi = colMeans (gq[t > T0, , drop = FALSE ])
init.psi.minus = mean (exp (cbind (1 , data$ Z[t <= T0, Z.states, drop = FALSE ]) %*% init.beta) *
(data$ Y[t <= T0] - predict (init.model.h, newdata = as.data.frame (data$ W[t <= T0, , drop = FALSE ]))))
init.phi = mean (data$ Y[t > T0] -
predict (init.model.h, newdata = as.data.frame (data$ W[t > T0, , drop = FALSE ]))) - init.psi.minus
theta0 = c (init.alpha, init.beta, init.psi, init.phi, init.psi.minus)
names (theta0) = c (paste0 ("alpha" , 0 : nW),
paste0 ("beta" , 0 : nZ),
paste0 ("psi" , 1 : ngq),
"phi" , "psi-" )
######################################################################
# gmm
model = gmm (
g = g,
x = data,
t0 = theta0,
gradv = gradv,
wmatrix = "ident" ,
control = list (maxit = 1e5 ), method = "BFGS" , vcov = "iid" )
cat ("Parameter estimate: \n " )
print (coef (model))
cat ("Summary of estimated q(Zt): \n " )
print (summary (evalq (coef (model), data)[t <= T0]))
phi.hat = coef (model)["phi" ]
# vcov HAC
var = if (vcovfun == "vcovHAC" ) {
sandwich:: vcovHAC (model)
} else {
sandwich:: NeweyWest (model, prewhite = FALSE )
}
rownames (var) = colnames (var) = names (theta0)
SE = sqrt (var["phi" , "phi" ])
CI = phi.hat + qnorm (c (.025 , .975 )) * SE
SC = evalh (coef (model), data)
list (phi.hat = phi.hat, SE = SE, CI = CI, convergence = model$ algoInfo$ convergence, SC = SC)
}