Here are two ways in which you can use terra::regress.
A single SpatRaster and an index (that is, "x" in y~x is fixed)
library(terra)
set.seed(1)
r <- rast(ncol=10, nrow=10, nlyr=10, vals=runif(1000))
regress(r, 1:nlyr(r))
#class : SpatRaster
#dimensions : 10, 10, 2 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#source(s) : memory
#names : (Intercept), x
#min values : 0.02779796, -0.07366238
#max values : 0.90875803, 0.06692299
And with another SpatRaster (that is, (that is, "x" in y~x is changes by cell)
p <- rast(ncol=10, nrow=10, nlyr=10, vals=runif(1000))
regress(r, p)
#class : SpatRaster
#dimensions : 10, 10, 2 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#source(s) : memory
#names : (Intercept), x
#min values : 0.08374815, -0.7327174
#max values : 0.87454291, 0.6017231
You can achieve the same with lapp and lm (or other regression method) like this
x <- lapp(sds(p, r), \(x, y) {
sapply(1:nrow(x), \(i) {
coefficients(lm(b~a, data=data.frame(a=x[i,], b=y[i,])))
}) |> t()
})
x
#class : SpatRaster
#dimensions : 10, 10, 2 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#source(s) : memory
#names : (Intercept), a
#min values : 0.08374815, -0.7327174
#max values : 0.87454291, 0.6017231
The code is a bit gnarly because lm is not a vectorized function.
It is advisable to check some cells. E.g.,
x[1]
# (Intercept) a
#1 0.6239804 0.06438924
coefficients(lm(y~x, data=data.frame(x=unlist(p[1]), y=unlist(r[1]))))
#(Intercept) x
# 0.62398039 0.06438924