Получение доверительных интервалов по прогнозу от caret :: train - PullRequest
1 голос
/ 19 сентября 2019

Я пытаюсь выяснить, как получить доверительные интервалы из линейной модели caret :: train.

Моя первая попытка состояла в том, чтобы просто выполнить прогнозирование с обычными аргументами доверительных интервалов lm:

m <- caret::train(mpg ~ poly(hp,2), data=mtcars, method="lm")
predict(m, newdata=mtcars, interval="confidence", level=0.95)

Но похоже, что объект, возвращенный из caret :: train, не реализовал это.

Моя вторая попытка состояла в том, чтобы извлечь finalModel и предсказать это:

m <- caret::train(mpg ~ poly(hp,2), data=mtcars, method="lm")
fm <- m$finalModel
predict(fm, newdata=mtcars, interval="confidence", level=0.95)

Но я получаю ошибку

Error in eval(predvars, data, env) : object 'poly(hp, 2)1' not found

Копая глубже, кажется, что конечная модель имеет какое-то странное представление для формулы и скорее ищет столбец 'poly (hp, 2) 1' в моих новых данныхчем оценка формулы.M $ finalModel выглядит следующим образом:

Call:
lm(formula = .outcome ~ ., data = dat)

Coefficients:
   (Intercept)  `poly(hp, 2)1`  `poly(hp, 2)2`  
         20.09          -26.05           13.15

Я должен добавить, что я не просто использую lm, потому что я использую каретку, чтобы соответствовать модели через перекрестную проверку.

Как я могу получить доверительные интервалы из линейной модели, подходящей через caret :: train?

1 Ответ

1 голос
/ 19 сентября 2019

Отказ от ответственности:

Это ужасный ответ, или, возможно, пакет caret имеет ужасную реализацию этой конкретной проблемы.В любом случае это кажется подходящим для открытия вопроса или пожелания на их github , если он еще не существует (либо желание более разнообразных predict функций, либо исправление именования, используемого в object$finalModel)

Проблема (возникшая во втором испытании) проистекает из того, как пакет caret внутренне обрабатывает различные процедуры подбора, в основном ограничивая функцию предсказания для целей очистки и стандартизации.

Проблема:

Проблема двоякая.

  1. predict.train не допускает интервалы прогнозирования / доверительной вероятности
  2. finalModel, содержащийся в выходных данных train(...), содержит формулу, которая имеет необычный формат.

Кажется, две проблемы связаны с форматированием train и использованием в predict.train.Сосредоточившись сначала на последней проблеме, это становится очевидным, если взглянуть на выходные данные из

formula(m$finalModel)
#`.outcome ~ `poly(hp, 2)1` + `poly(hp, 2)2`)

. Очевидно, что некоторое форматирование выполняется во время работы train, поскольку ожидаемый результат будет mpg ~ poly(hp, 2), в то время как выход имеетрасширил RHS (и добавил кавычки / теги) и изменил LHS.Поэтому было бы неплохо либо исправить формулу, либо использовать формулу.

Анализ того, как пакет caret использует это в функции predict.train, показывает фрагмент кода ниже для * 1037.* input

predict.formula
#output
--more code
if (!is.null(newdata)) {
    if (inherits(object, "train.formula")) {
        newdata <- as.data.frame(newdata)
        rn <- row.names(newdata)
        Terms <- delete.response(object$terms)
        m <- model.frame(Terms, newdata, na.action = na.action, 
            xlev = object$xlevels)
        if (!is.null(cl <- attr(Terms, "dataClasses"))) 
            .checkMFClasses(cl, m)
        keep <- match(row.names(m), rn)
        newdata <- model.matrix(Terms, m, contrasts = object$contrasts)
        xint <- match("(Intercept)", colnames(newdata), 
            nomatch = 0)
        if (xint > 0) 
            newdata <- newdata[, -xint, drop = FALSE]
    }
}
--more code
    out <- predictionFunction(method = object$modelInfo, 
                modelFit = object$finalModel, newdata = newdata, 
                preProc = object$preProcess)

