Imputes missing species trait data for comparative analyses
by combining three sources of information: phylogenetic similarity
(closely related species share similar traits), cross-trait
correlations (observed traits inform missing ones), and optional
environmental covariates (climate, habitat, geography). Handles
continuous measurements, counts, binary variables, ordered categories,
unordered categories, bounded proportions, zero-inflated counts, and
compositional multi-proportion data in a single call. The default
method is a phylogenetic baseline calibrated on held-out data; an
optional graph neural network correction, which is needed to use
covariates, is blended in through a per-trait gate that retains a
baseline fallback. Provides conformal
prediction intervals for continuous, count, ordinal, and proportion
traits and an experimental analysis-aware multiple-imputation workflow
for one missing continuous covariate in Gaussian linear, binomial-logit,
and Gaussian random-intercept models, with Rubin pooling limited to
fixed effects.
Stochastic graph-network and posterior-tree completions are prediction
diagnostics rather than validated inferential imputations.
Bundled datasets include 300-species and 9,993-species bird-trait subsets
with matching example phylogenetic trees.
Rubin (1987, ISBN:978-0-471-08705-2); Vovk et al. (2005,
ISBN:978-0-387-25061-8); Nakagawa and de Villemereuil (2019)

Warning: pigauto is experimental; use at your own risk. It needs further validation. Point estimates are the supported claim. Prediction intervals are nominal held-out diagnostics, not package-wide certification; covariance routes have focused-test evidence only.
pigauto fills missing species trait values using a phylogenetic tree, other traits, and optional covariates. It supports continuous, count, binary, categorical, ordinal, proportion, zero-inflated-count, and compositional traits.
The workflow below uses functions and defaults from pigauto 0.11.0. Check
packageVersion("pigauto") after installation: the CRAN release can lag
behind the GitHub version described on this site.
For the released version:
install.packages("pigauto")
packageVersion("pigauto")
If CRAN has an earlier version, install the GitHub version to use this workflow:
# install.packages("pak") # once, if needed
pak::pak("itchyshin/pigauto")
# torch::install_torch() # once, if you opt into gnn = TRUE
Put a CSV trait table (with a unique species column) and a Newick or NEXUS
tree beside your R script. Then start with this short workflow:
library(pigauto)
traits <- read_traits("traits.csv")
tree <- read_tree("tree.nwk")
check_pigauto(traits, tree)
result <- impute(traits, tree)
completed <- completed_data(result)
pigauto_report(result)
BirdTree distributes its tree files in Newick format. Download one from
BirdTree and read it with read_tree();
read_tree() also accepts NEXUS files from other sources. Cite Jetz et al.
(2012) for the tree, and cite BirdTree.org when you use its website. pigauto uses
the tree you provide and
does not download BirdTree data automatically. The bundled tree300 is a
teaching example; it is not a consensus or recommended analysis tree.
impute() now uses the phylogenetic baseline by default (gnn = FALSE),
estimates Pagel's lambda for eligible traits, and leaves the mean safety
floor and phylogenetic-signal gate off. To train the optional graph neural
network, install the torch runtime once and call
impute(traits, tree, gnn = TRUE). The former GNN-on behaviour is an
explicit choice in 0.11.0.
check_pigauto() and completed_data() were added in 0.11.0. If your
installed version is 0.10.0, call impute(traits, tree) directly; that
version does not include check_pigauto().
check_pigauto() runs before fitting: it reports input errors, species/tree
matching, trait declarations, and estimated size. Its default gnn = FALSE
matches impute() and does not probe torch. Pass gnn = TRUE when planning a
GNN fit to include runtime availability. Resolve an "error" status before
fitting; a fully observed target table does not need imputation, so use
cross_validate() instead.
The output roles are deliberately separate:
completed is the input-shaped trait data with observed values retained and
modeled missing cells filled.result$prediction contains all-cell diagnostic predictions, not a second
completed dataset.result$prediction$se is type-dependent uncertainty; discrete values are
not Gaussian standard errors. Conformal bounds are nominal held-out
diagnostics.pigauto_result does not itself authorize downstream inference. The
supported pooling entries begin with multi_impute_analysis() in its
documented narrow regime or, for continuous traits,
multi_impute(draws_method = "posterior"). multi_impute()'s default,
draws_method = "auto", picks "posterior" whenever the data allow it
and otherwise says why it fell back to non-poolable conformal draws.Tiny installed example inputs are available at
system.file("extdata", "novice_traits.csv", package = "pigauto") and
system.file("extdata", "novice_tree.nwk", package = "pigauto"). The
matching installed six-expression script is
system.file("examples", "novice-workflow.R", package = "pigauto").
Use an ordered factor when states have a known order.
traits$threat_status <- ordered(
traits$threat_status,
levels = c("LC", "NT", "VU", "EN", "CR")
)
result <- impute(traits, tree)
An integer column is otherwise read as a count. Declare a measurement stored as whole numbers explicitly.
result <- impute(
traits, tree,
trait_types = c(body_length_mm = "continuous")
)
Declare proportions only when their numeric 0–1 scale is semantically a
proportion. Declare zi_count only when zero is a separate process from the
positive count magnitude.
result <- impute(
traits, tree,
trait_types = c(habitat_cover = "proportion", parasite_load = "zi_count")
)
Each declared composition is one trait: every row must have all components or all components missing, and observed rows must sum to one.
result <- impute(
traits, tree,
multi_proportion_groups = list(diet = c("diet_insect", "diet_fruit", "diet_seed"))
)
read_traits() requires unique species names. For repeated observations,
read the CSV directly and supply species_col.
traits_obs <- read.csv("traits_repeated.csv", stringsAsFactors = FALSE)
check_pigauto(traits_obs, tree, species_col = "species")
result <- impute(traits_obs, tree, species_col = "species")
Inspect the structured species report before changing data:
check <- check_pigauto(traits, tree)
check$species$matched
check$species$data_only
check$species$tree_only
data_only rows remain in completed but are not modeled or filled.
tree_only tips are internal all-missing rows used only while fitting.
impute(traits, tree) with its defaults is the starting point. The table
says which route to take for each need; reach for another route only for
the need in the left-hand column.
| You want | Use | Default? |
|---|---|---|
| Filled-in traits | impute(traits, tree) |
Yes |
| Uncertainty for one imputed value | the per-cell conformal interval in result$prediction |
Yes |
| A linear downstream analysis of imputed continuous traits on their imputation scale | multi_impute(traits, tree), then with_imputations() and pool_mi() |
Yes, when every trait is continuous, with one row per species and no covariates: the default draws_method = "auto" then uses posterior draws |
One incomplete covariate in lm, binomial-logit glm, or Gaussian random-intercept lmer |
multi_impute_analysis() |
No |
For other data, draws_method = "auto" falls back to "conformal" draws
and says so. Those draws, like "mc_dropout", describe the spread of
plausible values but are not proper multiple imputations: in a simulation
of a phylogenetic regression they biased the pooled slope towards zero, and
with_imputations() refuses them. Bayesian downstream fits (brms, MCMCglmm) are
combined by stacking posterior draws, for example with
brms::brm_multiple(), not with pool_mi(). Worked examples for nlme,
lme4, glmmTMB, drmTMB, gllvmTMB and brms are in the
multiple imputation article.
The ability to fit and extract coefficients from a model class does not by
itself validate the imputation model for that analysis; check the article's
conditions before interpreting pooled estimates.
The default journey above is the supported starting point. These controls are for an explicit technical workflow and are kept separate from it.
# Solver, EM, and refinement controls
result <- impute(
traits, tree,
joint_solver = "rphylopars",
em_iterations = 2L,
joint_refine_iter = 1L,
conformal_split_val = TRUE
)
# Prediction route: the default "auto" chooses per trait between the
# cross-trait "exact" conditional and "per_column"; force one with
result <- impute(traits, tree, predict_method = "exact")
See ?impute, ?fit_baseline, and the articles for all calibration,
refinement, and prediction controls.
Nakagawa S (2026). pigauto: Phylogenetic Imputation via Graph Autoencoder.