Changelog
Source:NEWS.md
hvtiRimputation 0.1.3
DESCRIPTIONnow declares the Quarto command line tool inSystemRequirements, which the new vignette needs to build.New Overview vignette,
vignette("hvtiRimputation"). It walks one small synthetic example fromimpute_mean()through the record, the row-level attrition columns, indicators, provenance and the inputs the package refuses, then shows theimpute_multiple()prototype. On the pkgdown site, articles put the table of contents on the left and use the full window width, throughpkgdown/extra.css.quartoandknitrjoinSuggests.
hvtiRimputation 0.1.2
-
impute_multiple()is now reproducible by default (breaking).seedis required, either as an argument or once per session throughoptions(hvtiRimputation.seed = ); with neither, the call fails. The old default,seed = NA, left the draws to whatever state R’s RNG happened to be in. Themicecall now runs underwithr::with_seed()with the RNG kind pinned to R’s defaults, so the same seed gives the same imputations after anyset.seed()orRNGkind()change, and the caller’s own random stream is restored afterwards. A call that already passed a seed gets the same values as before under R’s default RNG kind.withris a new import. - A new test parses
R/and fails on a call outsidewithr::with_seed()to any function in a defined audited set: everystatsrandom generator (found from the installedstatsexports, so new ones are covered),sample(),jitter(),simulate(),mice,randomForestSRCandvarPro. It also fails on arandomForestSRCcall without a negativeseed =, and it self-tests on planted violations. A function that draws from the RNG internally without being in that set is outside the audit. - Now requires R 4.4.0 or newer, up from 4.1.0, to match the rest of the HVTI family.
hvtiR::install()installs the members together, and several already required 4.4.0, so on an older R the install failed whatever this package declared.
hvtiRimputation 0.1.1
New features
-
impute_multiple()prototype. Multiple imputation by chained equations (mice), returningmcompleted datasets stacked long plus the same shape of recordimpute_mean()returns. Method defaults tomice’s own per-column dispatch (pmm/logreg/polyreg/polr) rather than one string forced across every column; a named-vectormethodargument overrides specific columns. A new class,hvti_imputation_multi, keepsimpute_mean()’s own contract untouched.imputed_data()is now a real S3 generic; itshvti_imputation_multimethod requires animputationargument with no default, on purpose – seedev/specs/2026-09-23-impute-multiple-design.mdfor why. Pooling (Rubin’s rules) remains out of scope, per the design note and the README.
hvtiRimputation 0.1.0
First release. Single mean imputation, and the record that goes with it.
The
impute_mean()help page no longer tells readers to call the designed but unimplementedimpute_multiple()function.Coverage uploads without a Codecov token are now best-effort, so a successful package test run is not marked failed solely because tokenless upload is unavailable.
impute_mean()portsPROC STANDARD ... REPLACE– the form with noMEAN=/STD=, which theimputsubmacro wraps. Missing values are filled with the variable’s mean over its non-missing values; observed values are never touched.The record is a logical matrix parallel to the data, one column per imputed variable,
TRUEwhere a value was filled. Read it withimputed_matrix(). A count cannot answer was this patient’s value imputed?, so the matrix is the primary artifact andsummary()is a view of it rather than a replacement for it.imputed_any(),complete_case_pass()andanalysis_pass()are the row-level columns the attrition record consumes.complete_case_pass()is read from the input, before anything is filled – evaluated on the completed data every row overvarswould pass, which is the opposite of what the column means.analysis_pass()is the same question after imputing.-
kept_by_imputation()counts the rows in an analysis only because a covariate was filled in – the number that catches a port which imputed the wrong variable list yet still reached the right row count.⚠️ It is
analysis_pass & !complete_case_pass, notimputed_any & !complete_case_pass. The latter overcounts: it isTRUEfor a row that had a value filled but is still incomplete because a column outsidevarsis missing, and such a row never enters the analysis at all. The two agree only when imputation completes every row, which is the case the design was written against – so the wrong formula gave the right answer there and the error was invisible. imputation_indicators()generates missingness indicators from the record, with a prefix the caller chooses. The SASms_*spelling is available (prefix = "ms_") and is deliberately not the default: a convention adopted for parity becomes permanent.imputation_provenance()records the method,m, the fill values, the package version and the seed. An imputed dataset that does not say how it was imputed cannot be reproduced.
Divergences from SAS, stated once
-
varsis required.PROC STANDARDwith noVARstatement processes every numeric variable in the dataset; that default is not inherited. An imputation that silently chose its own variable list is the failure the record exists to catch. -
An all-missing variable is an error, not a pass-through. There is no mean to impute from, and leaving the column as
NAwhile reporting it as imputed would be a lie in the record. -
A non-finite mean is an error.
mean(c(Inf, -Inf), na.rm = TRUE)isNaN; filling with it leaves the cell missing while the record marks it imputed. An infinite mean is refused in the other direction, as not a plausible measurement. The completed column is then asserted to hold no missing values, so the invariant is proved rather than assumed. -
A classed numeric is an error, even though it passes
is.numeric().bit64::integer64packs a 64-bit integer into a double’s bits, so taking its mean into an ordinary double reinterprets the bit pattern – a column of 1 and 3 completes as 0, with the provenance recording9.88e-324rather than 2. Wrong data and wrong provenance, no error. The guard keys on the class attribute rather than a list of known classes, so it also catches whatever the next one is called. Convert withas.numeric()yourself, so the conversion is a choice you made. -
Duplicated column names in
dataare an error.data[["age"]]returns the firstage, so naming it fills one column, leaves the other missing, and emits a single record column that cannot say which. An audit cannot read that. - A non-numeric variable is an error. A mean of a factor or a character column is not defined, and guessing one would be a method choice made silently.
Not in this release
impute_multiple() (PROC MI, mult_imput) is designed and not built. Pooling by Rubin’s rules is deferred: multiple imputation is only multiple imputation if the results are pooled, and that is separate work with its own verification. BY-group means are unmeasured in the corpus and unimplemented. PROC STANDARD MEAN=0 STD=1 REPLACE, which standardises and fills, is a different operation and is not what impute_mean() does.