Skip to content

Releases: tidyfun/tf

tf 0.5.0

Choose a tag to compare

@fabian-s fabian-s released this 15 Jul 15:36
4180eb8

Internal

  • tf_rgp() no longer depends on mvtnorm or pracma. GP draws are now
    generated by a direct eigen-based sampler (the symmetric square root
    V D^{1/2} V^T of the covariance) that reproduces the previous
    mvtnorm::rmvnorm(method = "eigen") draws bit-for-bit under set.seed() and
    handles rank-deficient kernels (e.g. squared-exp with zero nugget) correctly.
    tf_smooth.tfd(method = "savgol") now inlines a small Savitzky–Golay filter
    in place of the pracma::savgol() dependency.

Bug fixes

  • tf_evaluate() no longer returns values at the wrong positions when the
    requested arg contains duplicates (#236).
  • tf_integrate(f, definite = FALSE) for irregular tfd with n > 1 no longer
    crashes; the antiderivative's per-curve grids are kept as a list (#237).
  • Math.tfd() / Math.tfb() now forward ... to the underlying op so
    round(x, digits), log(x, base), signif(x, digits), etc. honor their
    extra arguments instead of silently dropping them (#246).
  • tf_integrate() on irregular tfd no longer silently returns NA under
    default limits; for irregular input the defaults are now each curve's own
    observed arg range (i.e., the range of its tf_arg() values). Pass explicit
    lower / upper (or an extrapolating evaluator) to override (#253).

Vector-valued functional data

This release introduces first-class support for vector-valued (multivariate)
functional data -- functions whose codomain is R^d -- alongside the existing
univariate tfd/tfb classes.

  • tfd_mv() and tfb_mv(): new vctrs-based S3 classes for vector-valued
    functional data, holding several component functions per observation on a
    shared domain. Constructors accept named lists of tfd/tfb vectors or
    list-columns of matrices.
  • tfb_mfpc() implements multivariate functional principal component analysis
    (Happ & Greven, 2018) for tf_mv data: a single set of scalar scores per
    curve shared across all components, with vector-valued eigenfunctions.
    Component weighting is configurable ("inverse_variance" default, "snr",
    "equal", or user-supplied). New data can be projected onto a fitted basis
    via tf_rebase() / vec_cast(). Accessors tf_mfpc_scores(),
    tf_mfpc_efunctions() and the predicate is_tfb_mfpc().
  • Multivariate registration: tf_register() gains method = "srvf_mv" for
    jointly aligning the components of tf_mv curves via the multivariate SRVF
    framework, and tf_register_shape() provides elastic shape registration
    (rotation/translation/scale-invariant) via fdasrvf.
  • New geometry verbs for tf_mv (and where meaningful for univariate tf):
    tf_norm(), tf_inner(), tf_tangent(), tf_arclength().
  • Component accessors (tf_ncomp(), tf_components(), tf_component()),
    tf_split() / tf_combine() extensions and [/[[ methods for extracting,
    replacing and recombining components.
  • Function-wise scalar summaries tf_fmean(), tf_fvar() and tf_fsd()
    return component-wise matrices for tf_mv objects.
  • tf_interpolate(), tf_fwise(), tf_sparsify() and tf_jiggle() now have
    component-wise tf_mv methods; tf_sparsify() and tf_jiggle() keep shared
    component grids by default via same_arg = TRUE.
  • tf_where() / tf_anywhere() work on tf_mv objects with joint
    conditions across components, referenced by name (e.g.
    tf_where(f, x > 0 & y < 1)); there is no value column for tf_mv input.
    Components must share a common grid, or arg must be supplied explicitly.
  • quantile() works on tf_mv objects, returning the component-wise
    pointwise quantiles: a tf_mv with one curve per requested probability in
    probs, exactly as quantile.tf() does per component (na.rm / probs /
    type are forwarded).
  • points() works on tf_mv objects, mirroring lines.tf_mv(): in
    "trajectory" mode (d == 2) it overlays the paired (x(t), y(t)) points
    with per-curve graphical-parameter recycling; in "facet" mode it overlays
    each component onto the current device.
  • tf_depth() gains a tf_mv method: a weighted componentwise aggregation of
    the (centrality) univariate depths, with a weights argument mirroring
    tfb_mfpc() ("equal" default, "inverse_variance", or a numeric vector).
    The up-down ordering index "MHI" has no canonical vector-valued analogue and
    aborts with a pointer to tf_order() (#273).
  • median(), summary() and fivenum() on tf_mv now select observed
    vector-valued curves via a single joint-depth index (one curve across all
    components), fixing the previous component-wise "chimera" where each component
    could come from a different observation. Pointwise entries (mean, min/max, the
    central-half range) remain component-wise (#273).
  • New generic tf_order() with a tf_mv method: tf_order(f, by = "norm")
    (or by = <component name>) orders vector-valued curves by an explicit
    scalar reduction. sort(), rank() and xtfrm() remain permanently
    undefined for tf_mv -- there is no canonical total order on R^d -- so
    base sort()/order()/rank() fail fast rather than fabricate an order
    (#273).

Contract change

  • is_tf() now returns TRUE for tf_mv as well as univariate tfd/tfb.
    Code that branched on is_tf() to mean "univariate tf" should switch to
    the new predicate is_tf_1d().
  • "arg" and "id" are reserved and cannot be used as component names --
    they collide with the grid and curve-id columns of long-format conversions.
  • Constructing a tf_mv from components with differing domains now warns
    when widening tfd components to the union domain (evaluations outside the
    observed range are NA) and aborts for tfb components, where basis
    evaluation outside the fitted range would extrapolate, i.e. fabricate
    values.
  • Component-wise operations on a tfb_mfpc (tf_smooth(), tf_derive(),
    tf_zoom(), tf_integrate(), mean()/sd()/var(), Summary group
    generics) now consistently demote to valid per-component tfb_fpc
    representations with a one-time warning, like arithmetic already did --
    previously they silently produced objects that abort on later use.
  • tf_fmax(), tf_fmin() and tf_fmedian() on tf_mv return an n x d
    curves-x-components matrix like tf_fmean()/tf_fsd() (previously: a
    misnamed interleaved vector).
  • tfb_fpc() and tfb_mfpc() abort informatively when the input contains
    completely missing curves (partially missing evaluations continue to be
    handled by the soft-impute SVD); re-scoring new data with NA curves via
    tf_rebase() / vec_cast() yields NA scores and NA entries.

Tabular export of components on differing grids

  • as.data.frame.tf_mv(unnest = TRUE) gains a grids argument controlling
    where components are evaluated when they live on different argument grids:
    "union" (default, previous behavior) evaluates every component on each
    curve's union grid, interpolating inside the observed range; "component"
    evaluates each component strictly on its own grid (or on arg), so no
    values are fabricated where a component was not observed -- the faithful
    export used by tidyfun::tf_unnest(). For shared grids both agree.

More bug fixes (pre-release review)

  • Empty prototypes (tfd(), tfb(), tfd_mv(list()) and friends) carry the
    sentinel domain c(NA, NA) and now combine cleanly with populated vectors
    in all vctrs paths (vec_c(), vec_rbind(), c(), casts) -- binding
    rows onto an initially empty tf column works again.
  • tfb_mv() on an existing tfb_mv with an explicit basis argument re-fits
    in the requested basis instead of silently returning the old one; changing
    the basis kind converts through tfd().
  • tfb_mv()/tfb_mfpc() on raw lists/arrays route constructor arguments
    (arg, domain) and basis arguments to the right place instead of
    forwarding everything everywhere.
  • tfd_mv() on 3-d arrays keeps length-1 curve/arg margins and curve names.
  • tf_derive() and tf_integrate() on tf_mv accept per-component arg
    lists, consistent with tf_interpolate().
  • Summary group generics on tf_mv no longer recycle NA masks across
    operands of different lengths.
  • tf_arclength(): method = "polyline" honors lower/upper without
    creating near-duplicate vertices, and method = "derive" no longer
    NA-poisons irregular curves that do not span the full domain.
  • Indefinite tf_integrate() on irregular tfd snaps user-supplied limits
    to (almost-)coinciding grid points instead of constructing invalid objects.
  • tf_register() works for tf_mv inputs whose components live on different
    grids; tf_register_shape() returns a user-supplied template unchanged
    from tf_template(); single-component srvf_mv delegates to univariate
    elastic registration and template-free single-curve registration is
    rejected with an explanation instead of crashing inside fdasrvf.

v0.4.1

Choose a tag to compare

@fabian-s fabian-s released this 07 Apr 10:26
015f182
Merge pull request #230 from tidyfun/issue-229-checkmate-imports

Fix R-devel import conflicts and bump version to 0.4.1

tf 0.4.0

Choose a tag to compare

@fabian-s fabian-s released this 19 Mar 15:16

New features

  • tf_register() & co implement registration methods (SRVF, affine, landmark,
    continuous-criterion) for aligning functions and analyzing phase variability.
    Returns a new tf_registration class with accessors tf_aligned(),
    tf_inv_warps(), tf_template().
  • tf_depth() now implements five functional depth methods: MBD (default), MHI,
    FM (Fraiman-Muniz), FSD (Functional Spatial Depth), and RPD (Regularized
    Projection Depth). MHI ranks functions from lowest (0) to highest (1); all
    other depths are scaled from 0 (most extreme) to 1 (most central).
    MBD is now scaled to [0, 1] instead of [0, 0.5].
  • tf_split() / tf_combine() for splitting functions into sub-domain
    fragments and re-combining them
  • tf_rgp() gains a "brownian_bridge" covariance option and can generate
    irregular data via the new irreg argument
  • tfb_spline() now converts fda::fd and fda::fdSmooth objects directly
  • mgcv-style Fourier basis constructor for use in tfb_spline()
  • sparklines in print() / format() for all tf subtypes
  • tf_where() now defaults to arg = tf_arg(x), consistent with other functions
  • as.matrix() for irregular tfd now always interpolates to a common grid

Bug fixes

  • tf_derive() for tfd objects now uses second-order accurate finite
    differences, preserving the original domain and grid (#59)
  • major overhaul of NA handling: NA entries are now consistently represented as
    NULL internally; fixes for tf_arg(), tf_evaluate(), tf_smooth(),
    tfd() conversion, is.na(), printing, and arithmetic with NA entries
  • fix summary.tf() returning wrong central range
  • fix tfd domain enforcement for length-1 data (#139)
  • fix printing for empty tfb objects and all-NA vectors

Other changes

  • tf_derive and tf_integrate can now handle tfb with non-identity link functions
    by falling back to tfd-calculus methods (and returning tfd objects).
  • tfd_irreg arithmetic now operates on intersection of arg-values instead
    of failing when arg-values are not identical
  • tfb arithmetic fix
  • dropped glue dependency in favour of cli / sprintf;
    replaced stopifnot() with informative cli::cli_abort() throughout
  • use vctrs::vec_arith() for group generics, vctrs utils in [.tf
  • various internal performance improvements
  • use air formatter for all R code

tf 0.3.4

Choose a tag to compare

@fabian-s fabian-s released this 22 May 10:32
  • bug fix: normalize tf_crosscov correctly