Пакет Caret - GAM с перекрестной проверкой как с гладкими, так и с линейными предикторами

Я хотел бы перекрестно проверить модель GAM, используя каретку. Моя модель GAM имеет бинарную переменную результата, изотропное сглаживание пар координат широты и долготы, а затем линейные предикторы. Типичный синтаксис при использовании mgcv:

gam1 <- gam( y ~ s(lat , long) + x1 + x2, family = binomial(logit) )

Я не совсем уверен, как указать эту модель, используя функцию поезда в каретке. Это мой синтаксис более или менее:

cv <- train(y ~ lat + long + x1 + x2, 
            data = data, 
            method = "gam", 
            family = "binomial", 
            trControl = trainControl(method = "LOOCV", number=1, repeats=), 
            tuneGrid = data.frame(method = "GCV.Cp", select = FALSE))

Проблема в том, что я хочу, чтобы широта и долгота были сглажены, а x1 и x2 рассматривались как линейные.

Спасибо!


person Paul Lantos    schedule 15.01.2017    source источник
comment
Согласен с @李哲源ZheyuanLi, но разве caret::train не принимает регрессионные или сглаживающие сплайн-функции в аргументе формулы?   -  person IRTFM    schedule 15.01.2017
comment
Я не вижу никаких трудностей с использованием сплайнов или полиномиальных функций в аргументе формулы для train, когда method="glm".   -  person IRTFM    schedule 15.01.2017


Ответы (1)


Очень интересно посмотреть, как кто-то использует mgcv вне mgcv. После небольшого исследования я здесь, чтобы расстроить вас: использование mgcv с caret — плохая идея, по крайней мере, при текущей поддержке caret.

Позвольте мне задать вам несколько основных вопросов, если вы используете caret:

  1. Как указать количество узлов, а также базисный класс сплайна для гладкой функции?
  2. Как вы можете указать функцию 2D-сглаживания?
  3. Как вы можете указать сплайн тензорного произведения с помощью te или ti?
  4. Как вы можете настроить параметры сглаживания?

Если вы хотите узнать, что caret::train делает с method = "gam", посмотрите его программу настройки:

getModelInfo(model = "gam", regex = FALSE)$gam$fit

function(x, y, wts, param, lev, last, classProbs, ...) { 
            dat <- if(is.data.frame(x)) x else as.data.frame(x)
            modForm <- caret:::smootherFormula(x)
            if(is.factor(y)) {
              dat$.outcome <- ifelse(y == lev[1], 0, 1)
              dist <- binomial()
            } else {
              dat$.outcome <- y
              dist <- gaussian()
            }
            modelArgs <- list(formula = modForm,
                              data = dat,
                              select = param$select, 
                              method = as.character(param$method))
            ## Intercept family if passed in
            theDots <- list(...)
            if(!any(names(theDots) == "family")) modelArgs$family <- dist
            modelArgs <- c(modelArgs, theDots)                 
            out <- do.call(getFromNamespace("gam", "mgcv"), modelArgs)
            out    
            }

Видите строку modForm <- caret:::smootherFormula(x)? Эта строка является ключевой, в то время как другие строки представляют собой просто рутинную конструкцию вызова модели. Итак, давайте проверим, какую формулу GAM строит caret:

caret:::smootherFormula

function (data, smoother = "s", cut = 10, df = 0, span = 0.5, 
    degree = 1, y = ".outcome") 
{
    nzv <- nearZeroVar(data)
    if (length(nzv) > 0) 
        data <- data[, -nzv, drop = FALSE]
    numValues <- sort(apply(data, 2, function(x) length(unique(x))))
    prefix <- rep("", ncol(data))
    suffix <- rep("", ncol(data))
    prefix[numValues > cut] <- paste(smoother, "(", sep = "")
    if (smoother == "s") {
        suffix[numValues > cut] <- if (df == 0) 
            ")"
        else paste(", df=", df, ")", sep = "")
    }
    if (smoother == "lo") {
        suffix[numValues > cut] <- paste(", span=", span, ",degree=", 
            degree, ")", sep = "")
    }
    if (smoother == "rcs") {
        suffix[numValues > cut] <- ")"
    }
    rhs <- paste(prefix, names(numValues), suffix, sep = "")
    rhs <- paste(rhs, collapse = "+")
    form <- as.formula(paste(y, rhs, sep = "~"))
    form
}

Короче говоря, он создает аддитивное одномерное сглаживание. Это классическая форма, когда GAM была впервые предложена.

В связи с этим вы теряете значительную часть контроля над mgcv, как указано выше.

Чтобы убедиться в этом, позвольте мне построить пример, аналогичный вашему случаю:

set.seed(0)
dat <- gamSim(eg = 2, scale = 0.2)$data[1:3]
dat$a <- runif(400)
dat$b <- runif(400)
dat$y <- with(dat, y + 0.3 * a - 0.7 * b)

#            y         x         z          a         b
#1 -0.30258559 0.8966972 0.1478457 0.07721866 0.3871130
#2 -0.59518832 0.2655087 0.6588776 0.13853856 0.8718050
#3 -0.06978648 0.3721239 0.1850700 0.04752457 0.9671970
#4 -0.17002059 0.5728534 0.9543781 0.03391887 0.8669163
#5  0.55452069 0.9082078 0.8978485 0.91608902 0.4377153
#6 -0.17763650 0.2016819 0.9436971 0.84020039 0.1919378

Поэтому мы стремимся соответствовать модели: y ~ s(x, z) + a + b. Данные y являются гауссовыми, но это не имеет значения; это не влияет на то, как caret работает с mgcv.

cv <- train(y ~ x + z + a + b, data = dat, method = "gam", family = "gaussian",
            trControl = trainControl(method = "LOOCV", number=1, repeats=1), 
            tuneGrid = data.frame(method = "GCV.Cp", select = FALSE))

Вы можете извлечь окончательную модель:

fit <- cv[[11]]

Так какую формулу он использует?

fit$formula
#.outcome ~ s(x) + s(z) + s(a) + s(b)

Видеть? Помимо того, что он является «аддитивным, одномерным», он также оставляет все mgcv::s по умолчанию: по умолчанию bs = "tp", по умолчанию k = 10 и т. д.

person Zheyuan Li    schedule 15.01.2017
comment
Спасибо, все хорошие моменты. Да, если я хотел сравнить адаптивность с tp и te smooths, я не понимаю, как это сделать в каретке. Поэтому я полагаю, что должен быть способ жестко запрограммировать перекрестную проверку, но это выходит за рамки моих навыков. Может ли кто-нибудь указать код, где я могу это сделать? Спасибо - person Paul Lantos; 16.01.2017