
Predict Trained Genotypes at Untested Environments Without Refitting
Source:R/env_prediction.R
scan_untested_envs.RdTransfers a fitted kernel_model to environments that were never
planted – new locations, new planting dates, or both – using only their
environmental covariates. No re-fitting and no phenotypes at the new sites
are required.
The environmental main effect estimated at the training sites is kriged onto each new site through a linear environmental kernel, and the whole posterior is carried draw-by-draw so that credible intervals, win probabilities and an extrapolation diagnostic are all internally consistent.
The transfer. Covariates are standardised on the training moments,
$$\tilde{W} = (W - \bar{W}_{tr}) \; / \; s_{tr},$$
and a linear (product) environmental kernel is formed from the \(p\)
covariates,
$$K_{tt} = \tilde{W}_{tr}\tilde{W}_{tr}^{\top}/p, \quad
K_{nt} = \tilde{W}_{n}\tilde{W}_{tr}^{\top}/p, \quad
K_{nn} = \tilde{W}_{n}\tilde{W}_{n}^{\top}/p.$$
The new-site environmental effects are a kriging (Gaussian-process
conditional-mean) map of the training effects,
$$H = K_{nt}\,(K_{tt} + \lambda I)^{-1}, \qquad
\hat{e}_{n}^{(d)} = H\,e_{tr}^{(d)},$$
applied to every retained MCMC draw \(d\). When a GxE kernel is present its
interaction effects are kriged the same way. The ridge \(\lambda\)
stabilises the inverse; \(H\) is not constrained to be positive, and
large negative row weights are the signal that a site is being reached by
extrapolation (see weight_negativity below).
The prediction. For draw \(d\), genotype \(g\) and new site \(j\), $$\hat{y}^{(d)}_{gj} = \mu + u_g^{(d)} + \hat{e}^{(d)}_{j} + \widehat{(ge)}^{(d)}_{gj},$$ with \(\mu\) the training grand mean. Point predictions are posterior means over draws and the credible interval uses the empirical quantiles at \(\alpha=(1-\texttt{level})/2\) and \(1-\alpha\). The probability that a genotype is the best at a site is the fraction of draws in which it attains the row maximum, so it respects the genotype correlation within a draw. Per-site genomic heritability is reported as \(h^2 = \sigma^2_g / (\sigma^2_g + \sigma^2_e)\).
Arguments
- object
a fitted model from
kernel_model, fitted withkeep_effects = TRUE. The per-draw effect chains (not posterior means) are required; without them the intervals would be fabricated.- W_train
training environmental covariate matrix, environments \(\times\) covariates (\(e \times p\)). If it has no
rownamesthey are taken to be the sorted training environments.- W_new
new-environment covariate matrix, sites \(\times\) covariates (\(m \times p\)). Must have the same columns as
W_train. Unnamed rows are labelledNewEnv1..NewEnvm.- K_G
optional genomic relationship matrix. Used only to inform the GxE transfer; when omitted, GxE is kriged from environmental similarity alone (a warning is issued).
- standardize
logical. Standardise covariates on the training mean and SD before building the kernels. Default
TRUEand strongly advised when covariates are on different scales.- lambda
numeric ridge added to \(K_{tt}\) before inversion, as a fraction of its mean diagonal. Default
1e-6. Raise it if the kernel is near-singular (highly collinear covariates).- level
credible-interval mass. Default
0.95.- max_draws
integer. Cap on the number of MCMC draws used; draws are thinned by even spacing when the chain is longer. Default
500.- envelope
what to do about sites that fall outside the training covariate envelope:
"keep"(default, return everything unchanged),"flag"(return everything, warn),"mask"(set flagged predictions toNAbut keep the matrix structure so indexing by environment name still resolves), or"drop"(remove flagged rows/columns and record them in$excluded).- envelope_level
which sites count as flagged:
"gross"(default) or"mild". Only"gross"separates cleanly in calibration;"mild"acts on a weak signal and is not recommended as a gate.
Value
An object of class "scan_untested_envs": a list with
yHat_matrix,yHat_lower,yHat_uppergenotype \(\times\) new-site matrices of the posterior mean and credible bounds.
yHatthe same in long form, with
ci_width.yHat_prob_winprobability each genotype is best at each site.
genetic_varper-site genetic variance, its interval and
genomic_h2.vcov,corbetween-new-site genetic covariance and correlation matrices.
interpolation,divergence,diagnosticsthe extrapolation measures described above, one row per new site.
exceedance_detailone row per (site \(\times\) offending covariate) that fell outside the training range.
excludedsites masked or dropped by
envelope, elseNULL.metadimensions, settings, similarity and kriging weights.
Details
Extrapolation diagnostics. The scan reports where each new site sits relative to the training covariate cloud. Several complementary measures are returned because no single one is sufficient:
Cosine similarity to the nearest training site, \(s_{ij} = K_{nt,ij}/\sqrt{K_{nn,ii}\,K_{tt,jj}}\), summarised as
max_similarityandmean_similarity.A Mahalanobis-type distance in the leading principal-component subspace (enough PCs to reach 95% variance), \(d_i = \sqrt{\sum_k z_{ik}^2}\), divided by the 95th percentile of the training distances to give
mahalanobis_ratio.A marginal range test per covariate (
prop_outside,max_exceedance_sd). This is marginal: a site inside every covariate's range individually can still occupy a combination that never occurred, which only the distance and weight measures catch.Kriging-weight geometry:
weight_negativity\(= \sum_j \min(H_{ij},0)\) and the effective number of training sites leaned on, \(n_{\mathrm{eff},i} = (\sum_j |H_{ij}|)^2 / \sum_j H_{ij}^2\).A combined
divergence_index\(= \min\!\big(1, \max(0,\; 0.5(1-s_{\max}) + 0.5\,t)\big)\) with \(t = \mathrm{clamp}((\texttt{mahalanobis\_ratio}-0.5)/2,\,0,\,1)\).
Sites are labelled "interpolation", "edge",
"mild_extrapolation" or "gross_extrapolation" from these.
Position is geometry, not a correctness guarantee. Calibration
against 60 held-out environments found the envelope measures correlate only
\(r \approx -0.37\) to \(-0.66\) with realised accuracy. Treat the
position label as a description of where a site lies, never as a verdict that
the prediction is right or wrong. The model-internal ci_width_ratio
was the strongest single accuracy correlate (\(r=-0.66\)); to know your
true accuracy, run leave-environments-out cross-validation on your own data.
References
Costa-Neto, G., Fritsche-Neto, R. & Crossa, J. (2021) Nonlinear kernels, dominance, and envirotyping data increase the accuracy of genome-based prediction in multi-environment trials. Heredity 126, 92-106.
Jarquin, D. et al. (2014) A reaction norm model for genomic selection using high-dimensional genomic and environmental data. Theoretical and Applied Genetics 127, 595-607.
Cressie, N. (1993) Statistics for Spatial Data. Wiley. (kriging as a Gaussian-process conditional mean.)
Examples
# \donttest{
data("maizeWTH"); data("maizeYield"); data("maizeG")
## Training covariates (first 100 days after sowing)
vars <- c("FRUE", "PETP", "GDD", "T2M_MAX")
Wtr <- W_matrix(env.data = maizeWTH[maizeWTH$daysFromStart < 100, ],
var.id = vars, statistic = "mean")
#> ---------------------------------------------------------------
#> W_matrix -- builds the environmental covariable (W) matrix
#> Last updated at 09/27/2026
#> ---------------------------------------------------------------
#> - summarising weather data into environmental covariables
#> - centring, scaling and quality-controlling W
## Fit KEEPING the effect chains -- required by the scan
K <- get_kernel(K_G = list(G = maizeG),
K_E = list(W = env_kernel(env.data = Wtr)[[2]]),
data = maizeYield, model = "RNMM",
env = "env", gid = "gid", y = "value")
#> ---------------------------------------------------------------
#> env_kernel -- builds environmental relatedness kernels
#> Last updated at 09/27/2026
#> ---------------------------------------------------------------
#> - computing a single environmental kernel
fit <- kernel_model(y = "value", data = maizeYield, random = K,
env = "env", gid = "gid", keep_effects = TRUE)
## Predict the trained genotypes at new sites (reuse the training W here)
sc <- scan_untested_envs(fit, W_train = Wtr, W_new = Wtr, K_G = maizeG)
#> Warning: Only 5 training environments. This tool is designed for a LARGE training network; with few environments the covariate-to-performance mapping is poorly estimated.
sc # print method: per-site diagnostics
#> <scan_untested_envs> 150 genotypes x 5 new environments
#> trained on 5 environments | 4 covariates | 100 draws
#> GxE included: TRUE | credible level: 0.95 | envelope: keep
#>
#> env position pred ci_ratio mahal out w_neg max_sim
#> NM interpolation -0.491 1.84 0.22 0% -0.78 1
#> SO edge 0.953 3.04 1.00 0% -0.79 1
#> PM interpolation 0.519 2.00 0.57 0% -0.49 1
#> IP interpolation -1.117 3.35 0.99 0% -0.79 1
#> SE interpolation 0.427 2.42 0.73 0% -0.69 1
#>
#> position: interpolation 4 | edge 1 | mild_extrapolation 0 | gross_extrapolation 0
#>
#> Position is GEOMETRIC: where the site sits relative to the training
#> covariate cloud. It is not a reliability verdict. Calibrated on 60
#> held-out environments:
#> ci_width_ratio vs accuracy r = -0.66 (best accuracy guide)
#> divergence_index vs accuracy r = -0.41
#> max_similarity vs accuracy r = +0.12 (NOT predictive)
#> max_similarity vs gain-over-mean r = +0.69 (best gain guide)
#> Lower ci_width_ratio = more precise. Higher max_similarity = the
#> covariates are more likely to beat a plain genotype mean. To know your
#> real accuracy, run leave-environments-out CV on your own data.
head(sc$yHat) # predictions + credible intervals
#> gid env yHat lower upper ci_width
#> 1 G001 NM -0.4519297 -0.6343264 -0.2475748 0.3867516
#> 2 G002 NM -0.4883372 -0.6542589 -0.3228566 0.3314023
#> 3 G003 NM -0.4882496 -0.6542457 -0.3233927 0.3308530
#> 4 G004 NM -0.5660495 -0.8463357 -0.2748072 0.5715285
#> 5 G005 NM -0.4501614 -0.7187839 -0.2195134 0.4992705
#> 6 G006 NM -0.7938049 -1.2915761 -0.3402577 0.9513184
sc$interpolation[, c("env", "position", "mahalanobis_ratio")]
#> env position mahalanobis_ratio
#> 1 NM interpolation 0.2151366
#> 2 SO edge 1.0022725
#> 3 PM interpolation 0.5666292
#> 4 IP interpolation 0.9909099
#> 5 SE interpolation 0.7312492
# }