Skip to contents

metaprep 0.4.1

  • rma_mv_helper() and rma_uni_helper() accept a formula for yi again. metafor reads a two-sided yi as estimates-on-the-left, moderators-on-the-right, so rma_mv_helper(ev, estimate ~ x) fits what rma_mv_helper(ev, yi = estimate, mods = ~ x) fits, down to the coefficient names. Both help pages have documented yi as “Formula or bare column name” since the functions were written. 0.3.1’s non-finite guard assumed yi evaluated to a numeric vector and called is.finite() on it, so every formula call started failing with default method not implemented for type 'language'. The guards now check the two sides separately (left-hand side finite, right-hand side present on the object) and the formula is passed to metafor untouched, so the fit is exactly what it was before the guard existed rather than a mods = call rebuilt by this package. estimate ~ 1, the plain pooled fit written in formula form, is covered by its own test against the bare-yi fit.

    Supplying both a formula yi and mods is now an error rather than silently dropping mods, and a one-sided yi such as ~ x is an error naming the fix instead of failing inside metafor.

metaprep 0.4.0

  • The variance-covariance matrix is now stored sparsely. A block-diagonal vcov is overwhelmingly zeros (99.88% on the largest object in real use), so this is a large win: 27.5 MB becomes 0.3 MB, and metafor::rma.mv() runs roughly 7x faster because it does not densify internally. Verified against 115 estimates_vcov objects: every vcov quantity, and every pooled fit on a well-conditioned object, is unchanged. get_vcov() returns the stored matrix rather than converting it, and make_estimates_vcov() accepts either a base matrix or a Matrix and converts neither, so storage follows the data (a bootstrapped cov() is genuinely dense and would only grow if forced sparse). Sparse matrices print with . for structural zeros, which makes the block-diagonal structure easier to read.
  • Breaking-ish: Matrix moves from Imports to Depends, so library(metaprep) now attaches it. This is required rather than cosmetic: Matrix defines diag() and t() as S4 generics in its own namespace instead of adding methods to the base functions, so without attachment diag(ev$vcov) does not take the diagonal of a sparse matrix, it errors. Attaching Matrix masks base t, diag, det, solve, and crossprod in your search path. Code that tested is.matrix(ev$vcov) will now get FALSE; see the “Public interface” section of ?estimates_vcov for what the object does and does not promise. Scalar element access (V[i, j] in a loop) is markedly slower on a sparse matrix, so call as.matrix() once if you are reading thousands of individual cells.
  • Internally, the four operations the package performs on a vcov are now storage-agnostic, so the representation cannot affect a reported number. rma_uni_helper() takes the diagonal with Matrix::diag() rather than diag(), which would have errored on a sparse matrix.

metaprep 0.3.1

  • New ?estimates_vcov help page documenting the object the package is built around. It had none: the central noun of the package was undocumented, so nothing said what the components are, what the id column is for, which dplyr verbs keep the vcov aligned and which are refused, or what the object guarantees at construction. ?metaprep is also new, giving the four-step workflow and the two silent failures the package refuses to guess about.

  • ?estimates_vcov gains a “Public interface” section settling what callers may rely on. estimates and vcov are public: read them as ev$estimates / ev$vcov or through [get_estimates_df()] / [get_vcov()], whichever suits, and both will keep working. What is guaranteed about vcov is its content and shape (square, symmetric, finite, one row and column per estimate in the same order, dimnames equal to id), not its storage class, so ordinary matrix operations are the supported way to use it and is.matrix() is not. row_map is documented as internal, since the verbs do not agree on what its “parent” means: filter() and the filtering joins set it to positions within the object they were handed while arrange() composes it through. Use id for a stable per-estimate label.

  • The S3 methods are reachable by name. ?filter.estimates_vcov, ?print.estimates_vcov, ?nest_by.estimates_vcov and the rest previously returned “no documentation”: the dplyr-methods page carried no aliases, so a caller who knew a method’s name could not find its page.

  • dplyr-methods gains runnable examples, documented arguments, and a @return section. It is the page that carries the mutate(estimate = -estimate) desync warning and it had nothing runnable beside the prose. The examples now show the trap and its fix on the one entry where it is visible, the within-study covariance, using a partial sign flip so the covariance changes sign.

  • @family tags group the exports into estimates_vcov objects, component accessors, and meta-analysis wrappers, so every page now generates a See Also block pointing at its siblings. There were none before, across ten exports. prep_fit() gains an explicit @seealso to the same effect.

  • New examples use base lm() rather than randomizr plus estimatr, so they run without any suggested package installed.

  • rma_uni_helper() no longer discards covariances silently. rma.uni() takes only the variances, so calling it on an object whose vcov has nonzero off-diagonals throws away the dependence the package exists to carry and returns a standard error that is too small: on a five-estimate two-study object, 0.100 against rma_mv_helper()’s 0.152. The docs already said to use rma_mv_helper() for correlated estimates, but nothing fired at runtime. When vi is not supplied and the vcov has nonzero off-diagonal entries, rma_uni_helper() now warns (class "metaprep_discarded_covariance"), names how many covariances were dropped, and points at rma_mv_helper(). Supplying vi explicitly silences it and returns an identical fit, which is the way to say the univariate fit is what you meant. Objects with no covariances (the ordinary univariate case) are unaffected.

  • rma_mv_helper() and rma_uni_helper() now error when an estimate entering the pool is NA, NaN, or infinite. metafor drops such rows with a warning and returns a fit whose k is smaller than the object, so anything joining a per-estimate quantity back onto the estimates (weights(), resid()) silently misaligns. The error names the count and the affected ids. This is the mirror of the non-finite vcov guard added in 0.2.x, and it follows the same reasoning: an estimate that cannot carry its own weight must not enter a pooled fit silently, and which estimates to drop is the analyst’s call. Verified against 115 estimates_vcov objects across the meta-reanalysis projects, none of which has a non-finite estimate, so no existing pipeline changes.

  • Fourteen error and warning messages were silently dropping their guidance bullet. rlang::abort(msg, "i" = hint) passes the hint into ..., where rlang stores it as a condition field and never prints it; the bullets only render when they are part of the message vector, as rlang::abort(c(msg, "i" = hint)). So as_estimates_vcov(some_data_frame) reported only “Input must contain list-columns named tidy_obj and vcov_obj.” and swallowed “Did you pass the result of prep_fit()?”, which is the hint a first-time caller most needs. All fourteen now print their bullet: the four “did you pass prep_fit() output” hints, the four dimension and squareness reports, the three missing-package install lines, get_glance_df()’s pointer to extract glance before building the object, and prep_fit()’s missing-tidy()/glance()/ vcov()-method hints. A new test-error-messages.R asserts on the hint text rather than the headline, so the defect class cannot return silently.

  • The vignette’s bootstrap section pooled with random = ~ 1 | study where every other chunk uses random = ~ 1 | id, so the one place the reader meets a combined object silently switched to a different model (a study-level intercept over five levels rather than an estimate-level random effect over eight, moving tau^2 from 0.006 to 0.020 and the pooled estimate from 0.223 to 0.238). Worse, the two bootstrapped rows are one study sharing subjects, and ~ 1 | study entered them as two independent studies. Now ~ 1 | id throughout.

