tests/testthat/test-smooths.R

# https://github.com/pbs-assess/sdmTMB/issues/60
test_that("smoothers with 'bs = re' error", {
  skip_on_cran()
  expect_error({
    m <- sdmTMB(
      density ~ s(depth_scaled, bs = "re"),
      data = pcod_2011,
      mesh = pcod_mesh_2011, spatial = "off"
    )
  }, regexp = "re")
})

test_that("A model with 2 s() splines works", {
  skip_on_cran()
  d <- subset(pcod, year >= 2000 & density > 0)
  pcod_spde <- make_mesh(d, c("X", "Y"), cutoff = 30)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled) + s(year, k = 5),
    mesh = pcod_spde, spatial = "off", spatiotemporal = "off"
  )
  expect_equal(ncol(m$tmb_data$X_ij[[1]]), 1L)
  expect_equal(length(m$tmb_data$Zs), 2L)
  # head(m$tmb_data$Zs[[1]])
  # head(m$tmb_data$Zs[[2]])
  expect_equal(ncol(m$tmb_data$Xs), 2L)
  expect_equal(m$tmb_data$b_smooth_start, c(0L, 8L))
  # exp(as.list(m$sd_report, "Estimate")$ln_smooth_sigma)
  # as.list(m$sd_report, "Estimate")$b_smooth
  expect_equal(sum(is.na(as.list(m$sd_report, "Std. Error")$b_smooth)), 0L)
  p <- predict(m, newdata = NULL)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled) + s(year, k = 5), data = d)
  p_mgcv <- predict(m_mgcv, newdata = d)
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.999)

  pnd <- predict(m, newdata = d[1:8,])
  expect_equal(p$est[1:8], pnd$est, tolerance = 0.001)

  set.seed(23402)
  .s <- sample(seq_len(nrow(d)), 200L)
  pnd_mgcv <- predict(m_mgcv, newdata = d[.s, ])
  pnd <- predict(m, newdata = d[.s, ])
  expect_gt(cor(pnd_mgcv, pnd$est), 0.999)
})

test_that("A model with t2() works", {
  skip_on_cran()
  set.seed(2938)
  dat <- mgcv::gamSim(1, n = 400, dist = "normal", scale = 2)

  dat$f <- NULL
  dat$f0 <- NULL
  dat$f1 <- NULL
  dat$f2 <- NULL
  dat$f3 <- NULL
  dat$x3 <- NULL
  dat$observed <- dat$y
  dat$y <- NULL
  dat$.x0 <- dat$x0
  dat$.x1 <- dat$x1
  dat$x0 <- NULL
  dat$x1 <- NULL
  dat$x2 <- NULL

  m_mgcv <- mgcv::gam(observed ~ t2(.x0, .x1, k = 9),
                      data = dat,
                      method = "REML"
  )
  p_mgcv <- predict(m_mgcv)
  m <- sdmTMB(observed ~ t2(.x0, .x1, k = 9),
              data = dat,
              spatial = 'off'
  )
  p <- predict(m, newdata = NULL)
  expect_error(pnd <- predict(m, newdata = dat), "t2")
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.9999)
  expect_equal(as.numeric(p$est), as.numeric(p_mgcv), tolerance = 0.001)
})

test_that("A model with dimensions specified in t2() works", {
  skip_on_cran()
  set.seed(2938)
  dat <- mgcv::gamSim(1, n = 400, dist = "normal", scale = 1)

  dat$f <- NULL
  dat$f0 <- NULL
  dat$f1 <- NULL
  dat$f2 <- NULL
  dat$f3 <- NULL
  #dat$x3 <- NULL
  dat$observed <- dat$y
  dat$y <- NULL
  dat$.x0 <- dat$x0
  dat$.x1 <- dat$x1
  dat$.x2 <- dat$x2
  #dat$x0 <- NULL
  #dat$x1 <- NULL
  #dat$x2 <- NULL

  m_mgcv <- mgcv::gam(observed ~ t2(x0, x1, x2, d = c(2,1), k = c(5,3)),
                      data = dat,
                      method = "REML"
  )
  p_mgcv <- predict(m_mgcv)
  m <- sdmTMB(observed ~ t2(x0, x1, x2, d = c(2,1), k = c(5,3)),
              data = dat,
              spatial = 'off'
  )
  p <- predict(m, newdata = NULL)
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.9999)
  expect_equal(as.numeric(p$est), as.numeric(p_mgcv), tolerance = 0.001)
})


