Transforming R-INLA code to Inlabru

33 views
Skip to first unread message

Bamidele Toba

unread,
Sep 6, 2025, 8:59:47 AM (2 days ago) Sep 6
to R-inla discussion group

In INLA, I can provide a projection matrix A for a spatial effect in both estimation and prediction stacks. For example:

In Estimation Stack: A = list(1, A_matrix, diagonal(n)), where 1 represents the intercept, A_ matrix is an inla.spde.make.A from the observed data and diagonal(n) represents an IID random effect,

In Prediction Stack: A = list(1, A_pred, diagonal(n)), where 1 represents the intercept, A_pred is the SPDE projection for the prediction locations and diagonal(n)  represents the IID effect at the prediction locations.

Similarly, I can also provide a custom projection matrix for the spatial effect in both estimation and prediction stacks, where A_pred is a custom projection corresponding to the latent locations in A_matrix.

In inlabru, there is no direct way to supply the custom projection matrix A. How can I reformulate INLA codes to inlabru so that inlabru correctly maps a custom spatial latent effect to each observation for both estimation and prediction?

Finn Lindgren

unread,
Sep 7, 2025, 3:28:38 PM (yesterday) Sep 7
to Bamidele Toba, R-inla discussion group
Hi Bamidele,

with inlabru, you normally don't need to supply those matrices at all, as they are constructed automatically based on your input data, which in your case should contain the geographic locations, and the index into the prediction locations; assuming you have an sf data frame "my_data" with geometry column called "geometry" (this is usually the case, but st_geometry(data) <- "geometry" can be used to set it to whatever name you want; "geometry" is the most common, and what all the inlabru examples assume) and an index column called "ID".
Also assume the sf object has the response variable, called "y", with NA values for the rows where you have new prediction locations.

Then you can do

  matern <- inla.spde2.pcmatern(mesh, ...)
  fit_and_predict <- bru(y ~ 0 + Intercept(1) + Field(geometry, model = matern) + RandomEffect(ID, model = "iid"), data = my_data, family = ...)

The resulting linear predictor & fitted values outputs will have the same order as in "my_data", so you can easily know where the predictions are.
This is _the_ canonical way to handle such models in inlabru.

All that said, there _is_ a way (actually multiple ways) to supply custom matrices in the inlabru model construction.
Where did you get that "In inlabru, there is no direct way to supply the custom projection matrix A."?
If that's being claimed somewhere, I'd like to know, so I can tell them to correct it, as it is not true.

One way is by explicitly multiplying with a matrix in the prediction expression, and another is to use a bm_matrix() mapper for the component.
Those are, however, more advanced options, and you should only use those if you have a special reason for it.

With the mapper approach (I'm using fm_basis() here instead of inla.spde.make.A(), as the latter is effectively deprecated for inlabru models):

  fit_and_predict <- bru(y ~ 0 + Intercept(1) +
    Field(fm_basis(mesh, geometry), model = matern, mapper = bm_matrix(fm_dof(mesh))) +
    RandomEffect(ID, model = "iid"), data = my_data,family = ...)

This is essentially what the default mapper (bm_fmesher()) for the spde models does; it calls the fm_basis() function that returns the A-matrix.
By computing the matrix based on the data supplied to bru() it will work also when calling predict(), whereas pre-computing the matrix would prevent normal operation of predict().

Explicit matrix multiplication:

  A_precomputed <- fm_basis(mesh, my_data$geometry)
  fit_and_predict <- bru(~ 0 + Intercept(1) +
    Field_basis_weights(seq_len(fm_dof(mesh)), model = matern, mapper = bm_index(fm_dof(mesh))) +
    RandomEffect(ID, model = "iid"),
    bru_obs(y ~ Intercept + A_precomputed %*% Field_basis_weights + RandomEffect, family = ..., data = my_data, allow_combine = TRUE)
)

Note: In the current inlabru version, this last version will be slower, as it (currently) forces inlabru to consider that the general R expression given as predictor expression in bru_obs() might be non-linear.

Finn

--
You received this message because you are subscribed to the Google Groups "R-inla discussion group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to r-inla-discussion...@googlegroups.com.
To view this discussion, visit https://groups.google.com/d/msgid/r-inla-discussion-group/8908d7a9-49c2-469b-809e-9d9b902c9c96n%40googlegroups.com.


--
Finn Lindgren
email: finn.l...@gmail.com
Reply all
Reply to author
Forward
0 new messages