Prevedere la risposta da nuove curve usando il pacchetto fda in R


10

Fondamentalmente tutto quello che voglio fare è prevedere una risposta scalare usando alcune curve. Ho ottenuto una regressione (usando fRegress dal pacchetto fda) ma non ho idea di come applicare i risultati a una NUOVA serie di curve (per la previsione).

Ho N = 536 curve e 536 risposte scalari. Ecco cosa ho fatto finora:

  • Ho creato una base per le curve.
  • Ho creato un oggetto fdPar per introdurre una penalità
  • Ho creato l'oggetto fd usando smooth.basis per smussare le curve con la penalità scelta sulla base specificata.
  • Ho eseguito una regressione usando fRegress (), regredendo le curve sulla risposta scalare.

Ora, tutto ciò che mi piacerebbe fare è usare quella regressione per produrre previsioni per un nuovo set di dati che ho. Non riesco a trovare un modo semplice per farlo.

Saluti


Anche una descrizione di come calcolare manualmente le previsioni dalla base, dagli oggetti smussati (fd) e dalle stime di regressione da fRegress () sarebbe molto utile.
dcl

Solo controllo: hai provato a usare predict.fRegressl' newdataopzione (dal manuale di fda qui )?

Sì, è solo che non sono esattamente sicuro di quale classe o formato debbano essere i "newdata". Non accetterà un oggetto fd o fdSmooth che sono le curve levigate da cui desidero prevedere. E non mi permetterà di inserire argomenti grezzi e valori di covariata.
dcl,

1
Ricordo di aver avuto un problema simile circa un anno fa, quando ho giocato con il fdapacchetto. Stavo scrivendo una risposta che prevedeva di ottenere manualmente le previsioni, ma una grande parte di essa è andata persa a causa del mancato salvataggio. Se qualcun altro non mi picchia, dovrei avere una soluzione per te tra un paio di giorni.

Risposte:


14

Non mi interessa fdal'uso delle strutture di oggetti Inception -list-in-list-in-list simili a Inception , ma la mia risposta si atterrà al sistema creato dagli autori dei pacchetti.

Penso che sia istruttivo pensare prima a cosa stiamo facendo esattamente. Sulla base della descrizione di ciò che hai fatto finora, questo è quello che credo tu stia facendo (fammi sapere se ho interpretato male qualcosa). Continuerò a utilizzare la notazione e, a causa della mancanza di dati reali, un esempio di Analisi dei dati funzionali di Ramsay e Silverman e Analisi dei dati funzionali di Ramsay, Hooker e Graves con R e MATLAB (Alcune delle seguenti equazioni e codici vengono sollevati direttamente da questi libri).

Stiamo modellando una risposta scalare tramite un modello lineare funzionale, ad es

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

Espandiamo il in alcune basi. Usiamo, diciamo, le funzioni di baseCosì,βK

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

Nella notazione matriciale, si tratta di .β(s)=θ(s)b

Espandiamo anche le funzioni della covariata anche in alcune basi (diciamo funzioni di base ). Così,L

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

Ancora una volta, in notazione matriciale, si tratta di .X(s)=Cψ(s)

E quindi, se lasciamo , il nostro modello può essere espresso comeJ=ψ(s)θ(s)ds

y=β0+CJb .

E se lasciamo e , il nostro modello èZ=[1CJ]ξ=[β0b]

y=Zξ

E questo ci sembra molto più familiare.

Ora vedo che stai aggiungendo una sorta di regolarizzazione. Il fdapacchetto funziona con penalità di rugosità del modulo

P=λ[Lβ(s)]2ds

per alcune lineare operatore differenziale . Ora può essere mostrato (dettagli lasciati fuori qui - non è davvero difficile dimostrarlo) che se definiamo la matrice di penalità comeLR

R=λ(0000R1000RK)

dove è in termini di espansione base di , quindi minimizziamo la somma dei quadrati penalizzata:Riβi

(yZξ)(yZξ)+λξRξ ,

e quindi il nostro problema è semplicemente una regressione della cresta con la soluzione:

ξ^=(ZZ+λR)1Zy .

Ho esaminato quanto sopra perché, (1) penso sia importante capire cosa stiamo facendo, e (2) alcune delle precedenti sono necessarie per comprendere parte del codice che userò in seguito. Acceso al codice ...

