Je ne me soucie pas de fda
l'utilisation des structures d'objets list-within-list-within-list de type Inception , mais ma réponse respectera le système que les rédacteurs de packages ont créé.
Je pense qu'il est instructif de penser d'abord à ce que nous faisons exactement. Sur la base de votre description de ce que vous avez fait jusqu'à présent, c'est ce que je crois que vous faites (faites-moi savoir si j'ai mal interprété quelque chose). Je continuerai à utiliser la notation et, en raison du manque de données réelles, un exemple de l' analyse fonctionnelle des données de Ramsay et Silverman et l' analyse fonctionnelle des données de Ramsay, Hooker et Graves avec R et MATLAB (certaines des équations et du code suivants sont directement extraits de ces livres).
Nous modélisons une réponse scalaire via un modèle linéaire fonctionnel, c'est-à-dire
yi=β0+∫T0Xi(s)β(s)ds+ϵi
Nous développons la dans une certaine base. Nous utilisons, disons, fonctions de base. Alors,KβK
β(s)=∑k=1Kbkθk(s)
En notation matricielle, il s'agit de .β(s)=θ′(s)b
Nous développons également les fonctions de covariation sur une certaine base également (disons les fonctions de base ). Alors,L
Xi(s)=∑k=1Lcikψk(s)
Encore une fois, en notation matricielle, il s'agit de .X(s)=Cψ(s)
Et donc, si nous laissons , notre modèle peut être exprimé commeJ=∫ψ(s)θ′(s)ds
y=β0+CJb .
Et si nous laissons et , notre modèle estZ=[1CJ]ξ=[β0b′]′
y=Zξ
Et cela nous semble beaucoup plus familier.
Maintenant, je vois que vous ajoutez une sorte de régularisation. Le fda
package fonctionne avec des pénalités de rugosité du formulaire
P=λ∫[Lβ(s)]2ds
pour un certain opérateur différentiel linéaire . Maintenant, il peut être montré (détails laissés ici - ce n'est vraiment pas difficile à montrer) que si nous définissons la matrice de pénalité commeLR
R=λ⎛⎝⎜⎜⎜⎜⎜00⋮00R1⋮0⋯⋯⋱⋯00⋮RK⎞⎠⎟⎟⎟⎟⎟
où est en termes d'expansion de base de , alors nous minimisons la somme pénalisée des carrés:Riβi
(y−Zξ)′(y−Zξ)+λξ′Rξ ,
et donc notre problème est simplement une régression de crête avec solution:
ξ^=(Z′Z+λR)−1Z′y .
J'ai parcouru ce qui précède parce que, (1) je pense qu'il est important que nous comprenions ce que nous faisons, et (2) une partie de ce qui précède est nécessaire pour comprendre une partie du code que j'utiliserai plus tard. Passons au code ...
Voici un exemple de données avec le code R. J'utilise l'ensemble de données météorologiques canadiennes fourni dans le fda
package. Nous modéliserons les précipitations annuelles logarithmiques pour un certain nombre de stations météorologiques via un modèle linéaire fonctionnel et nous utiliserons les profils de température (les températures ont été enregistrées une fois par jour pendant 365 jours) de chaque station comme covariables fonctionnelles. Nous procéderons de la même manière que vous décrivez dans votre situation. Les données ont été enregistrées dans 35 stations. Je vais diviser l'ensemble de données en 34 stations, qui seront utilisées comme mes données, et la dernière station, qui sera mon "nouveau" ensemble de données.
Je continue via le code R et les commentaires (je suppose que vous êtes assez familier avec le fda
package pour que rien de ce qui suit n'est trop surprenant - si ce n'est pas le cas, faites-le moi savoir):
# 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)
Maintenant, quand j'ai appris pour la première fois les données fonctionnelles il y a environ un an, j'ai joué avec ce package. Je n'ai pas non plus pu me predict.fRegress
donner ce que je voulais. En y repensant maintenant, je ne sais toujours pas comment le faire se comporter. Donc, nous devrons simplement obtenir les prédictions semi-manuellement. Je vais utiliser des morceaux que j'ai extraits du code fRegress()
. Encore une fois, je continue via le code et les commentaires.
Tout d'abord, la configuration:
# 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)
Maintenant pour obtenir les prédictions
y^new=Znewξ^
Je prends juste le code qui l' fRegress
utilise pour le calculer yhatfdobj
et le modifier légèrement. fRegress
calcule yhatfdobj
en estimant l'intégrale via la règle trapézoïdale (avec et étendus dans leurs bases respectives). ∫T0Xi(s)β(s)Xiβ
Normalement, fRegress
calcule les valeurs ajustées en parcourant les covariables stockées dans annPrecTemp$xfdlist
. Donc, pour notre problème, nous remplaçons cette liste de covariables par celle correspondante dans notre nouvelle liste de covariables, c'est-à-dire templistNew
. Voici le code (identique au code trouvé fRegress
avec deux modifications, quelques suppressions de code inutile et quelques commentaires ajoutés):
# 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
}
(Remarque: si vous regardez ce morceau et le code qui l'entoure fRegress
, vous verrez les étapes que j'ai décrites ci-dessus).
J'ai testé le code en réexécutant l'exemple météo en utilisant les 35 stations comme données et j'ai comparé la sortie de la boucle ci-dessus à annPrecTemp$yhatfdobj
et tout correspond. Je l'ai également exécuté plusieurs fois en utilisant différentes stations comme mes "nouvelles" données et tout semble raisonnable.
Faites-moi savoir si l'un des éléments ci-dessus n'est pas clair ou si quelque chose ne fonctionne pas correctement. Désolé pour la réponse trop détaillée. Je ne pouvais pas m'en empêcher :) Et si vous ne les possédez pas déjà, consultez les deux livres que j'ai utilisés pour rédiger cette réponse. Ce sont de très bons livres.