Non mi interessa fda
l'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+∫T0Xi(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 fda
pacchetto 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=λ⎛⎝⎜⎜⎜⎜⎜00⋮00R1⋮0⋯⋯⋱⋯00⋮RK⎞⎠⎟⎟⎟⎟⎟
dove è in termini di espansione base di , quindi minimizziamo la somma dei quadrati penalizzata:Riβi
(y−Zξ)′(y−Zξ)+λξ′Rξ ,
e quindi il nostro problema è semplicemente una regressione della cresta con la soluzione:
ξ^=(Z′Z+λR)−1Z′y .
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 fda
pacchetto. 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 fda
pacchetto 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.fRegress
darmi 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 fRegress
usa per calcolarlo yhatfdobj
e modificarlo leggermente. fRegress
calcola yhatfdobj
stimando l'integrale tramite la regola del trapezio (con e espansi nelle rispettive basi). ∫T0Xi(s)β(s)Xiβ
Normalmente, fRegress
calcola 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 fRegress
con 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$yhatfdobj
tutto 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.