Для менее опытных пользователей R мы в основном видим, что model.matrix создается с нуля без использования вывода formula(m$finalModel) (мы можем использовать это!), ипозже вызывается некоторая функция для прогнозирования на основе m$finalModel.Изучение predictionFunction из того же пакета показывает, что эта функция просто вызывает m$modelInfo$predict(m$finalModel, newdata) (для нашего примера)

И наконец, просмотр m$modelInfo$predict показывает приведенный ниже фрагмент кода

m$modelInfo$predict
#output
function(modelFit, newdata, submodels = NULL) {
                    if(!is.data.frame(newdata)) 
                        newdata <- as.data.frame(newdata)
                    predict(modelFit, newdata)
                  }

Примечаниечто modelFit = m$finalModel и newdata сделаны с выводом выше.Также Обратите внимание , что вызов predict не позволяет указать interval = "confidence", что является причиной первой проблемы.

Устранение проблемы (сортировка):

Существует множество способов решения этой проблемы.Одним из них является использование lm(...) вместо train(...).Другой способ - использовать внутреннюю часть функции для создания объекта данных, который соответствует странной спецификации модели, поэтому мы можем использовать predict(m$finalModel, newdata = newdata, interval = "confidence") так, как ожидается.

Я выбрал последнее.

caretNewdata <- caretTrainNewdata(m, mtcars)
preds <- predict(m$finalModel, caretNewdata, interval = "confidence")
head(preds, 3)
#output
                         fit      lwr      upr
Mazda RX4           22.03708 20.74297 23.33119
Mazda RX4 Wag       22.03708 20.74297 23.33119
Datsun 710          24.21108 22.77257 25.64960

Функция представлена ​​ниже.для всезнайки я в основном извлек процесс строительства model.matrix из predict.train, predictionFunction и m$modelInfo$predict.Я не буду обещать, что эта функция работает для общего использования каждой модели caret, но это место для начала.

caretTrainNewdata Функция:

caretTrainNewdata <- function(object, newdata, na.action = na.omit){
    if (!is.null(object$modelInfo$library)) 
        for (i in object$modelInfo$library) do.call("requireNamespaceQuietStop", 
                                                    list(package = i))
    if (!is.null(newdata)) {
        if (inherits(object, "train.formula")) {
            newdata <- as.data.frame(newdata)
            rn <- row.names(newdata)
            Terms <- delete.response(object$terms)
            m <- model.frame(Terms, newdata, na.action = na.action, 
                             xlev = object$xlevels)
            if (!is.null(cl <- attr(Terms, "dataClasses"))) 
                .checkMFClasses(cl, m)
            keep <- match(row.names(m), rn)
            newdata <- model.matrix(Terms, m, contrasts = object$contrasts)
            xint <- match("(Intercept)", colnames(newdata), 
                          nomatch = 0)
            if (xint > 0) 
                newdata <- newdata[, -xint, drop = FALSE]
        }
    }
    else if (object$control$method != "oob") {
        if (!is.null(object$trainingData)) {
            if (object$method == "pam") {
                newdata <- object$finalModel$xData
            }
            else {
                newdata <- object$trainingData
                newdata$.outcome <- NULL
                if ("train.formula" %in% class(object) && 
                    any(unlist(lapply(newdata, is.factor)))) {
                    newdata <- model.matrix(~., data = newdata)[, 
                                                                -1]
                    newdata <- as.data.frame(newdata)
                }
            }
        }
        else stop("please specify data via newdata")
    } else
        stop("please specify data data via newdata")
    if ("xNames" %in% names(object$finalModel) & is.null(object$preProcess$method$pca) & 
        is.null(object$preProcess$method$ica)) 
        newdata <- newdata[, colnames(newdata) %in% object$finalModel$xNames, 
                           drop = FALSE]
    if(!is.null(object$preProcess))
       newdata <- predict(preProc, newdata)
    if(!is.data.frame(newdata) && 
      !is.null(object$modelInfo$predict) && 
      any(grepl("as.data.frame", as.character(body(object$modelInfo$predict)))))
           newdata <- as.data.frame(newdata)
    newdata
}
...