test_that("A model with by in spline (and s(x, y)) works", {
  skip_on_cran()
  set.seed(19203)
  # examples from ?mgcv::gam.models
  # continuous by example:
  dat <- mgcv::gamSim(3, n = 800)
  m_mgcv <- mgcv::gam(y ~ s(x2, by = x1), data = dat)
  p_mgcv <- predict(m_mgcv)
  dat$X <- runif(nrow(dat))
  dat$Y <- runif(nrow(dat))
  spde <- make_mesh(dat, c("X", "Y"), cutoff = 0.1)
  m <- sdmTMB(y ~ s(x2, by = x1),
              data = dat,
              mesh = spde,spatial = "off"
  )
  p <- predict(m, newdata = NULL)
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.9999)
  pnd <- predict(m, newdata = dat)
  plot(p$est, pnd$est)
  expect_gt(cor(p$est, pnd$est), 0.9999)

  # s(x, y)
  m_mgcv <- mgcv::gam(y ~ s(x2, x1), data = dat)
  p_mgcv <- predict(m_mgcv)
  m <- sdmTMB(y ~ s(x2, x1),
              data = dat,
              mesh = spde, spatial = "off"
  )
  p <- predict(m, newdata = NULL)
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.999)
  p2 <- predict(m, newdata = dat)
  plot(p2$est, p$est)
  expect_gt(cor(p2$est, p$est), 0.999)

  pnd <- predict(m, newdata = dat)
  plot(p$est, pnd$est)
  expect_gt(cor(p$est, pnd$est), 0.9999)


  # Factor `by' variable example (with a spurious covariate x0)
  set.seed(1)
  dat <- mgcv::gamSim(4)
  m_mgcv <- mgcv::gam(y ~ fac + s(x2, by = fac) + s(x0), data = dat)
  p_mgcv <- predict(m_mgcv)
  dat$X <- runif(nrow(dat))
  dat$Y <- runif(nrow(dat))
  spde <- make_mesh(dat, c("X", "Y"), cutoff = 0.1)
  m <- sdmTMB(y ~ fac + s(x2, by = fac) + s(x0),
              data = dat,
              mesh = spde, spatial = "off"
  )
  p <- predict(m, newdata = NULL)
  plot(p$est, p_mgcv)
  abline(a = 0, b = 1)
  expect_gt(cor(p$est, p_mgcv), 0.9999)
  pnd <- predict(m, newdata = dat)
  plot(p$est, pnd$est)
  expect_gt(cor(p$est, pnd$est), 0.9999)

  set.seed(291823)
  .s <- sample(seq_len(nrow(dat)), 200L)
  pnd <- predict(m, newdata = dat[.s,])
  expect_equal(p$est[.s], pnd$est, tolerance = 0.001)
})


test_that("Formula removal of s and t2 works", {
  expect_identical(remove_s_and_t2(y ~ x + s(z)), y ~ x)
  expect_identical(remove_s_and_t2(y ~ s(x) + s(z)), y ~ 1)
  expect_identical(remove_s_and_t2(y ~ s(x) + t2(z)), y ~ 1)
  expect_identical(remove_s_and_t2(y ~ ignore(x) + t2(z)), y ~ ignore(x))
})

test_that("Smooth plotting works", {
  skip_on_cran()
  d <- subset(pcod, year >= 2000 & density > 0)
  pcod_spde <- make_mesh(d, c("X", "Y"), cutoff = 30)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled) + s(year, k = 5),
    mesh = pcod_spde, spatial = "off", spatiotemporal = "off"
  )

  plot_smooth(m)
  plot_smooth(m, level = 0.4)
  plot_smooth(m, select = 2)
  plot_smooth(m, ggplot = TRUE)
  plot_smooth(m, ggplot = TRUE, rug = FALSE)
  plot_smooth(m, rug = FALSE)
  plot_smooth(m, n = 3)
  out <- plot_smooth(m, return_data = TRUE)
  expect_equal(class(out), "data.frame")

  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled) + year,
    mesh = pcod_spde, spatial = "off", spatiotemporal = "off",
    control = sdmTMBcontrol(newton_loops = 1)
  )

  plot_smooth(m, select = 1)
  expect_error(plot_smooth(m, select = 2), regexp = "select")

  suppressMessages({
    m <- sdmTMB(
      data = d, time = "year",
      formula = log(density) ~ s(depth_scaled),
      mesh = pcod_spde, spatial = "on", spatiotemporal = "off"
    )
  })
  plot_smooth(m)

  # with a factor
  suppressMessages({
    m1 <- sdmTMB(
      data = d, time = "year",
      formula = log(density) ~ 0 + s(depth_scaled) + as.factor(year),
      mesh = pcod_spde, spatial = "on", spatiotemporal = "off"
    )
  })
  plot_smooth(m)
})

test_that("print works with s(X, Y)", {
  skip_on_cran()

  d <- subset(pcod_2011, density > 0)
  m <- sdmTMB(log(density) ~ s(X, Y, k = 5), data = d, spatial = "off")
  print(m)
  expect_output(summary(m), regexp = "sXY_1")
  expect_output(summary(m), regexp = "sXY_2")

  m2 <- sdmTMB(log(density) ~ s(X) + s(Y), data = d, spatial = "off")
  summary(m2)

  m3 <- sdmTMB(log(density) ~ s(X) + s(Y) + s(depth, year), data = d, spatial = "off")
  summary(m3)
  expect_output(summary(m3), regexp = "sX")
  expect_output(summary(m3), regexp = "sY")
  expect_output(summary(m3), regexp = "sdepthyear_1")
  expect_output(summary(m3), regexp = "sdepthyear_2")
  # m <- brms::brm(log(density) ~ s(X) + s(Y) + s(depth, year), data = d, chains = 1, iter = 800)
  # m
})

