S7 class for M-estimation via solving estimating equations with empirical sandwich variance estimation.
Usage
MEstimator(
stacked_equations,
init,
subset = NULL,
finite_correction = NULL,
summed_equations = NULL,
check_summed_equations = TRUE
)Arguments
- stacked_equations
A function that takes a numeric vector
thetaand returns a p-by-n matrix of estimating equation contributions, where p is the number of parameters and n is the number of observations. Row names on that matrix name the parameters wheninithas none and every parameter is labeled; seeestimate().- init
Numeric vector of initial parameter values for the root-finding algorithm. Names on it label the parameters and take precedence over the row names of
stacked_equations.- subset
Integer vector of parameter indices to solve for, or
NULL(default) to solve for all parameters. Indices are 1-based; parameters not listed are held fixed at theirinitvalues while the rest are solved. The equations outside the subset are set aside along with the parameters they estimate, so the subset parameters are the root of the subset equations alone and the rest of the stack has no say in where they land: give a three-equation linear regression stacksubset = 1Land the intercept comes back as the mean of the response less what the slopes held at theirinitvalues account for, because the first equation on its own is the estimating equation for a mean. Held at zero, which is what an unsetinitusually means, they account for nothing and the intercept is the mean of the response itself.GMMEstimator()andgmm_estimate()read the argument differently, since the GMM objective sums every equation whether the subset lists it or not, so the same stack and the samesubsetgive the two different values. The variance estimator ignoressubset.- finite_correction
Character string for finite-sample correction (e.g.,
"HC1"), orNULL(default) for no correction.- summed_equations
A function that takes a numeric vector
thetaand returns the length-p vector of row sums ofstacked_equationsattheta, orNULL(default) to derive those sums from the full p-by-n return.A fit reduces the estimating functions to those sums everywhere but the meat. The solver is given the summed equations to find a root of, and the bread is their Jacobian, so a fit builds the whole p-by-n matrix once per solver evaluation and once or twice more per parameter, all of it for arithmetic that is linear in it. An estimating function whose sums have a closed form, such as the \(X^T r\) of a regression score, can supply them here and give both steps only what they use. The meat is unaffected either way: it needs the per-observation contributions and takes the one full evaluation it always took, as does the validation at the starting values.
Under
deriv_method = "exact"the reduction is called with a tangent-carryingtheta, so it must be written in operations that carry derivatives:t(X) %*% rdoes, andbase::crossprod()does not. Seeauto_differentiation()for which operations carry a tangent and where.Anything that is neither
NULLnor a function is refused here, with an error carrying the classdeli_summed_equations_error. So is a return at the estimated values that is not numeric or does not hold one value per estimating equation, whichestimate()reads.m_estimate()andgmm_estimate()do not offer it. Both buildstacked_equationsthemselves from a formula and the equation named in.ee, so the estimating functions a reduction would have to match are ones the caller never writes; this is for a system assembled by hand.- check_summed_equations
Logical. When
TRUE(default) andsummed_equationswas supplied, its value at the estimated values is compared against the row sums of the one full evaluation the meat is built from, and a disagreement raises an error carrying the classdeli_summed_equations_disagree. The comparison costs one call tosummed_equationsand one reduction of a matrix the fit already holds.What it is for is a reduction that sums some other system. The solver drives whatever it is given to zero, so such a reduction sends the fit to that other system's root and leaves the bread the Jacobian of one system and the meat the cross-product of another. Set it to
FALSEto skip the comparison, which leaves a fit that reports estimates nobody solved for and a covariance with the shape of one and no claim to be one.A reduction that is a multiple of the right one is not what the comparison sees. It vanishes where the right one does, so the fit lands at the same estimates and both quantities are at rounding where they are compared; the bread comes back as that multiple of the right bread. See
compute_sandwich(), whose argument of the same name reads the same comparison at a point the caller supplies.
Value
An MEstimator S7 object. Call estimate() to solve the
estimating equations and compute the sandwich variance.
Examples
# Estimating equations for the mean
y <- c(1, 2, 3, 4, 5)
psi <- function(theta) {
matrix(y - theta[1], nrow = 1)
}
m <- MEstimator(stacked_equations = psi, init = 0) |>
estimate()
coef(m)
#> theta_1
#> 3
summary(m)
#> ── MEstimator Results ──────────────────────────────────────────────────────────
#> Observations: 5
#> Parameters: 1
#>
#> Estimate Std.Err Z-score 95% LCL 95% UCL P-value S-value
#> theta_1 3.0000 0.6325 4.7434 1.7604 4.2396 2.1e-06 18.8602
# The solver and the bread only ever need the sums of the estimating
# equations, so an equation whose sums have a closed form can supply them
# and leave the whole matrix to the meat
summed <- function(theta) sum(y) - length(y) * theta[1]
MEstimator(stacked_equations = psi, init = 0, summed_equations = summed) |>
estimate() |>
summary()
#> ── MEstimator Results ──────────────────────────────────────────────────────────
#> Observations: 5
#> Parameters: 1
#>
#> Estimate Std.Err Z-score 95% LCL 95% UCL P-value S-value
#> theta_1 3.0000 0.6325 4.7434 1.7604 4.2396 2.1e-06 18.8602