Get function from matrix akima :: interp ()

Using the interp function (Akima package) it is possible to draw a surface corresponding to the 2D interpolation of the dataset, see example below (from the documentation on request):

library(rgl)
data(akima)
# data visualisation
rgl.spheres(akima$x,akima$z , akima$y,0.5,color="red")
rgl.bbox()
# bivariate linear interpolation
# interp:
akima.li <- interp(akima$x, akima$y, akima$z, 
                   xo=seq(min(akima$x), max(akima$x), length = 100),
                   yo=seq(min(akima$y), max(akima$y), length = 100))
# interp surface:
rgl.surface(akima.li$x,akima.li$y,akima.li$z,color="green",alpha=c(0.5))

      

However, the output is only a list describing a set of points, not a general function.

Question: is there any method to get the function z = f (x, y) that matches the previously obtained surface? I know it works using interp (akima $ x, akima $ y, akima $ z, xo = A, yo = B), but it is very slow.

In two dimensions, approxfun () would have done the job, but I couldn't find an equivalent to interpolate multiple parameters.

+3


source to share


1 answer


If you need linear interpolation so that the surface intersects all points, you cannot interpolate with a function z = f(x,y)

, except that the dataset has been modeled with this type of function.
If you are looking for a function z=f(x,y)

that fits your set of points, you will need to build a model with GLM or GAM, for example. However, this causes the surface to not intersect all point data and there will be some residuals.

As I use to work with spatial datasets, which means x and y coordinates with observation z, I will give you some hints this way.

First, I prepare a dataset for interpolation:

library(rgl)
library(akima)
library(dplyr)
library(tidyr)

data(akima)
data.akima <- as.data.frame(akima)
# data visualisation
rgl.spheres(akima$x, akima$z , akima$y,0.5,color="red")
rgl.bbox()

# Dataset for interpolation
seq_x <- seq(min(akima$x) - 1, max(akima$x) + 1, length.out = 20)
seq_y <- seq(min(akima$y) - 1, max(akima$y) + 1, length.out = 20)
data.pred <- dplyr::full_join(data.frame(x = seq_x, by = 1),
                              data.frame(y = seq_y, by = 1)) %>%
  dplyr::select(-by)

      

Then I use your akima interpolation function:

# bivariate linear interpolation
# interp:
akima.li <- interp(akima$x, akima$y, akima$z, 
                   xo=seq_x,
                   yo=seq_y)

# interp surface:
rgl.surface(akima.li$x,akima.li$y,akima.li$z,color="green",alpha=c(0.5))
rgl.spheres(akima$x, akima$z , akima$y,0.5,color="red")
rgl.bbox()

      

Using rasters

Now, if you want to get interpolated information at some specific points, you can reuse the function interp

or decide to work with a rasterized image. Using rasters, you can increase the resolution and obtain spatial position data.



# Using rasters 
library(raster)
r.pred <- raster(akima.li$z, xmn = min(seq_x), xmx = max(seq_x),
       ymn = min(seq_y), ymx = max(seq_y))
plot(r.pred)

## Further bilinear interpolations
## Double raster resolution
r.pred.2 <- disaggregate(r.pred, fact = 2, method = "bilinear")
plot(r.pred.2)

      

Spatial interpolation (inverse distance interpolation or kriging)

When we think about spatial interpolation, I think about kriging first. This will smooth your surface so it won't intersect all data points.

# Spatial inverse distance interpolation
library(sp)
library(gstat)
# Transform data as spatial objects
data.akima.sp <- data.akima
coordinates(data.akima.sp) <- ~x+y
data.pred.sp <- data.pred
coordinates(data.pred.sp) <- ~x+y
# Inverse distance interpolation
# idp is set to 2 as weight for interpolation is :
# w = 1/dist^idp
# nmax is set to 3, so that only the 3 closest points are used for interpolation
pred.idw <- idw(
  formula = as.formula("z~1"),
  locations = data.akima.sp, 
  newdata = data.pred.sp,
  idp = 2,
  nmax = 3)

data.spread.idw <- data.pred %>%
  select(-pred) %>%
  mutate(idw = pred.idw$var1.pred) %>%
  tidyr::spread(key = y, value = idw) %>% 
  dplyr::select(-x)

surface3d(seq_x, seq_y, as.matrix(data.spread.idw), col = "green")
rgl.spheres(akima$x, akima$y , akima$z, 0.5, color = "red")
rgl.bbox()

      

Interpolate with gam or glm

However, if you want to find a type formula z = f(x,y)

, you should use GLM or GAM with a high degree of freedom depending on what you hope to see. Another benefit is that you can add covariates other than x and y. The model must be equipped with an x ​​/ y interaction.
Here's an example with simple GAM smooth:

# Approximation with a gam model
library(mgcv)
gam1 <- gam(z ~ te(x, y), data = data.akima)
summary(gam1)

plot(gam1)
data.pred$pred <- predict(gam1, data.pred)
data.spread <- tidyr::spread(data.pred, key = y, value = pred) %>% 
  dplyr::select(-x)

surface3d(seq_x, seq_y, as.matrix(data.spread), col = "blue")
rgl.spheres(akima$x, akima$y , akima$z, 0.5, color = "red")
rgl.bbox()

      

Is this answer going in the right direction for you?

+4


source







All Articles