-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathfRegress.double.R
284 lines (243 loc) · 9.96 KB
/
fRegress.double.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
fRegress.double <- function(y, xfdlist, betalist, wt=NULL,
y2cMap=NULL, SigmaE=NULL, returnMatrix=FALSE, ...)
{
# FREGRESS.DOUBLE Fits a scalar dependent variable using the concurrent
# functional regression model using inner products
# of functional covariates and functional regression
# functions.
#
# Arguments:
# Y ... A numeric vector that is the dependent variable.
# It is converted to yvec below.
# XFDLIST ... a list object of length p with each list
# containing an object for an independent variable.
# the object may be:
# a functional data object or
# a vector
# if XFDLIST is a functional data object or a vector,
# it is converted to a list of length 1.
# BETALIST ... a list object of length p with each list
# containing a functional parameter object for
# the corresponding regression function. If any of
# these objects is a functional data object, it is
# converted to the default functional parameter object.
# if BETALIST is a functional parameter object
# it is converted to a list of length 1.
# WT ... a vector of nonnegative weights for observations
# Y2CMAP ... the matrix mapping from the vector of observed values
# to the coefficients for the dependent variable.
# This is output by function SMOOTH_BASIS. If this is
# supplied, confidence limits are computed, otherwise not.
# SIGMAE ... Estimate of the covariances among the residuals. This
# can only be estimated after a preliminary analysis
# with .
# RETURNMATRIX ... If False, a matrix in sparse storage model can be returned
# from a call to function BsplineS. See this function for
# enabling this option.
#
# Returns LIST ... A list containing seven members with names:
# yvec ... numeric vector dependent variable
# xfdlist ... list of objects that are dependent variables
# betalist ... list of objects that are regression functions
# betaestlist ... list of estimated regression functions
# yhatfdobj ... functional data object containing fitted function
# Cmatinv ... inverse of the coefficient matrix, needed for
# function .STDERR that computes standard errors
# wt ... weights for observations
# df ... degrees of freedom for fit
# This list object is converted to a class with the name ""
# function predict. is an example of a method that can be called simply
# as predict(List). In this call List can be any object of the
# "".
# Last modified 29 January 2024 by Jim Ramsay
# check Y and compute sample size N
if (!inherits(y, "numeric")) stop("Argument y is not a numeric vector.")
# yvec is the dependent variable, which is a numeric vector
yvec <- y
# ----------------------------------------------------------------
# yvec is scalar or multivariate
# ----------------------------------------------------------------
#. check the terms
arglist <- fRegressArgCheck(yvec, xfdlist, betalist, wt)
#. extract the terms and rename them
yvec <- arglist$yfd
xfdlist <- arglist$xfdlist
betalist <- arglist$betalist
wt <- arglist$wt
ymat <- as.matrix(yvec) # yvec converted to matrix object ymat
N <- dim(ymat)[1] # the size of ymat
p <- length(xfdlist) # the number of regression terms
#. work through independent terms to format them
Zmat <- NULL
Rmat <- NULL
pjvec <- rep(0,p)
ncoef <- 0
xrangeval <- matrix(0,p,2)
brangeval <- matrix(0,p,2)
for (j in 1:p) {
# check the xfdj term
xfdj <- xfdlist[[j]]
if (!inherits(xfdj, "fd")) {
stop(paste("Independent variable",j,"is not of class fd."))
}
xcoefj <- xfdj$coefs
xbasisj <- xfdj$basis
xrangeval[j,] <- xbasisj$rangeval
betafdParj <- betalist[[j]]
bbasisj <- betafdParj$fd$basis
nbbasisj <- bbasisj$nbasis
brangeval[j,] <- bbasisj$rangeval
pjvec[j] <- nbbasisj
Jpsithetaj <- inprod(xbasisj,bbasisj)
Zmat <- cbind(Zmat,crossprod(xcoefj,Jpsithetaj))
if (betafdParj$estimate) {
lambdaj <- betafdParj$lambda
if (lambdaj > 0) {
Lfdj <- betafdParj$Lfd
Rmatj <- lambdaj*eval.penalty(bbasisj,Lfdj)
} else {
Rmatj <- matrix(0,nbbasisj,nbbasisj)
}
# accumulate b-coefficients into a single vector
if (ncoef > 0) {
zeromat <- matrix(0,ncoef,nbbasisj)
Rmat <- rbind(cbind(Rmat, zeromat),
cbind(t(zeromat), Rmatj))
ncoef <- ncoef + nbbasisj
} else {
Rmat <- Rmatj
ncoef <- ncoef + nbbasisj
}
}
}
# -----------------------------------------------------------
# solve the linear equations for the solution
# -----------------------------------------------------------
# solve for coefficients defining BETA
if (any(wt != 1)) {
rtwt <- sqrt(wt)
Zmatwt <- Zmat*rtwt
ymatwt <- ymat*rtwt
Cmat <- t(Zmatwt) %*% Zmatwt + Rmat
Dmat <- t(Zmatwt) %*% ymatwt
} else {
Cmat <- t(Zmat) %*% Zmat + Rmat
Dmat <- t(Zmat) %*% ymat
}
eigchk(Cmat)
Cmatinv <- solve(Cmat)
betacoef <- Cmatinv %*% Dmat
# df <- sum(diag(Zmat %*% Cmatinv %*% t(Zmat)))
hatvals = diag(Zmat %*% Cmatinv %*% t(Zmat))
df <- sum(hatvals)
# -----------------------------------------------------------
# set up fdPar object for BETAESTFDPAR
# -----------------------------------------------------------
betaestlist <- betalist
mj2 <- 0
for (j in 1:p) {
betafdParj <- betalist[[j]]
betafdj <- betafdParj$fd
ncoefj <- betafdj$basis$nbasis
mj1 <- mj2 + 1
mj2 <- mj2 + ncoefj
indexj <- mj1:mj2
betacoefj <- betacoef[indexj]
betaestfdj <- betafdj
betaestfdj$coefs <- as.matrix(betacoefj)
betaestfdParj <- betafdParj
betaestfdParj$fd <- betaestfdj
betaestlist[[j]] <- betaestfdParj
}
# -----------------------------------------------------------
# set up fd object for predicted values
# -----------------------------------------------------------
yhatmat <- matrix(0,N,1)
for (j in 1:p) {
xfdj <- xfdlist[[j]]
if (inherits(xfdj, "fd")) {
xbasisj <- xfdj$basis
xnbasisj <- xbasisj$nbasis
xrngj <- xbasisj$rangeval
nfinej <- max(501,10*xnbasisj+1)
tfinej <- seq(xrngj[1], xrngj[2], len=nfinej)
deltatj <- tfinej[2]-tfinej[1]
xmatj <- eval.fd(tfinej, xfdj, 0, returnMatrix)
betafdParj <- betaestlist[[j]]
betafdj <- betafdParj$fd
betamatj <- eval.fd(tfinej, betafdj, 0, returnMatrix)
fitj <- deltatj*(crossprod(xmatj,betamatj) -
0.5*(outer(xmatj[1, ],betamatj[1, ]) +
outer(xmatj[nfinej,],betamatj[nfinej,])))
yhatmat <- yhatmat + fitj
} else{
betaestfdParj <- betaestlist[[j]]
betavecj <- betaestfdParj$fd$coefs
yhatmat <- yhatmat + xfdj %*% t(betavecj)
}
}
yhatfdobj <- yhatmat
# Calculate OCV and GCV scores
OCV = sum( (ymat-yhatmat)^2/(1-hatvals)^2 )
GCV = sum( (ymat-yhatmat)^2 )/( (sum(1-hatvals))^2 )
# -----------------------------------------------------------------------
# Compute pointwise standard errors of regression coefficients
# if both y2cMap and SigmaE are supplied.
# -----------------------------------------------------------------------
if (!(is.null(y2cMap) || is.null(SigmaE))) {
# check dimensions of y2cMap and SigmaE
y2cdim <- dim(y2cMap)
if (y2cdim[2] != dim(SigmaE)[1]) stop(
"Dimensions of Y2CMAP not correct.")
# compute linear mapping c2bMap takinging coefficients for
# response into coefficients for regression functions
c2bMap <- Cmatinv %*% t(Zmat)
y2bmap <- c2bMap
bvar <- y2bmap %*% as.matrix(SigmaE) %*% t(y2bmap)
betastderrlist <- vector("list",p)
mj2 <- 0
for (j in 1:p) {
betafdParj <- betalist[[j]]
betabasisj <- betafdParj$fd$basis
ncoefj <- betabasisj$nbasis
mj1 <- mj2 + 1
mj2 <- mj2 + ncoefj
indexj <- mj1:mj2
bvarj <- bvar[indexj,indexj]
betarng <- betabasisj$rangeval
nfine <- max(c(501,10*ncoefj+1))
tfine <- seq(betarng[1], betarng[2], len=nfine)
bbasismat <- eval.basis(tfine, betabasisj, 0, returnMatrix)
bstderrj <- sqrt(diag(bbasismat %*% bvarj %*% t(bbasismat)))
bstderrfdj <- smooth.basis(tfine, bstderrj, betabasisj)$fd
betastderrlist[[j]] <- bstderrfdj
}
} else {
betastderrlist = NULL
bvar = NULL
c2bMap = NULL
}
# -----------------------------------------------------------------------
# Set up output list object
# -----------------------------------------------------------------------
fRegressList <-
list(yvec = yvec,
xfdlist = xfdlist,
betalist = betalist,
betaestlist = betaestlist,
yhatfdobj = yhatfdobj,
Cmat = Cmat,
Dmat = Dmat,
Cmatinv = Cmatinv,
wt = wt,
df = df,
GCV = GCV,
OCV = OCV,
y2cMap = y2cMap,
SigmaE = SigmaE,
betastderrlist = betastderrlist,
bvar = bvar,
c2bMap = c2bMap)
class(fRegressList) <- "fRegress"
return(fRegressList)
}