Estimates parameters by the generalized method of moments against moment conditions you write.
This is the constructor the upstream C# library itself exposes,
GeneralizedMethodOfMoments(momentConditionFunction, ...): fit_gmm() can only fit a
model_bulletin17c() model (the single implementation of the IGMMModel interface it takes),
while this function takes any moment conditions you can write down.
Usage
fit_gmm_moments(
moment_conditions,
initial,
lower = NULL,
upper = NULL,
sample_size,
jacobian = NULL,
penalty = NULL,
optimizer = "BFGS",
strategy = "Iterative",
max_gmm_iterations = 0L
)Arguments
- moment_conditions
the required function described above.
- initial
numeric vector of starting values, one per parameter. Its length IS the parameter count.
- lower, upper
numeric vectors of parameter bounds, the same length as
initial, with every starting value inside them. Both are required: every optimizer this dispatches to takes a box, and the numerical Jacobian's step selection is bounds-aware.- sample_size
the number of observations behind the moment conditions. Required, and only you know it: your function hands over averages, not data. The sandwich covariance divides by it, so the standard errors scale as
1 / sqrt(sample_size).- jacobian
an optional analytic Jacobian of the moment conditions, called as
jacobian(parameters)and returning a q by p numeric matrix – one ROW per moment condition, one COLUMN per parameter.NULL, the default, uses the ported bounds-aware finite-difference Jacobian, which costs two extramoment_conditionscalls per parameter per gradient.- penalty
an optional penalty added to the GMM objective, called as
penalty(parameters)and returning one number. Ridge-type regularization, and the only way to fit a model with more parameters than moment conditions (which is otherwise refused as under-identified). Return0for no penalty. Note the ported half-quadratic convention: with a penalty the objective is0.5 * g'Wg + penalty, so a penalty should carry its own1/2.- optimizer
one of
"BFGS"(default, matchingGeneralizedMethodOfMoments's own class default),"NelderMead","Brent","Powell","DifferentialEvolution","MultilevelSingleLinkage".- strategy
GMM estimation strategy:
"Iterative"(default),"OneStep", or"TwoStep"."OneStep"is refused for an over-identified problem, matching the estimator.- max_gmm_iterations
maximum number of GMM iterations;
0(default) keeps the estimator's own default cap.
Value
An object of class corehydro_fit with method == "GMM" – the same object fit_gmm()
returns, so coef(), vcov(), print() and summary() behave identically. Parameters are
named p1, p2, ... since your moment conditions name nothing. Method of moments computes no
likelihood surface, so $log_likelihood, $aic and $bic are NA and confint() errors, as
they do for fit_gmm(). $j_stat is Hansen's J and $j_stat_pval its p-value, which is NA
whenever the fit is just-identified (as many moment conditions as parameters): zero degrees of
freedom leaves no over-identifying restriction to test, and print() says so rather than
showing a figure. $j_stat itself is not a goodness-of-fit number you can read there either.
The residual covariance it is scaled by is singular – it has rank q - p, so it is exactly
zero when the fit is just-identified – and inverting it amplifies the optimizer's convergence
tolerance rather than any property of your data. The result varies by many orders of magnitude
and in sign between optimizers, and between this package and the C# library it ports, on fits
whose parameters agree to ten significant figures. Sometimes it cannot be computed at all, and
then it comes back NA rather than failing the fit. Over-identifying the model restores the
p-value but not $j_stat, since the rank deficiency only shrinks from q to q - p.
$degree_of_freedom and $number_of_moment_conditions carry q - p and q.
fit_diagnostics() and quantile_variance() are not available for this fit – both need the
model a fit_gmm() fit carries.
The moment condition function
moment_conditions(parameters) is called with one numeric vector, as long as initial, and must
return a list with two elements:
gthe sample mean of the moment conditions at those parameters: a numeric vector of length q, one entry per moment condition. GMM drives this towards zero.
stheir covariance: a q by q numeric matrix. In two-step and iterative GMM the optimal weighting matrix is its inverse.
Both are required and both are checked by name, because returning the wrong thing here is the likeliest mistake on this surface. A two-parameter method-of-moments fit of a Normal, whose answer is the sample mean and the population variance:
avg <- function(v) { # not mean(): see "Reproducing a run in Python" below
total <- 0
for (value in v) total <- total + value
total / length(v)
}
moments <- function(p) {
a <- x - p[1]
b <- a * a - p[2]
list(g = c(avg(a), avg(b)),
s = matrix(c(avg(a * a), avg(a * b), avg(a * b), avg(b * b)), 2, 2))
}q (the number of moment conditions) is measured by calling your function once at initial, so
there is no argument to get wrong. When q equals the number of parameters the fit is
just-identified and $j_stat_pval comes back NA – see the return value below.
Reproducing a run in Python
There is no random number generator anywhere in this fit, so a repeated call returns the
identical numbers. Across languages the guarantee is the usual one for this surface: the
optimizer arithmetic all happens in the shared C++ core, but g and s are computed by your
own R code, and R and Python do not guarantee identical rounding for the same formula.
Arithmetic (+ - * /) is IEEE-deterministic and does reproduce; log, exp and friends come
from each platform's math library. R's sum() and mean() accumulate in extended precision
where Python's do not, so an explicit loop is the portable spelling.
See also
fit_gmm() for the Bulletin 17C flood-frequency fit, optim_minimize() for a plain
bounded optimization of your own objective, and fit_mle() for likelihood-based fitting.
Examples
x <- c(4.1, 5.2, 4.8, 5.5, 4.9, 5.1, 5.3, 4.7)
# An explicit loop rather than mean(), so the same formula returns the same bits in Python:
# R's mean() and sum() accumulate in extended precision and Python's do not.
avg <- function(v) {
total <- 0
for (value in v) total <- total + value
total / length(v)
}
moments <- function(p) {
a <- x - p[1]
b <- a * a - p[2]
list(
g = c(avg(a), avg(b)),
s = matrix(c(avg(a * a), avg(a * b), avg(a * b), avg(b * b)), 2, 2)
)
}
f <- fit_gmm_moments(moments,
initial = c(5, 0.5), lower = c(0, 0.001), upper = c(10, 10),
sample_size = length(x)
)
round(coef(f), 6) # the sample mean and the population variance
#> p1 p2
#> 4.950 0.165
f$j_stat_pval # NA: just-identified, so there is nothing to test
#> [1] NA