【问题标题】:Custom Link function works for GLM but not mgcv GAM自定义链接功能适用于 GLM,但不适用于 mgcv GAM
【发布时间】:2017-02-09 02:59:01
【问题描述】:

如果答案很明显,我很抱歉,但我花了很长时间尝试在 mgcv.gam 中使用自定义链接函数

总之,

  • 我想使用来自包psyphy的修改后的概率链接(我想使用psyphy.probit_2asym,我称之为custom_link
  • 我可以用这个链接创建一个 {stats}family 对象,并在 glm 的 'family' 参数中使用它。

    m <- glm(y~x, family=binomial(link=custom_link), ... )

  • 当用作 {mgcv}gam 的参数时它不起作用

    m <- gam(y~s(x), family=binomial(link=custom_link), ... )

    我收到错误Error in fix.family.link.family(family) : link not recognised

我不明白这个错误的原因,如果我指定标准link=probit,glm 和 gam 都可以工作。

所以我的问题可以概括为:

这个适用于 glm 但不适用于 gam 的自定义链接中缺少什么?

如果你能告诉我我应该做什么,请提前感谢。


链接功能

probit.2asym <- function(g, lam) {
    if ((g < 0 ) || (g > 1))
        stop("g must in (0, 1)")
    if ((lam < 0) || (lam > 1))
        stop("lam outside (0, 1)")
    linkfun <- function(mu) {
        mu <- pmin(mu, 1 - (lam + .Machine$double.eps))
        mu <- pmax(mu, g + .Machine$double.eps)
        qnorm((mu - g)/(1 - g - lam))
        }
    linkinv <- function(eta) {
        g + (1 - g - lam) * 
         pnorm(eta)
        }
    mu.eta <- function(eta) {
        (1 - g - lam) * dnorm(eta)      }
    valideta <- function(eta) TRUE
    link <- paste("probit.2asym(", g, ", ", lam, ")", sep = "")
    structure(list(linkfun = linkfun, linkinv = linkinv, 
    mu.eta = mu.eta, valideta = valideta, name = link), 
    class = "link-glm")
}

【问题讨论】:

  • 非常感谢您编辑问题。

标签: r regression glm gam mgcv


【解决方案1】:

您可能知道,glm 采用迭代重新加权最小二乘 拟合迭代。 gam 的早期版本通过拟合 迭代惩罚重加权最小二乘 扩展了这一点,这是由 gam.fit 函数完成的。这在某些情况下称为性能迭代

自 2008 年(或者更早一点)以来,gam.fit3 基于所谓的外部迭代 已将gam.fit 替换为gam 默认值。这种变化确实需要一些额外的家庭信息,关于这些你可以阅读?fix.family.link

两次迭代的主要区别在于系数迭代beta和平滑参数迭代lambda是否嵌套。

  • 性能迭代采用嵌套方式,每次更新beta,都会执行一次lambda迭代;
  • 外部迭代将这 2 个迭代完全分开,其中对于 beta 的每次更新,lambda 的迭代都会进行到最后直到收敛。

显然外迭代更稳定,收敛失败的可能性更小。

gam 有一个参数optimizer。默认取optimizer = c("outer", "newton"),即外迭代的牛顿法;但如果设置optimizer = "perf",则需要性能迭代。


所以,经过上述概述,我们有两个选择:

  • 仍然使用外部迭代,但扩展您自定义的链接功能;
  • 使用性能迭代与glm保持一致。

我很懒,所以会展示第二种方法(实际上我对第一种方法没有太大信心)


可重现的示例

你没有提供一个可重现的例子,所以我准备了一个如下。

set.seed(0)
x <- sort(runif(500, 0, 1))    ## covariates (sorted to make plotting easier)
eta <- -4 + 3 * x * exp(x) - 2 * log(x) * sqrt(x)   ## true linear predictor
p <- binomial(link = "logit")$linkinv(eta)    ## true probability (response)
y <- rbinom(500, 1, p)    ## binary observations

table(y)    ## a quick check that data are not skewed
#  0   1 
#271 229 

我会取你打算使用的函数probit.2asymg = 0.1lam = 0.1

probit2 <- probit.2asym(0.1, 0.1)

par(mfrow = c(1,3))

## fit a glm with logit link
glm_logit <- glm(y ~ x, family = binomial(link = "logit"))
plot(x, eta, type = "l", main = "glm with logit link")
lines(x, glm_logit$linear.predictors, col = 2)

## glm with probit.2asym
glm_probit2 <- glm(y ~ x, family = binomial(link = probit2))
plot(x, eta, type = "l", main = "glm with probit2")
lines(x, glm_probit2$linear.predictors, col = 2)

## gam with probit.2aysm
library(mgcv)
gam_probit2 <- gam(y ~ s(x, bs = 'cr', k = 3), family = binomial(link = probit2),
                   optimizer = "perf")
plot(x, eta, type = "l", main = "gam with probit2")
lines(x, gam_probit2$linear.predictors, col = 2)

我使用自然三次样条基crs(x),至于单变量平滑,不需要薄板样条的默认设置。我还设置了一个小的基础维度k = 3(对于三次样条不能更小),因为我的玩具数据接近线性并且不需要大的基础维度。更重要的是,这似乎可以防止我的玩具数据集的性能迭代收敛失败。

【讨论】:

  • 非常感谢您的回答。使用性能优化器是这个问题的简单答案。我将研究这个我不知道是新标准的外部迭代(显然在阅读 simon wood r 书时跳过了这一部分)。现在,我将凭经验探索这个不再默认的优化器是否会损害我的问题的拟合性能和收敛性,并将在此处报告我的发现。我可能会扩展和共享链接以使用外部迭代。
猜你喜欢
  • 2017-11-25
  • 2021-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 2017-01-04
相关资源
最近更新 更多