fml maximises a log-likelihood you write yourself, which is what TDA
offers that a fixed catalogue of models cannot. The likelihood is written
in an expression language, evaluated inside TDA rather than as an R
function – but as of this version, that expression can be written in
ordinary R syntax and translated automatically, rather than TDA's.
Arguments
- definitions
either an unevaluated
{ }block of R assignments (see the section on writing the likelihood) or a character vector of TDA's assignments, the last definingfn, the contribution of one case to the log-likelihood. Names that appear on the right but are neither variables indatanor defined earlier are the parameters to be estimated.- data
a data frame; its columns are the variables the definitions can refer to.
- start
optional named vector of starting values, e.g.
c(b0 = 0, b1 = 1).- control
convergence settings from
tda_control.- constraints
optional linear constraints on the parameters –
fml'scon=, the same machinerytda_qreg'sconstraintsuses. Refers to parameters by their position,b1/b2/..., 1-based, in the order they are first introduced acrossdefinitions– never by whatever name was actually given them. A parameter namedb0indefinitionsis stillb1here if it is the first one introduced; TDA's error for a literal"b0 = ..."constraint is “Error in parameter index”, sinceb0is not a valid 1-based position. Run once withoutconstraintsand checktda_estimates()'sIdxcolumn for which position is which parameter before writing one. Must be strictly fewer constraints than parameters (TDA's rule; its error reads “number of constraints should be less than number of parameters”).- residuals
ask TDA to also compute, per case, its contribution to the log-likelihood at the converged parameters –
fml'spres=. Not a classical observed-minus-fitted residual –fmlhas no built-in notion of a fitted value to subtract from, unliketda_lsreg'sresiduals. Forfn = -0.5 * (y - xb)^2, say, this is that expression's value per case, noty - xbitself.- residual_vars
with
residuals = TRUE, extra columns fromdatato write alongsidefn's value, one column per case, in the order given –fml'sv=.$residualsthen comes back as a data frame (fnplus each named column) instead of a plain vector. Has no effect withoutresiduals = TRUE.- protocol
ask TDA to also write its iteration-by-iteration diagnostic log –
fml'sprot=: the iteration table (function value, gradient norm, parameter change per step), the parameter vector, and the covariance matrix at convergence. Not one consistent shape across every algorithm and situation, so returned as$protocol, the file's text lines, rather than force-parsed into a table that would not fit every case.- options
a named list of further TDA options, passed through.
- dir
working directory.
- ...
passed to
tda_run.
Value
An object of class tda_fit. With residuals =
TRUE, also carries $residuals (see residuals above).
Writing the likelihood in R syntax
Give definitions as an unevaluated { } block of plain R
assignments instead of a character vector, and it is translated to TDA's
own expression syntax for you – never actually run as R code (DES,
rate and the rest only ever exist inside TDA, so it cannot be).
ifelse(cond, yes, no) becomes TDA's if() (TDA's
if takes a 2- or 3-argument
if(cond, then)/if(cond, then, else) shape matching
ifelse exactly, not R's control-flow if), and
R's comparison operators (<, >, <=, >=,
==, !=) become TDA's comparison functions (lt,
gt, le, ge, eq, ne). Arithmetic
(+ - * / ^), &/|, and ordinary function calls
(exp, log, negbin, ...) already mean the same thing
in both and pass through unchanged.
These six TDA functions are not the strict comparisons their R
equivalents are. Every one of them – lt, le, gt,
ge, eq, ne alike – carries a fixed tolerance,
EPSI2 = 1000 * DBL_EPSILON (about 2.22e-13): le,
say, computes x <= y + EPSI2, not x <= y. This can
matter on real data: a case in examples/exam/rrdat.1
has PRESN/PRES - 1 equal to 0.2 exactly in exact arithmetic,
and the two land on different sides of 0.2 once represented as
IEEE 754 doubles – ge(x, 0.2) inside TDA still calls it true, R's
own x >= 0.2 on the identical computation does not. Applied
consistently across all six, at least, but nowhere in TDA's
documentation: not in the manual, not in tda_help()'s
operator table, which describes le as plainly as “true if
less than, or equal” with no footnote at all. A hand-written R
replication of a TDA calculation involving a comparison near a round
number (==, or a boundary like 0.2 here) can therefore
disagree with TDA's output at that boundary, for a
reason with nothing to do with which language computed it – this is a
property of TDA's expression evaluator, present whether the
comparison was written by hand in TDA's syntax or reached it through
this translation.
tda_fml({
rate = exp(a0 + COHO2 * a1 + COHO3 * a2 + W * a3)
l1 = ifelse(DES, log(rate), 0)
fn = l1 - rate * DUR
}, data = d, start = c(-4, 0, 0, 0))The older, direct form – a character vector of TDA's assignment
syntax – still works exactly as before, for anything the translator
does not (yet) cover, or for pasting a .cf file's text in
directly.
estimates b0 and b1 by least squares written as a likelihood.
TDA's functions are available, so fn = negbin(alpha, gamma, y)
and the rest work.
See also
Other sequence analysis:
tda_evalfi(),
tda_frml(),
tda_seq_info(),
tda_seqgc(),
tda_seqm(),
tda_seqmd(),
tda_seqpe(),
tda_seqpm()
Examples
set.seed(1)
d <- data.frame(x = 1:20, y = 2 + 0.5 * (1:20) + rnorm(20))
tda_fml(c("xb = b0 + x * b1", "fn = -0.5 * (y - xb)^2"), d)
#> Call: tda_fml(definitions = c("xb = b0 + x * b1", "fn = -0.5 * (y - xb)^2"),
#> data = d)
#>
#> Cases: 20
#> logLik (starting values): -651.8385
#> logLik: -7.768427
#> Converged in 2 iterations
#>
#> Idx Parameter Coeff Error C/Error Signif
#> 1 b0 1.9639 0.4645 4.2277 1.0000
#> 2 b1 0.5216 0.0388 13.4504 1.0000
# the same model, written in R syntax instead
tda_fml({
xb = b0 + x * b1
fn = -0.5 * (y - xb)^2
}, d)
#> Call: tda_fml(definitions = {
#> xb = b0 + x * b1
#> fn = -0.5 * (y - xb)^2
#> }, data = d)
#>
#> Cases: 20
#> logLik (starting values): -651.8385
#> logLik: -7.768427
#> Converged in 2 iterations
#>
#> Idx Parameter Coeff Error C/Error Signif
#> 1 b0 1.9639 0.4645 4.2277 1.0000
#> 2 b1 0.5216 0.0388 13.4504 1.0000
# a compound Poisson (negative binomial) count regression -- TDA has no
# separate command for this (unlike its plain Poisson, which is a glm()
# family), but negbin(alpha, gamma, k) is a built-in log-likelihood
# function in its expression language, reachable through fml like any
# other: gamma is the mean, alpha = 1/sigma the dispersion
set.seed(7)
d2 <- data.frame(x = rnorm(200))
d2$ndi <- rnbinom(200, mu = exp(0.5 + 0.8 * d2$x), size = 2)
coef(tda_fml({
xb = b0 + x * b1
gamma = exp(xb)
sigma = exp(sig)
alpha = 1 / sigma
fn = negbin(alpha, gamma, ndi)
}, d2, start = list(b0 = 0, b1 = 0, sig = 0)))
#> b0 b1 sig
#> 0.4208311 0.8130428 -0.4504466