Ecco un esempio di dati con il codice R. Sto usando il set di dati meteorologici canadese fornito nel fdapacchetto. Modelleremo le precipitazioni annue del registro per un certo numero di stazioni meteorologiche tramite un modello lineare funzionale e utilizzeremo i profili di temperatura (le temperature sono state registrate una volta al giorno per 365 giorni) da ciascuna stazione come covariate funzionali. Procederemo in modo simile al modo in cui descrivi la tua situazione. I dati sono stati registrati in 35 stazioni. Suddividerò il set di dati in 34 stazioni, che verranno utilizzate come miei dati, e l'ultima stazione, che sarà il mio "nuovo" set di dati.

Continuo tramite il codice R e i commenti (suppongo che tu abbia abbastanza familiarità con il fdapacchetto in modo tale che nulla di quanto segue sia troppo sorprendente - se non è così, per favore fatemelo sapere):

# 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)

Ora, quando mi è stato insegnato per la prima volta sui dati funzionali circa un anno fa, ho giocato con questo pacchetto. Non sono stato nemmeno in grado di predict.fRegressdarmi quello che volevo. Ripensandoci ora, non so ancora come farlo comportare. Quindi, dovremo solo ottenere le previsioni semi-manualmente. Userò pezzi per cui ho estratto il codice fRegress(). Ancora una volta, continuo tramite codice e commenti.

Innanzitutto, il set-up:

# 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)

Ora per ottenere le previsioni

y^new=Znewξ^

Prendo solo il codice che fRegressusa per calcolarlo yhatfdobje modificarlo leggermente. fRegresscalcola yhatfdobjstimando l'integrale tramite la regola del trapezio (con e espansi nelle rispettive basi). 0TXi(s)β(s)Xiβ

Normalmente, fRegresscalcola i valori adattati eseguendo il ciclo attraverso le covariate memorizzate annPrecTemp$xfdlist. Quindi, per il nostro problema, sostituiamo questo elenco di covariate con quello corrispondente nel nostro nuovo elenco di covariate, ovvero templistNew. Ecco il codice (identico al codice trovato fRegresscon due modifiche, alcune eliminazioni di codice non necessario e un paio di commenti aggiunti):

# 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
}

(nota: se guardi questo pezzo e il codice circostante fRegress, vedrai i passaggi che ho descritto sopra).

Ho testato il codice rieseguendo l'esempio meteorologico usando tutte e 35 le stazioni come dati e confrontando l'output del loop sopra con annPrecTemp$yhatfdobjtutto e tutto corrisponde. L'ho anche eseguito un paio di volte usando diverse stazioni come i miei "nuovi" dati e tutto sembra ragionevole.

Fammi sapere se uno dei precedenti non è chiaro o se qualcosa non funziona correttamente. Ci scusiamo per la risposta eccessivamente dettagliata. Non potevo fare a meno :) E se non li possiedi già, dai un'occhiata ai due libri che ho usato per scrivere questa risposta. Sono davvero dei bei libri.


Sembra che sia esattamente quello di cui ho bisogno. Grazie. Presumo che non dovrò giocare con le cose nfine / tine / deltat giusto? Dovrei supporre che l'integrazione stia facendo abbastanza accuratamente?
dcl,

Inoltre, noto che non hai penalizzato direttamente la "nuova" covariata o le "vecchie" covariate. È tutto fatto penalizzando la beta (e il numero di funzioni di base immagino). La penalità lambda viene applicata alla beta. Ottenete lo stesso effetto penalizzando i lisci prima della regressione? (con lo stesso valore di lambda)
dcl

1
La griglia utilizzata per approssimare l'integrale è abbastanza buona, quindi l'approssimazione dovrebbe essere abbastanza buona. Potresti sempre aumentare nfinee vedere quanto cambia l'integrale ma immagino che non farà molto. Per quanto riguarda la penalizzazione, sì, in questo caso stiamo penalizzando direttamente 's anziché '. Ramsay e Silverman discutono di un altro metodo di penalità che stima senza funzioni di base in cui applichiamo la penalità direttamente a . Entrambi i modi stanno inducendo un vincolo di scorrevolezza sulle funzioni , ma non sono sicuro che otterrai lo "stesso effetto". ξββ^ββ

Ho provato a manipolare il codice per produrre previsioni per più curve, ma non sono sicuro di averlo fatto correttamente. Per cominciare, yhatmat non è costante per tutte le curve dopo la prima iterazione del ciclo ... Questo significa che equivale a ? β0
dcl,

1
@dcl Nel ciclo, quando , sta aggiungendo a (supponendo che il primo elenco nella tua Xlist corrisponda al termine di intercettazione). Puoi aggiungere lo snippet di codice che stai utilizzando alla tua domanda in modo che io possa guardarlo? j=1β0^y^
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.