geex
This vignette implements examples from and is meant to read with
Stefanski and Boos (2002) (SB). Examples
4-9 use the geexex
data set. For information on how the
data are generated, run help('geexex')
.
library(geex)
Example 4 calculates an instumental variable estimator. The variables (Y3,W1,Z1) are observed according to:
Y3i=α+βX1i+σϵϵ1,i
W1i=βX1i+σUϵ2,i
and
Z1i=γ+δX1i+στϵ3,i.
Y3 is a linear function of a latent variable X1, whose coefficient β is of interest. W1 is a measurement of the unobserved X1, and Z1 is an instrumental variable for X1. The instrumental variable estimator is ˆβIV is the ratio of least squares regression slopes of Y3 on Z1 and Y3 and W1. The ψ function below includes this estimator as ˆθ4=ˆβIV. In the example data, 100 observations are generated where X1∼Γ(shape=5,rate=1), α=2, β=3, γ=2, δ=1.5, σϵ=στ=1, σU=.25, and ϵ⋅,i∼N(0,1).
ψ(Y3i,Z1i,W1i,θ)=(θ1−Z1iθ2−W1i(Y3i−θ3W1i)(θ2−W1i)(Y3i−θ4W1i)(θ1−Z1i))
<- function(data){
SB4_estFUN <- data$Z1; W1 <- data$W1; Y3 <- data$Y3
Z1 function(theta){
c(theta[1] - Z1,
2] - W1,
theta[- (theta[3] * W1)) * (theta[2] - W1),
(Y3 - (theta[4] * W1)) * (theta[1] - Z1)
(Y3
)
} }
<- m_estimate(
estimates estFUN = SB4_estFUN,
data = geexex,
root_control = setup_root_control(start = c(1, 1, 1, 1)))
The R packages AER
and
ivpack
can compute the IV estimator and sandwich variance estimators
respectively, which is done below for comparison.
<- AER::ivreg(Y3 ~ W1 | Z1, data = geexex)
ivfit <- ivpack::cluster.robust.se(ivfit, clusterid = 1:nrow(geexex)) iv_se
coef(ivfit)[2]
coef(estimates)[4]
2, 'Std. Error']
iv_se[sqrt(vcov(estimates)[4, 4])
This example shows the link between the influence curves and the Hodges-Lehman estimator.
ψ(Y2i,θ)=(ICˆθHL(Y2;θ0)−(θ1−θ0))
The functions used in SB5_estFUN
are defined below:
<- function(y, theta0, distrFUN = pnorm){
F0 distrFUN(y - theta0, mean = 0)
}
<- function(y, densFUN){
f0 densFUN(y, mean = 0)
}
<- function(y, densFUN = dnorm){
integrand f0(y, densFUN = densFUN)^2
}
<- integrate(integrand, lower = -Inf, upper = Inf)$value IC_denom
<- function(data){
SB5_estFUN <- data[['Y2']]
Yi function(theta){
1/IC_denom) * (F0(Yi, theta[1]) - 0.5)
(
} }
<- m_estimate(
estimates estFUN = SB5_estFUN,
data = geexex,
root_control = setup_root_control(start = 2))
The hc.loc
of the ICSNP
package computes the Hodges-Lehman estimator and SB gave closed form
estimators for the variance.
<- ICSNP::hl.loc(geexex$Y2)
theta_cls <- 1/(12 * IC_denom^2) / nrow(geexex) Sigma_cls
## $geex
## $geex$parameters
## [1] 2.026376
##
## $geex$vcov
## [,1]
## [1,] 0.01040586
##
##
## $cls
## $cls$parameters
## [1] 2.024129
##
## $cls$vcov
## [1] 0.01047198
This example illustrates estimation with nonsmooth ψ function for computing the Huber (1964) estimator of the center of symmetric distributions.
ψk(Y1i,θ)={(Y1i−θ)when |(Y1i−θ)|≤kk∗sgn(Y1i−θ)when |(Y1i−θ)|>k
<- function(data, k = 1.5){
SB6_estFUN <- data$Y1
Y1 function(theta){
<- Y1 - theta[1]
x if(abs(x) <= k) x else sign(x) * k
} }
<- m_estimate(
estimates estFUN = SB6_estFUN,
data = geexex,
root_control = setup_root_control(start = 3))
The point estimate from geex
is compared to the estimate
obtained from the huber
function in the MASS
package. The variance estimate is compared to an estimator suggested by
SB: Am=∑i[−ψ′(Yi−ˆθ)]/m and Bm=∑iψ2k(Yi−ˆθ)/m, where ψ′k is the derivative of ψ where is exists.
<- MASS::huber(geexex$Y1, k = 1.5, tol = 1e-10)$mu
theta_cls
<- function(x, k = 1.5){
psi_k if(abs(x) <= k) x else sign(x) * k
}
<- mean(unlist(lapply(geexex$Y1, function(y){
A <- y - theta_cls
x -numDeriv::grad(psi_k, x = x)
})))
<- mean(unlist(lapply(geexex$Y1, function(y){
B <- y - theta_cls
x psi_k(x = x)^2
})))
## closed form covariance
<- matrix(1/A * B * 1/A / nrow(geexex)) Sigma_cls
<- list(geex = list(parameters = coef(estimates), vcov = vcov(estimates)),
results cls = list(parameters = theta_cls, vcov = Sigma_cls))
results
## $geex
## $geex$parameters
## [1] 4.82061
##
## $geex$vcov
## [,1]
## [1,] 0.08356179
##
##
## $cls
## $cls$parameters
## [1] 4.999386
##
## $cls$vcov
## [,1]
## [1,] 0.0928935
Approximation of ψ with geex is EXPERIMENTAL.
Example 7 illustrates calculation of sample quantiles using M-estimation and approximation of the ψ function.
ψ(Y1i,θ)=(0.5−I(Y1i≤θ1))
<- function(data){
SB7_estFUN <- data$Y1
Y1 function(theta){
0.5 - (Y1 <= theta[1])
} }
Note that ψ is not
differentiable; however, geex
includes the ability to
approximate the ψ function via
an approx_control
object. The FUN
in an
approx_control
must be a function that takes in the ψ function, modifies it, and returns a
function of theta
. For this example, I approximate ψ with a spline function. The
eval_theta
argument is used to modify the basis of the
spline.
<- function(psi, eval_theta){
spline_approx <- Vectorize(psi)(eval_theta)
y <- splinefun(x = eval_theta, y = y)
f function(theta) f(theta)
}
<- m_estimate(
estimates estFUN = SB7_estFUN,
data = geexex,
root_control = setup_root_control(start = 4.7),
approx_control = setup_approx_control(FUN = spline_approx,
eval_theta = seq(3, 6, by = .05)))
A comparison of the variance is not obvious, so no comparison is made.
## $geex
## $geex$parameters
## [1] 4.7
##
## $geex$vcov
## [,1]
## [1,] 0.1773569
##
##
## $cls
## $cls$parameters
## [1] 4.708489
##
## $cls$vcov
## [1] NA
Example 8 demonstrates robust regression for estimating β from 100 observations generated from Y4=0.1+0.1X1i+0.5X2i+ϵi, where ϵi∼N(0,1), X1 is defined as above, and the first half of the observation have X2i=1 and the others have X2i=0.
ψk(Y4i,θ)=(ψk(Y4i−xTiβ)xi)
<- function(x, k = 1.345){
psi_k if(abs(x) <= k) x else sign(x) * k
}
<- function(data){
SB8_estFUN <- data$Y4
Yi <- model.matrix(Y4 ~ X1 + X2, data = data)
xi function(theta){
<- Yi - xi %*% theta
r c(psi_k(r) %*% xi)
} }
<- m_estimate(
estimates estFUN = SB8_estFUN,
data = geexex,
root_control = setup_root_control(start = c(0, 0, 0)))
<- MASS::rlm(Y4 ~ X1 + X2, data = geexex, method = 'M')
m <- coef(m)
theta_cls <- vcov(m) Sigma_cls
<- list(geex = list(parameters = coef(estimates), vcov = vcov(estimates)),
results cls = list(parameters = theta_cls, vcov = Sigma_cls))
results
## $geex
## $geex$parameters
## [1] -0.04050369 0.14530196 0.30181589
##
## $geex$vcov
## [,1] [,2] [,3]
## [1,] 0.05871932 -0.0101399730 -0.0133230841
## [2,] -0.01013997 0.0021854268 0.0003386202
## [3,] -0.01332308 0.0003386202 0.0447117633
##
##
## $cls
## $cls$parameters
## (Intercept) X1 X2
## -0.0377206 0.1441181 0.2988842
##
## $cls$vcov
## (Intercept) X1 X2
## (Intercept) 0.07309914 -0.0103060747 -0.0241724792
## X1 -0.01030607 0.0020579145 0.0005364106
## X2 -0.02417248 0.0005364106 0.0431120686
Example 9 illustrates estimation of a generalized linear model.
ψ(Yi,θ)=(Di(β)Yi−μi(β)Vi(β)τ)
<- function(data){
SB9_estFUN <- data$Y5
Y <- model.matrix(Y5 ~ X1 + X2, data = data, drop = FALSE)
X function(theta){
<- X %*% theta
lp <- plogis(lp)
mu <- t(X) %*% dlogis(lp)
D <- mu * (1 - mu)
V %*% solve(V) %*% (Y - mu)
D
} }
<- m_estimate(
estimates estFUN = SB9_estFUN,
data = geexex,
root_control = setup_root_control(start = c(.1, .1, .5)))
Compare point estimates to glm
coefficients and
covariance matrix to sandwich
.
<- glm(Y5 ~ X1 + X2, data = geexex, family = binomial(link = 'logit'))
m9 <- coef(m9)
theta_cls <- sandwich::sandwich(m9) Sigma_cls
<- list(geex = list(parameters = coef(estimates), vcov = vcov(estimates)),
results cls = list(parameters = theta_cls, vcov = Sigma_cls))
results
## $geex
## $geex$parameters
## [1] -1.1256071 0.3410619 -0.1148368
##
## $geex$vcov
## [,1] [,2] [,3]
## [1,] 0.35202094 -0.058906883 -0.101528787
## [2,] -0.05890688 0.012842435 0.004357355
## [3,] -0.10152879 0.004357355 0.185455144
##
##
## $cls
## $cls$parameters
## (Intercept) X1 X2
## -1.1256070 0.3410619 -0.1148368
##
## $cls$vcov
## (Intercept) X1 X2
## (Intercept) 0.35201039 -0.058903546 -0.101534539
## X1 -0.05890355 0.012841392 0.004358926
## X2 -0.10153454 0.004358926 0.185456314
Example 10 illustrates testing equality of success probablities.
ψ(Yi,ni,θ)=((Yi−niθ2)2niθ2(1−θ2)−θ1Yi−niθ2)
<- function(data){
SB10_estFUN <- data$ft_made
Y <- data$ft_attp
n function(theta){
<- theta[2]
p c(((Y - (n * p))^2)/(n * p * (1 - p)) - theta[1],
- n * p)
Y
} }
<- m_estimate(
estimates estFUN = SB10_estFUN,
data = shaq,
units = 'game',
root_control = setup_root_control(start = c(.5, .5)))
<- function(p) {
V11 <- nrow(shaq)
k <- sum(shaq$ft_attp)
sumn <- sum(1/shaq$ft_attp)
sumn_inv <- 1 - (6 * p) + (6 * p^2)
term2_n <- p * (1 - p)
term2_d <- term2_n/term2_d
term2 <- ((1 - (2 * p))^2) / ((sumn/k) * p * (1 - p))
term3 2 + (term2 * (1/k) * sumn_inv) - term3
}
<- sum(shaq$ft_made)/sum(shaq$ft_attp)
p_tilde <- V11(p_tilde)/23
V11_hat
# Compare variance estimates
V11_hat
## [1] 0.0783097
vcov(estimates)[1, 1]
## [1] 0.1929791
# Note the differences in the p-values
pnorm(35.51/23, mean = 1, sd = sqrt(V11_hat), lower.tail = FALSE)
## [1] 0.02596785
pnorm(coef(estimates)[1],
mean = 1,
sd = sqrt(vcov(estimates)[1, 1]),
lower.tail = FALSE)
## [1] 0.1078138
This example shows that the empircal sandwich variance estimator may be different from other sandwich variance estimators that make assumptions about the structure of the A and B matrices.