Прогнозирование отклика по новым кривым с использованием пакета fda в R

10

В основном, все, что я хочу сделать, это предсказать скалярный ответ, используя некоторые кривые. Я дошел до регрессии (используя fRegress из пакета fda), но не знаю, как применить результаты к НОВОМУ набору кривых (для прогнозирования).

У меня N = 536 кривых и 536 скалярных ответов. Вот что я сделал до сих пор:

  • Я создал основу для кривых.
  • Я создал объект fdPar, чтобы ввести штраф
  • Я создал объект fd, используя smooth.basis, чтобы сгладить кривые с выбранным штрафом на указанной основе.
  • Я запустил регрессию с помощью fRegress (), регрессирующей кривые скалярного отклика.

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

ура

DCL
источник
Даже описание того, как вычислять прогнозы вручную из базовых, сглаженных (fd) объектов и регрессионных оценок из fRegress (), было бы очень полезно.
DCL
Просто проверяю: вы пробовали использовать с predict.fRegressпомощью newdataопции (из руководства ФДА здесь )?
У меня есть, просто я не совсем уверен, каким должен быть класс или формат «новых данных». Он не будет принимать объект fd или fdSmooth, которые являются сглаженными кривыми, из которых я хочу предсказать. И это не позволит мне вводить необработанные аргументы и ковариантные значения.
DCL
1
Помню, у меня была похожая проблема около года назад, когда я играл с fdaпакетом. Я писал ответ, который включал получение прогнозов вручную, но большая часть его была потеряна из-за того, что она не была сохранена. Если кто-то еще не побьет меня, я должен найти решение для вас через пару дней.

Ответы:

14

Меня не волнует fdaиспользование Inception- подобных списочно-структурных объектов-списков-в-списках, но мой ответ будет зависеть от системы, созданной создателями пакетов.

Я думаю, поучительно сначала подумать о том, что именно мы делаем. Исходя из вашего описания того, что вы сделали до сих пор, я верю, что вы делаете это (дайте мне знать, если я что-то неправильно понял). Я буду продолжать использовать нотацию и, из-за отсутствия реальных данных, пример из анализа функциональных данных Рамсея и Сильвермана и анализа функциональных данных Рамзея, Хукера и Грейвса с помощью R и MATLAB (некоторые из следующих уравнений и кода были сняты напрямую из этих книг).

Мы моделируем скалярный отклик через функциональную линейную модель, т.е.

yi=β0+0TXi(s)β(s)ds+ϵi

Разложим в некотором базисе. Мы используем, скажем, K базисных функций. Так,βK

β(s)=k=1Kbkθk(s)

В матричной записи это .β(s)=θ(s)b

Мы также расширяем ковариатные функции в некотором базисе (скажем, базисных функций). Так,L

Xi(s)=k=1Lcikψk(s)

Опять же, в матричной записи это .X(s)=Cψ(s)

И, таким образом, если мы позволим , наша модель может быть выражена какJ=ψ(s)θ(s)ds

y=β0+CJb .