test_that("smoothers with 'bs = cc' work", {
  skip_on_cran()
  m <- sdmTMB(
    density ~ s(depth_scaled, bs = "cc"),
    data = pcod_2011,
    mesh = pcod_mesh_2011, spatial = "off"
  )
  p <- predict(m)
  print(m)

  m1 <- mgcv::gam(
    density ~ s(depth_scaled, bs = "cc"),
    data = pcod_2011
  )
  p1 <- predict(m1)

  plot(p$est, p1)
  abline(0, 1)
  expect_gt(cor(p$est, p1), 0.999)
})


test_that("smoothers with 'bs = cc' work with knots specified", {
  skip_on_cran()
  m <- sdmTMB(
    density ~ s(depth_scaled, bs = "cc", k = 5), knots = list(depth_scaled = c(-3, -1, 0, 1, 3)),
    data = pcod_2011, spatial = "off"
  )
  p <- predict(m, newdata = pcod_2011)
  print(m)

  m1 <- mgcv::gam(
    density ~ s(depth_scaled, bs = "cc", k = 5), knots = list(depth_scaled = c(-3, -1, 0, 1, 3)),
    data = pcod_2011
  )
  p1 <- predict(m1)

  plot(p$est, p1)
  abline(0, 1)
  expect_gt(cor(p$est, p1), 0.999)
})

test_that("smoothers with 'bs = cr' work", {
  skip_on_cran()
  m <- sdmTMB(
    density ~ s(depth_scaled, bs = "cr"),
    data = pcod_2011,
    mesh = pcod_mesh_2011, spatial = "off"
  )
  p <- predict(m)
  print(m)

  m1 <- mgcv::gam(
    density ~ s(depth_scaled, bs = "cr"),
    data = pcod_2011
  )
  p1 <- predict(m1)

  plot(p$est, p1)
  abline(0, 1)
  expect_gt(cor(p$est, p1), 0.999)
})

test_that("prediction with smoothers error helpfully if missing variable", {
  skip_on_cran()
  suppressWarnings({
    m <- sdmTMB(
      density ~ s(year, k = 3) + s(depth_scaled),
      data = pcod_2011,
      mesh = pcod_mesh_2011, spatial = "off"
    )
  })
  nd <- data.frame(year = 2007)
  expect_error({
    p <- predict(m, newdata = nd, re_form = NA, se_fit = TRUE)
  }, regexp = "depth_scaled")

  nd <- data.frame(aaa = 2007)
  expect_error({
    p <- predict(m, newdata = nd, re_form = NA, se_fit = TRUE)
  }, regexp = "year")
})

test_that("A model with s(x, bs = 'cs') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "cs"),
    spatial = "off"
  )
  print(m)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, bs = "cs"), data = d)
  p <- predict(m)
  p2 <- predict(m_mgcv)
  # plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.999)
})

test_that("A model with s(x, bs = 'cr') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "cr"),
    spatial = "off"
  )
  print(m)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, bs = "cr"), data = d)
  p <- predict(m)
  p2 <- predict(m_mgcv)
  # plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.999)
})

test_that("A model with s(x, bs = 'ds') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "ds"),
    spatial = "off"
  )
  print(m)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, bs = "ds"), data = d)
  p <- predict(m)
  p2 <- predict(m_mgcv)
  # plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.999)
})

test_that("A model with s(x, bs = 'ps') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "ps"),
    spatial = "off"
  )
  print(m)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, bs = "ps"), data = d, method = "REML")
  p <- predict(m)
  p2 <- predict(m_mgcv)
  plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.999)
})

test_that("A model with s(x, bs = 're') errors", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  expect_error(m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "re"),
    spatial = "off"
  ))
})

test_that("A model with s(x, bs = 'gp') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, bs = "gp"),
    spatial = "off"
  )
  print(m)
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, bs = "gp"), data = d, method = "REML")
  p <- predict(m)
  p2 <- predict(m_mgcv)
  plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.999)
})

test_that("A model with s(x, bs = 'fs') works", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  d$yearf <- as.factor(d$year)
  m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, by = year, bs = "fs"),
    spatial = "off", control = sdmTMBcontrol(newton_loops = 1)
  )
  # FIXME:
  suppressWarnings(print(m))
  m_mgcv <- mgcv::gam(log(density) ~ s(depth_scaled, by = year, bs = "fs"), data = d, method = "REML")
  p <- predict(m)
  p2 <- predict(m_mgcv)
  # plot(p$est, p2)
  expect_gt(stats::cor(p$est, p2), 0.995)
})

test_that("An fx=TRUE smoother errors out", {
  skip_on_cran()
  d <- subset(pcod, density > 0)
  expect_error(m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, fx = TRUE),
    spatial = "off"
  ))
  expect_error(m <- sdmTMB(
    data = d,
    formula = log(density) ~ s(depth_scaled, fx = T),
    spatial = "off"
  ))
})
pbs-assess/sdmTMB documentation built on May 17, 2024, 11:31 a.m.