metaprep 0.3.0

  • Breaking: estimates_vcov_from_pieces() is renamed make_estimates_vcov(). No deprecated alias is kept, since the package has not been released. Rename call sites; the arguments and behavior are unchanged.
  • make_estimates_vcov() is documented as the entry point for estimates whose covariances do not come from a single regression – most often experiments run on overlapping samples, where the covariance between their estimates comes from bootstrapping the design and taking cov() of the replicate estimates. Previously it was described only as a way to recombine the output of get_estimates_df() and get_vcov(), which undersold it. The docs now state that the vcov is matched to the estimates by position and that any dimnames on the matrix are discarded, and recommend supplying std.error so rescale_estimates_vcov() has standard errors to rescale. The vignette gains a “Correlated estimates with no single regression” section working the overlapping-samples bootstrap end to end, through bind_estimates_vcov() and rma_mv_helper().

metaprep 0.2.3

  • prep_fit()’s term argument now accepts tidyselect expressions matched against the model’s term names, e.g. prep_fit(fit, starts_with("Z_party")), so callers no longer hand-build a coefficient-name vector with grep(..., names(coef(fit))). A treatment’s main effect can be taken while dropping its interactions with tidyselect’s own set algebra, e.g. matches("^Z_treated$") or starts_with("Z_treated") & !contains(":"). A character vector still works exactly as before (exact names, or regex with match = "regex").

metaprep 0.2.2

  • New rescale_estimates_vcov() sign-flips or rescales the estimates of an estimates_vcov object and updates the vcov to match (diag(s) V diag(s)), keeping the object consistent. This is the correct way to flip signs (including a partial flip of some arms) or change units; the dplyr methods keep the vcov row-aligned but never transform it, so mutate(estimate = -estimate) alone would leave the vcov inconsistent. The dplyr-methods docs now note this.

metaprep 0.2.1

  • The cluster argument of rma_mv_helper() and rma_uni_helper() now accepts a bare column name, a string-named column via .data[[var]], or an external vector (previously only a bare column name worked). It is captured with rlang::enquo(), so it composes inside wrapper functions that pass the clustering variable programmatically.

metaprep 0.2.0

  • rma_mv_helper() and rma_uni_helper() gain a cluster argument (a bare column name evaluated in the estimates, like yi) and a clubSandwich argument. When cluster is supplied the fit is wrapped in [metafor::robust()], so rma_mv_helper(ev, yi = estimate, random = ~ 1 | id, cluster = study) returns CR2 cluster-robust standard errors in one step. Defaults are unchanged (cluster = NULL returns the ordinary fit).
  • New bind_estimates_vcov() combines two or more estimates_vcov objects into one, stacking the estimates and assembling a block-diagonal vcov (zero covariance between objects), with id renumbered across the result.
  • as_estimates_vcov() and estimates_vcov_from_pieces() now repair floating-point asymmetry in the vcov and error on asymmetry beyond a relative tolerance, which would indicate a malformed (non-covariance) matrix.
  • rma_mv_helper() and rma_uni_helper() now error if a mods formula references a column that is not on the estimates_vcov object, so a moderator that never made it onto the object fails loudly instead of silently producing an empty meta-regression. The vignette gains sections on cluster-robust standard errors and meta-regression.

metaprep 0.1.0