И если мы допустим и , наша модель будетξ = [ β 0Z=[1CJ]ξзнак равно[β0б']'

y=Zξ

И это выглядит гораздо более знакомым для нас.

Теперь я вижу, что вы добавляете некоторую регуляризацию. fdaПакет работает с шероховатостью штрафами формы

пзнак равноλ[Lβ(s)]2ds

для некоторого линейного дифференциального оператора . Теперь можно показать (подробности здесь опущены - это действительно не сложно показать), что если мы определим штрафную матрицу какRLр

рзнак равноλ(0000р1000рК)

где в терминах базисного расширения , тогда мы минимизируем штрафную сумму квадратов:β iряβя

(Y-Zξ)'(Y-Zξ)+λξ'рξ ,

и поэтому наша проблема - всего лишь регрессия гребня с решением:

ξ^знак равно(Z'Z+λр)-1Z'Y .

Я прошел через вышесказанное, потому что, (1) я думаю, что важно, чтобы мы понимали, что мы делаем, и (2) некоторые из вышеперечисленных необходимы для понимания части кода, который я буду использовать позже. На коду ...

Вот пример данных с кодом R Я использую канадский набор данных о погоде, представленный в fdaпакете. Мы будем моделировать логарифм годовых осадков для ряда метеостанций с помощью функциональной линейной модели и будем использовать температурные профили (температуры регистрировались один раз в день в течение 365 дней) для каждой станции в качестве функциональных ковариат. Мы будем действовать так же, как вы описываете в вашей ситуации. Данные были зарегистрированы на 35 станциях. Я разделю набор данных на 34 станции, которые будут использоваться в качестве моих данных, и последнюю станцию, которая будет моим "новым" набором данных.

Я продолжаю через код R и комментарии (я предполагаю, что вы достаточно знакомы с fdaпакетом, так что ничто из следующего не является слишком удивительным - если это не так, пожалуйста, дайте мне знать):

# pick out data and 'new data'
dailydat <- daily$precav[,2:35]
dailytemp <- daily$tempav[,2:35]
dailydatNew <- daily$precav[,1]
dailytempNew <- daily$tempav[,1]

# set up response variable
annualprec <- log10(apply(dailydat,2,sum))

# create basis objects for and smooth covariate functions
tempbasis <- create.fourier.basis(c(0,365),65)
tempSmooth <- smooth.basis(day.5,dailytemp,tempbasis)
tempfd <- tempSmooth$fd

# create design matrix object
templist <- vector("list",2)
templist[[1]] <- rep(1,34)
templist[[2]] <- tempfd

# create constant basis (for intercept) and
# fourier basis objects for remaining betas
conbasis <- create.constant.basis(c(0,365))
betabasis <- create.fourier.basis(c(0,365),35)
betalist <- vector("list",2)
betalist[[1]] <- conbasis
betalist[[2]] <- betabasis

# set roughness penalty for betas 
Lcoef <- c(0,(2*pi/365)^2,0)
harmaccelLfd <- vec2Lfd(Lcoef, c(0,365))
lambda <- 10^12.5
betafdPar <- fdPar(betabasis, harmaccelLfd, lambda)
betalist[[2]] <- betafdPar

# regress
annPrecTemp <- fRegress(annualprec, templist, betalist)

Теперь, когда год назад мне впервые рассказали о функциональных данных, я поиграл с этим пакетом. Я также был не в состоянии predict.fRegressдать мне то, что я хотел. Оглядываясь назад, я все еще не знаю, как заставить его вести себя. Итак, нам просто нужно получить прогнозы полу-вручную. Я буду использовать части, которые я вытащил прямо из кода fRegress(). Я снова продолжаю через код и комментарии.

Во-первых, установка:

# create basis objects for and smooth covariate functions for new data
tempSmoothNew <- smooth.basis(day.5,dailytempNew,tempbasis)
tempfdNew <- tempSmoothNew$fd

# create design matrix object for new data
templistNew <- vector("list",2)
templistNew[[1]] <- rep(1,1)
templistNew[[2]] <- tempfdNew

# convert the intercept into an fd object
onebasis <- create.constant.basis(c(0,365))
templistNew[[1]] <- fd(matrix(templistNew[[1]],1,1), onebasis)

Теперь, чтобы получить прогнозы

Y^Nевесзнак равноZNевесξ^

Я просто беру код, который fRegressиспользует для вычисления yhatfdobjи немного его редактировать. fRegressвычисляет yhatfdobjпутем оценки интеграла помощью правила трапеции (с и развернутыми в соответствующих базах). X i β0TИкся(s)β(s)Иксяβ

Как правило, fRegressвычисляет подогнанные значения, просматривая ковариаты, хранящиеся в annPrecTemp$xfdlist. Так что для нашей проблемы, мы заменим этот ковариативный список с соответствующим одным в нашем новом списке ковариата, то есть templistNew. Вот код (идентичный коду fRegressс двумя правками, удалению ненужного кода и добавлению пары комментариев):

# set up yhat matrix (in our case it's 1x1)
yhatmat <- matrix(0,1,1)

# loop through covariates
p <- length(templistNew)
for(j in 1:p){
    xfdj       <- templistNew[[j]]
    xbasis     <- xfdj$basis
    xnbasis    <- xbasis$nbasis
    xrng       <- xbasis$rangeval
    nfine      <- max(501,10*xnbasis+1)
    tfine      <- seq(xrng[1], xrng[2], len=nfine)
    deltat     <- tfine[2]-tfine[1]
    xmat       <- eval.fd(tfine, xfdj)
    betafdParj <- annPrecTemp$betaestlist[[j]]
    betafdj    <- betafdParj$fd
    betamat    <- eval.fd(tfine, betafdj)
    # estimate int(x*beta) via trapezoid rule
    fitj       <- deltat*(crossprod(xmat,betamat) - 
                      0.5*(outer(xmat[1,],betamat[1,]) +
              outer(xmat[nfine,],betamat[nfine,])))
    yhatmat    <- yhatmat + fitj
}

(примечание: если вы посмотрите на этот фрагмент и окружающий код fRegress, вы увидите шаги, которые я описал выше).

Я протестировал код, повторно запустив пример погоды, используя все 35 станций в качестве наших данных, и сравнил вывод из вышеуказанного цикла с annPrecTemp$yhatfdobjи все совпадает. Я также запускал его пару раз, используя разные станции в качестве «новых» данных, и все кажется разумным.

Дайте мне знать, если что-то из перечисленного неясно или что-то работает неправильно. Извините за слишком подробный ответ. Я не мог с собой поделать :) И если вы еще не владеете ими, посмотрите две книги, которые я использовал, чтобы написать этот ответ. Это действительно хорошие книги.


источник
Похоже, это именно то, что мне нужно. Спасибо. Я предполагаю, что мне не придется играть с nfine / tine / deltat, верно? Должен ли я считать, что интеграция происходит достаточно точно?
DCL
Кроме того, я заметил, что вы не штрафовали «новый» ковариат или «старый» ковариат напрямую. Это все сделано с штрафом бета (и количество базовых функций, я думаю). Штраф лямбда применяется к бета-версии. Достигаете ли вы того же эффекта, штрафуя сглаживания перед регрессией? (с тем же значением лямбда)
DCL
1
nfineξββ^ββ
β0
1
Jзнак равно1β0^Y^