Die fda
Verwendung von Inception- ähnlichen Objektstrukturen für Listen innerhalb von Listen innerhalb von Listen ist mir egal , aber meine Antwort wird sich an das System halten, das die Paketschreiber erstellt haben.
Ich finde es lehrreich, zuerst darüber nachzudenken, was wir genau tun. Basierend auf Ihrer Beschreibung dessen, was Sie bisher getan haben, glaube ich, dass Sie dies tun (lassen Sie mich wissen, wenn ich etwas falsch interpretiert habe). Ich werde weiterhin die Notation verwenden und aufgrund fehlender realer Daten ein Beispiel aus der Funktionsdatenanalyse von Ramsay und Silverman sowie die Funktionsdatenanalyse von Ramsay, Hooker und Graves mit R und MATLAB (Einige der folgenden Gleichungen und Codes werden direkt aufgehoben aus diesen Büchern).
Wir modellieren eine skalare Antwort über ein funktionales lineares Modell, dh
yi=β0+∫T0Xi(s)β(s)ds+ϵi
Wir erweitern die in gewisser Weise. Wir verwenden beispielsweise Basisfunktionen. Damit,βK
β(s)=∑k=1Kbkθk(s)
In der Matrixnotation ist dies .β(s)=θ′(s)b
Wir erweitern auch die kovariaten Funktionen in einigen Basen (sagen wir Basisfunktionen). Damit,L
Xi(s)=∑k=1Lcikψk(s)
In der Matrixnotation ist dies wiederum .X(s)=Cψ(s)
Wenn wir also , kann unser Modell ausgedrückt werden alsJ=∫ψ(s)θ′(s)ds
y=β0+CJb .
Und wenn wir und , ist unser ModellZ=[1CJ]ξ=[β0b′]′
y=Zξ
Und das kommt uns viel vertrauter vor.
Jetzt sehe ich, dass Sie eine Art Regularisierung hinzufügen. Das fda
Paket arbeitet mit Rauheitsstrafen des Formulars
P=λ∫[Lβ(s)]2ds
für einige linearen Differentialoperator . Jetzt kann gezeigt werden (Details hier weggelassen - es ist wirklich nicht schwer, dies zu zeigen), dass, wenn wir die Strafmatrix als definierenLR
R=λ⎛⎝⎜⎜⎜⎜⎜00⋮00R1⋮0⋯⋯⋱⋯00⋮RK⎞⎠⎟⎟⎟⎟⎟
wo in Bezug auf die Basis Ausbau der ist , dann minimieren wir die bestraft Summe der Quadrate:Riβi
(y−Zξ)′(y−Zξ)+λξ′Rξ ,
und so ist unser Problem nur eine Gratregression mit Lösung:
ξ^=(Z′Z+λR)−1Z′y .
Ich habe das oben Gesagte durchgearbeitet, weil (1) ich denke, es ist wichtig, dass wir verstehen, was wir tun, und (2) einige der oben genannten Dinge notwendig sind, um einen Teil des Codes zu verstehen, den ich später verwenden werde. Weiter zum Code ...
Hier ist ein Datenbeispiel mit R-Code. Ich verwende den im fda
Paket enthaltenen kanadischen Wetterdatensatz . Wir modellieren den logarithmischen Jahresniederschlag für eine Reihe von Wetterstationen über ein funktionelles lineares Modell und verwenden Temperaturprofile (die Temperaturen wurden 365 Tage lang einmal täglich aufgezeichnet) von jeder Station als funktionale Kovariaten. Wir werden ähnlich vorgehen, wie Sie es in Ihrer Situation beschreiben. Die Daten wurden an 35 Stationen aufgezeichnet. Ich werde den Datensatz in 34 Stationen aufteilen, die als meine Daten verwendet werden, und die letzte Station, die mein "neuer" Datensatz sein wird.
Ich fahre mit R-Code und Kommentaren fort (ich gehe davon aus, dass Sie mit dem fda
Paket so vertraut sind, dass nichts im Folgenden zu überraschend ist - wenn dies nicht der Fall ist, lassen Sie es mich bitte wissen):
# 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)
Als ich vor ungefähr einem Jahr zum ersten Mal über funktionale Daten unterrichtet wurde, habe ich mit diesem Paket herumgespielt. Ich konnte predict.fRegress
mir auch nicht geben, was ich wollte. Wenn ich jetzt zurückblicke, weiß ich immer noch nicht, wie ich es dazu bringen soll, sich zu verhalten. Wir müssen die Vorhersagen also nur halb manuell abrufen. Ich werde Teile verwenden, für die ich direkt aus dem Code gezogen habe fRegress()
. Wieder gehe ich über Code und Kommentare weiter.
Zunächst das Setup:
# 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)
Nun zu den Vorhersagen
y^new=Znewξ^
Ich nehme nur den Code, fRegress
mit dem er berechnet yhatfdobj
und leicht bearbeitet wird. fRegress
berechnet yhatfdobj
durch Schätzen des Integrals über die Trapezregel (wobei und in ihren jeweiligen Basen erweitert sind). ∫T0Xi(s)β(s)Xiβ
Normalerweise fRegress
werden die angepassten Werte berechnet, indem die in gespeicherten Kovariaten durchlaufen werden annPrecTemp$xfdlist
. Für unser Problem ersetzen wir diese Kovariatenliste durch die entsprechende in unserer neuen Kovariatenliste, d templistNew
. H. Hier ist der Code (identisch mit dem Code, der fRegress
mit zwei Änderungen, einigen Löschungen von nicht benötigtem Code und einigen Kommentaren hinzugefügt wurde):
# 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
}
(Hinweis: Wenn Sie sich diesen Block und den umgebenden Code in fRegress
ansehen, werden die oben beschriebenen Schritte angezeigt.)
Ich habe den Code getestet, indem ich das Wetterbeispiel mit allen 35 Stationen als Daten erneut ausgeführt und die Ausgabe der obigen Schleife mit verglichen habe annPrecTemp$yhatfdobj
und alles übereinstimmt. Ich habe es auch ein paar Mal mit verschiedenen Stationen als "neue" Daten ausgeführt und alles scheint vernünftig.
Lassen Sie mich wissen, wenn einer der oben genannten Punkte unklar ist oder wenn etwas nicht richtig funktioniert. Entschuldigen Sie die zu detaillierte Antwort. Ich konnte mir nicht helfen :) Und wenn Sie sie noch nicht besitzen, lesen Sie die beiden Bücher, mit denen ich diese Antwort geschrieben habe. Das sind wirklich gute Bücher.