BiFuncLib 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. BiFuncLib-0.0.2/BiFuncLib/AuxFunc.py +34 -0
  2. BiFuncLib-0.0.2/BiFuncLib/BiclustResult.py +12 -0
  3. BiFuncLib-0.0.2/BiFuncLib/BsplineFunc.py +449 -0
  4. BiFuncLib-0.0.2/BiFuncLib/FDPlot.py +619 -0
  5. BiFuncLib-0.0.2/BiFuncLib/__init__.py +30 -0
  6. BiFuncLib-0.0.2/BiFuncLib/bcheatmap.py +269 -0
  7. BiFuncLib-0.0.2/BiFuncLib/bimax_biclus.py +84 -0
  8. BiFuncLib-0.0.2/BiFuncLib/cc_bifunc.py +254 -0
  9. BiFuncLib-0.0.2/BiFuncLib/cc_main_func.py +543 -0
  10. BiFuncLib-0.0.2/BiFuncLib/cvx_biclus.py +62 -0
  11. BiFuncLib-0.0.2/BiFuncLib/cvx_main_func.py +642 -0
  12. BiFuncLib-0.0.2/BiFuncLib/fem_bifunc.py +65 -0
  13. BiFuncLib-0.0.2/BiFuncLib/fem_main_func.py +281 -0
  14. BiFuncLib-0.0.2/BiFuncLib/lbm_bifunc.py +62 -0
  15. BiFuncLib-0.0.2/BiFuncLib/lbm_main_func.py +509 -0
  16. BiFuncLib-0.0.2/BiFuncLib/local_bifunc.py +42 -0
  17. BiFuncLib-0.0.2/BiFuncLib/local_main_func.py +434 -0
  18. BiFuncLib-0.0.2/BiFuncLib/pf_bifunc.py +157 -0
  19. BiFuncLib-0.0.2/BiFuncLib/pf_main_func.py +227 -0
  20. BiFuncLib-0.0.2/BiFuncLib/sas_bifunc.py +229 -0
  21. BiFuncLib-0.0.2/BiFuncLib/sas_main_func.py +604 -0
  22. BiFuncLib-0.0.2/BiFuncLib/simulation_data.py +470 -0
  23. BiFuncLib-0.0.2/BiFuncLib/sparse_bifunc.py +13 -0
  24. BiFuncLib-0.0.2/BiFuncLib/sparse_main_func.py +141 -0
  25. BiFuncLib-0.0.2/BiFuncLib/ssvd_biclus.py +18 -0
  26. BiFuncLib-0.0.2/BiFuncLib/ssvd_main_func.py +733 -0
  27. BiFuncLib-0.0.2/BiFuncLib.egg-info/PKG-INFO +16 -0
  28. BiFuncLib-0.0.2/BiFuncLib.egg-info/SOURCES.txt +34 -0
  29. BiFuncLib-0.0.2/BiFuncLib.egg-info/dependency_links.txt +1 -0
  30. BiFuncLib-0.0.2/BiFuncLib.egg-info/requires.txt +9 -0
  31. BiFuncLib-0.0.2/BiFuncLib.egg-info/top_level.txt +1 -0
  32. BiFuncLib-0.0.2/LICENSE.txt +21 -0
  33. BiFuncLib-0.0.2/PKG-INFO +16 -0
  34. BiFuncLib-0.0.2/README.md +2 -0
  35. BiFuncLib-0.0.2/setup.cfg +4 -0
  36. BiFuncLib-0.0.2/setup.py +34 -0
@@ -0,0 +1,34 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import itertools
4
+ from scipy.sparse import lil_matrix
5
+ import matplotlib.pyplot as plt
6
+
7
+
8
+ class AuxFunc:
9
+ def __init__(self, n, m = None, x = None, V = None):
10
+ self.n = n
11
+ self.m = m if m is not None else None
12
+ self.x = np.array(x) if x is not None else None
13
+ self.V = np.array(V) if V is not None else None
14
+
15
+ # Generate break sequence in spline expansion
16
+ def knots_eq(self):
17
+ return np.r_[self.x.min(), np.linspace(self.x.min(), self.x.max(), self.m+2)[1:-1], self.x.max()]
18
+
19
+ # Construct the adjacency matrix
20
+ def create_adjacency(self, plot = True):
21
+ differences = np.linalg.norm(self.V, axis=0)
22
+ connected_ix = np.where(differences == 0)[0]
23
+ index = pd.DataFrame(itertools.combinations(range(self.n), 2))
24
+ i = index.iloc[list(connected_ix),0]
25
+ j = index.iloc[list(connected_ix),1]
26
+ A = lil_matrix((self.n, self.n))
27
+ A[i, j] = 1
28
+ if plot == True:
29
+ plt.figure()
30
+ plt.spy(A, markersize=1)
31
+ plt.show()
32
+ A_array = A.toarray()
33
+ return A_array
34
+
@@ -0,0 +1,12 @@
1
+ import numpy as np
2
+
3
+
4
+ class BiclustResult:
5
+ def __init__(self, params, RowxNumber, NumberxCol, Number, info):
6
+ self.params = params
7
+ self.RowxNumber = RowxNumber
8
+ self.NumberxCol = NumberxCol.T
9
+ self.Number = Number
10
+ self.info = info
11
+ self.cluster_row_sizes = np.sum(RowxNumber, axis=0)
12
+ self.cluster_col_sizes = np.sum(NumberxCol, axis=0)
@@ -0,0 +1,449 @@
1
+ import numpy as np
2
+ from GENetLib.fda_func import fd, inprod, eval_basis, int2lfd
3
+ from GENetLib.fda_func import ppbspline, ycheck, wtcheck, fdparcheck
4
+ from scipy.linalg import cholesky, solve, qr, eigh
5
+
6
+
7
+ # Create a class for b-spline functions
8
+ class BsplineFunc:
9
+ def __init__(self, basisobj, Lfdobj = 2, rng = None, returnMatrix = False):
10
+ self.basisobj = basisobj
11
+ self.Lfdobj = Lfdobj
12
+ self.rng = rng
13
+ self.returnMatrix = returnMatrix
14
+
15
+ # Calculate B-spline penaty matrix
16
+ def penalty_matrix(self, btype = 'spline'):
17
+ if btype == 'spline':
18
+
19
+ # Initialize parameters
20
+ if type(self.Lfdobj) == int:
21
+ Lfdobj = int2lfd(self.Lfdobj)
22
+ else:
23
+ Lfdobj = self.Lfdobj
24
+ nbasis = self.basisobj['nbasis']
25
+ params = self.basisobj['params']
26
+ Rangeval = self.basisobj['rangeval']
27
+ Rng = self.rng if self.rng is not None else Rangeval
28
+ rng = np.array(Rng, dtype=float)
29
+ rangeval = np.array(Rangeval, dtype=float)
30
+ params = np.array(params, dtype=float)
31
+ breaks = np.concatenate(([rangeval[0]], params, [rangeval[1]]))
32
+ nbreaks = len(breaks)
33
+ ninterval = nbreaks - 1
34
+ nderiv = Lfdobj['nderiv']
35
+ norder = nbasis - len(params)
36
+ if nderiv >= norder:
37
+ raise ValueError('nderiv >= norder')
38
+ if nderiv > 0 and nderiv == norder - 1:
39
+ raise ValueError(f"Penalty matrix cannot be evaluated for derivative of order {nderiv} for B-splines of order {norder}")
40
+ bwtlist = Lfdobj['bwtlist']
41
+ isintLfd = True
42
+ if nderiv > 0:
43
+ for ideriv in range(1, nderiv + 1):
44
+ fdj = bwtlist[ideriv - 1]
45
+ if fdj is not None and not np.all(fdj['coefs'] == 0):
46
+ isintLfd = False
47
+ break
48
+ intbreaks = np.concatenate(([rng[0]], params, [rng[1]]))
49
+ index = (intbreaks >= rng[0]) & (intbreaks <= rng[1])
50
+ intbreaks = intbreaks[index]
51
+ uniquebreaks = np.min(np.diff(intbreaks)) > 0
52
+ if isintLfd and rng[0] == rangeval[0] and uniquebreaks and rng[1] == rangeval[1]:
53
+ onesv = np.ones((1, norder))
54
+ knots = np.concatenate(((rangeval[0] * onesv)[0], breaks[1:nbreaks - 1], (rangeval[1] * onesv)[0]))
55
+ polyorder = norder - nderiv
56
+ ndegree = polyorder - 1
57
+ prodorder = 2 * ndegree + 1
58
+ polycoef = np.zeros((ninterval, polyorder, norder))
59
+ indxdown = list(range(norder, nderiv, -1))
60
+ for i in range(nbasis):
61
+ t = knots[i:i + norder + 1]
62
+ ppBlist = ppbspline(t)
63
+ Coeff = ppBlist[0]
64
+ index = ppBlist[1]
65
+ nrowcoef = Coeff.shape[0]
66
+ index = index + i - norder
67
+ CoeffD = np.array(Coeff)[:, :polyorder]
68
+ if nderiv > 0:
69
+ for ideriv in range(1, nderiv + 1):
70
+ fac = np.array(indxdown) - ideriv
71
+ CoeffD = np.outer(np.ones(nrowcoef), fac) * CoeffD
72
+ if i >= norder - 1:
73
+ k = norder - 1
74
+ else:
75
+ k = i
76
+ if i <= norder - 1:
77
+ m = i
78
+ else:
79
+ m = norder - 1
80
+ for j in range(nrowcoef):
81
+ polycoef[i - k + j, :, m - j] = CoeffD[j, :]
82
+ prodmat = np.zeros((nbasis, nbasis))
83
+ convmat = np.zeros((norder, norder, prodorder))
84
+ for k in range(ninterval):
85
+ Coeff = polycoef[k, :, :]
86
+ for i in range(ndegree):
87
+ ind = np.arange(i + 1)
88
+ if len(ind) == 1:
89
+ convmat[:, :, i] = np.outer(Coeff[ind, :], Coeff[i - ind, :])
90
+ convmat[:, :, prodorder - i - 1] = np.outer(Coeff[ndegree - ind, :], Coeff[ndegree - i + ind, :])
91
+ else:
92
+ convmat[:, :, i] = np.dot(Coeff[ind, :].T, Coeff[i - ind, :])
93
+ convmat[:, :, prodorder - i - 1] = np.dot(Coeff[ndegree - ind - 1, :].T, Coeff[ndegree - i + ind, :])
94
+ ind = np.arange(ndegree + 1)
95
+ convmat[:, :, ndegree] = np.dot(Coeff[ind, :].T, Coeff[ndegree - ind, :])
96
+ delta = breaks[k + 1] - breaks[k]
97
+ power = delta
98
+ prodmati = np.zeros((norder, norder))
99
+ for i in range(1, prodorder + 1):
100
+ prodmati += power * convmat[:, :, prodorder - i] / i
101
+ power *= delta
102
+ index = np.arange(k, k + norder)
103
+ prodmat[index[:, None], index] += prodmati
104
+ penaltymat = prodmat
105
+ else:
106
+ if uniquebreaks:
107
+ prodmat = inprod(self.basisobj, self.basisobj, Lfdobj, Lfdobj, rng)
108
+ else:
109
+ rngvec = [rng[0]]
110
+ for i in range(1, nbreaks):
111
+ if breaks[i] == breaks[i - 1]:
112
+ rngvec.append(breaks[i])
113
+ rngvec = list(set(rngvec))
114
+ nrng = len(rngvec)
115
+ if rngvec[-1] < rng[1]:
116
+ rngvec.append(rng[1])
117
+ nrng += 1
118
+ prodmat = np.zeros((nbasis, nbasis))
119
+ for i in range(1, nrng):
120
+ rngi = [rngvec[i - 1] + 1e-10, rngvec[i] - 1e-10]
121
+ prodmati = inprod(self.basisobj, self.basisobj, Lfdobj, Lfdobj, rngi)
122
+ prodmat += prodmati
123
+ penaltymat = prodmat
124
+ return penaltymat
125
+
126
+ elif btype == 'fourier':
127
+ nbasis = self.basisobj['nbasis']
128
+ if nbasis % 2 == 0:
129
+ self.basisobj['nbasis'] = nbasis + 1
130
+ type_ = self.basisobj['btype']
131
+ if type_ != "fourier":
132
+ raise ValueError("Wrong basis type")
133
+ if isinstance(self.Lfdobj, int):
134
+ Lfdobj_ = int2lfd(self.Lfdobj)
135
+ nderiv = Lfdobj_['nderiv']
136
+ penaltymatrix = inprod(self.basisobj, self.basisobj, Lfdobj_, Lfdobj_)
137
+ else:
138
+ nderiv = self.Lfdobj['nderiv']
139
+ penaltymatrix = inprod(self.basisobj, self.basisobj, self.Lfdobj, self.Lfdobj)
140
+ return penaltymatrix
141
+
142
+
143
+ def smooth_basis(self, argvals, y, wtvec = None, fdnames = None, covariates = None,
144
+ method = "chol", dfscale = 1, returnMatrix = False):
145
+
146
+ # Check and initialize parameters
147
+ fdParobj = self.basisobj
148
+ dimy = y.shape
149
+ n = dimy[0]
150
+ y_check = ycheck(y, n)
151
+ y = y_check['y']
152
+ y0 = y
153
+ nrep = y_check['ncurve']
154
+ nvar = y_check['nvar']
155
+ fdParobj = fdparcheck(fdParobj, nrep)
156
+ fdobj = fdParobj['fd']
157
+ lambda_ = fdParobj['lambda']
158
+ Lfdobj = fdParobj['lfd']
159
+ penmat = fdParobj['penmat']
160
+ if lambda_ < 0:
161
+ print("Value of 'lambda' was negative. 0 used instead.")
162
+ lambda_ = 0
163
+ wtlist = wtcheck(n, wtvec)
164
+ wtvec = wtlist['wtvec']
165
+ onewt = wtlist['onewt']
166
+ matwt = wtlist['matwt']
167
+ nderiv = Lfdobj['nderiv']
168
+ basisobj = fdobj['basis']
169
+ dropind = basisobj['dropind']
170
+ ndropind = len(dropind) if dropind is not None else 0
171
+ nbasis = basisobj['nbasis'] - ndropind
172
+ names = basisobj['names']
173
+ if ndropind > 0:
174
+ names = np.delete(names, dropind)
175
+ if len(dimy) == 2:
176
+ coef = np.zeros((nbasis, dimy[1]))
177
+ ynames = dimy[1]
178
+ vnames = "value"
179
+ elif len(dimy) == 3:
180
+ coef = np.zeros((nbasis, dimy[1], dimy[2]))
181
+ ynames = dimy[1]
182
+ vnames = dimy[2]
183
+ if covariates is not None:
184
+ if not np.issubdtype(covariates.dtype, np.number):
185
+ raise ValueError("Optional argument COVARIATES is not numeric.")
186
+ if covariates.shape[0] != n:
187
+ raise ValueError("Optional argument COVARIATES has incorrect number of rows.")
188
+ q = covariates.shape[1]
189
+ else:
190
+ q = 0
191
+ beta_ = None
192
+ tnames = None
193
+ if y.ndim > 0 and y.shape[0] > 0:
194
+ tnames = np.arange(1, n+1)
195
+ basismat = eval_basis(argvals, basisobj, 0, returnMatrix)
196
+
197
+ # Calculation
198
+ if method == "chol":
199
+ if n > nbasis + q or lambda_ > 0:
200
+ if covariates is not None:
201
+ ind1 = np.arange(n)
202
+ ind2 = np.arange(nbasis, nbasis + q)
203
+ basismat = np.asmatrix(basismat)
204
+ basismat = np.c_[basismat, np.zeros((basismat.shape[0], q))]
205
+ basismat[ind1[:, np.newaxis], ind2] = covariates
206
+ if matwt:
207
+ wtfac = cholesky(wtvec)
208
+ basisw = wtvec @ basismat
209
+ else:
210
+ rtwtvec = np.sqrt(wtvec)
211
+ basisw = (wtvec @ np.ones((1, nbasis + q))) * np.array(basismat)
212
+ Bmat = basisw.T @ basismat
213
+ Bmat0 = Bmat
214
+ if len(dimy) < 3:
215
+ Dmat = basisw.T @ y
216
+ else:
217
+ Dmat = np.zeros((nbasis + q, nrep, nvar))
218
+ for ivar in range(nvar):
219
+ Dmat[:, :, ivar] = basisw.T @ y[:, :, ivar]
220
+ if lambda_ > 0:
221
+ if penmat is None:
222
+ penmat = BsplineFunc(basisobj = basisobj, Lfdobj = Lfdobj).penalty_matrix()
223
+ Bnorm = np.sqrt(np.sum(np.diag(Bmat0.T @ Bmat0)))
224
+ pennorm = np.sqrt(np.sum(penmat * penmat))
225
+ condno = pennorm / Bnorm
226
+ if lambda_ * condno > 1e12:
227
+ lambda_ = 1e12 / condno
228
+ print(f"Warning: lambda reduced to {lambda_} to prevent overflow")
229
+ if covariates is not None:
230
+ penmat = np.block([[penmat, np.zeros((nbasis, q))], [np.zeros((q, nbasis)), np.zeros((q, q))]])
231
+ Bmat = Bmat0 + lambda_ * penmat
232
+ else:
233
+ penmat = None
234
+ Bmat = Bmat0
235
+ Bmat = (Bmat + Bmat.T) / 2
236
+ try:
237
+ Lmat = cholesky(Bmat)
238
+ except np.linalg.LinAlgError:
239
+ Beig = eigh(Bmat)
240
+ BgoodEig = Beig[0] > 0
241
+ Brank = np.sum(BgoodEig)
242
+ if Brank < Bmat.shape[0]:
243
+ print(f"Warning: Matrix of basis function values has rank {Brank} < {Bmat.shape[0]}, ignoring null space")
244
+ goodVec = Beig[1][:, BgoodEig]
245
+ Bmatinv = goodVec @ np.diag(1 / Beig[0][BgoodEig]) @ goodVec.T
246
+ else:
247
+ Lmatinv = solve(Lmat, np.eye(Lmat.shape[0]))
248
+ Bmatinv = Lmatinv @ Lmatinv.T
249
+
250
+ if len(dimy) < 3:
251
+ coef = Bmatinv @ Dmat
252
+ if covariates is not None:
253
+ beta_ = coef[nbasis:, :]
254
+ coef = coef[:nbasis, :]
255
+ else:
256
+ beta_ = None
257
+ else:
258
+ coef = np.zeros((nbasis, nrep, nvar))
259
+ if covariates is not None:
260
+ beta_ = np.zeros((q, nrep, nvar))
261
+ else:
262
+ beta_ = None
263
+ for ivar in range(nvar):
264
+ coefi = Bmatinv @ Dmat[:, :, ivar]
265
+ if covariates is not None:
266
+ beta_[:, :, ivar] = coefi[nbasis:, :]
267
+ coef[:, :, ivar] = coefi[:nbasis, :]
268
+ else:
269
+ coef[:, :, ivar] = coefi
270
+ else:
271
+ if n == nbasis + q:
272
+ if len(dimy) == 2:
273
+ coef = np.linalg.solve(basismat, y)
274
+ else:
275
+ for ivar in range(nvar):
276
+ coef[:, :, ivar] = np.linalg.solve(basismat, y[:, :, ivar])
277
+ penmat = None
278
+ else:
279
+ raise ValueError(f"The number of basis functions = {nbasis + q} exceeds {n} = the number of points to be smoothed.")
280
+ else:
281
+ if n > nbasis or lambda_ > 0:
282
+ if not onewt:
283
+ if matwt:
284
+ wtfac = cholesky(wtvec)
285
+ basismat_aug = wtfac @ basismat
286
+ if len(dimy) < 3:
287
+ y = wtfac @ y
288
+ else:
289
+ for ivar in range(nvar):
290
+ y[:, :, ivar] = wtfac @ y[:, :, ivar]
291
+ else:
292
+ rtwtvec = np.sqrt(wtvec)
293
+ basismat_aug = np.tile(rtwtvec, (nbasis, 1)).T * basismat
294
+ if len(dimy) < 3:
295
+ y = np.tile(rtwtvec, (nrep, 1)).T * y
296
+ else:
297
+ for ivar in range(nvar):
298
+ y[:, :, ivar] = np.tile(rtwtvec, (nrep, 1)).T * y[:, :, ivar]
299
+ else:
300
+ basismat_aug = basismat
301
+ if lambda_ > 0:
302
+ if penmat is None:
303
+ penmat = BsplineFunc(basisobj = basisobj, Lfdobj = Lfdobj).penalty_matrix('fourier')
304
+ eiglist = eigh(penmat)
305
+ Dvec = eiglist[0]
306
+ Vmat = eiglist[1]
307
+ neiglow = nbasis - nderiv
308
+ if Dvec[neiglow] <= 0:
309
+ raise ValueError("Eigenvalue(NBASIS-NDERIV) of penalty matrix is not positive. Check penalty matrix.")
310
+ indeig = np.arange(neiglow)
311
+ penfac = Vmat[:, indeig] @ np.diag(np.sqrt(Dvec[indeig]))
312
+ basismat_aug = np.r_[basismat_aug, np.sqrt(lambda_) * penfac.T]
313
+ if len(dimy) < 3:
314
+ y = np.r_[y, np.zeros((nbasis - nderiv, nrep))]
315
+ else:
316
+ y = np.zeros((y.shape[0] + nbasis - nderiv, y.shape[1], y.shape[2]))
317
+ y[:y.shape[0], :, :] = y0
318
+ ind1 = np.arange(y.shape[0] - (nbasis - nderiv), y.shape[0])
319
+ for ivar in range(nvar):
320
+ y[ind1, :, ivar] = np.zeros((nbasis - nderiv, nrep))
321
+ else:
322
+ penmat = None
323
+ if covariates is not None:
324
+ ind1 = np.arange(n)
325
+ ind2 = np.arange(nbasis, nbasis + q)
326
+ basismat_aug = np.c_[basismat_aug, np.zeros((basismat_aug.shape[0], q))]
327
+ if not onewt:
328
+ if matwt:
329
+ basismat_aug[ind1, ind2] = wtfac @ covariates
330
+ else:
331
+ wtfac = np.tile(rtwtvec, (q, 1)).T
332
+ basismat_aug[ind1, ind2] = wtfac * covariates
333
+ else:
334
+ basismat_aug[ind1, ind2] = covariates
335
+ penmat = np.block([[penmat, np.zeros((nbasis, q))], [np.zeros((q, nbasis)), np.zeros((q, q))]])
336
+ qr_result = qr(basismat_aug)
337
+ if len(dimy) < 3:
338
+ coef = solve(qr_result, y)
339
+ if covariates is not None:
340
+ beta_ = coef[ind2, :]
341
+ coef = coef[:nbasis, :]
342
+ else:
343
+ beta_ = None
344
+ else:
345
+ coef = np.zeros((nbasis, nrep, nvar))
346
+ if covariates is not None:
347
+ beta_ = np.zeros((q, nrep, nvar))
348
+ else:
349
+ beta_ = None
350
+ for ivar in range(nvar):
351
+ coefi = solve(qr_result, y[:, :, ivar])
352
+ if covariates is not None:
353
+ beta_[:, :, ivar] = coefi[ind2, :]
354
+ coef[:, :, ivar] = coefi[:nbasis, :]
355
+ else:
356
+ coef[:, :, ivar] = coefi
357
+ else:
358
+ if n == nbasis + q:
359
+ if len(dimy) == 2:
360
+ coef = np.linalg.solve(basismat, y)
361
+ else:
362
+ for ivar in range(nvar):
363
+ coef[:, :, ivar] = np.linalg.solve(basismat, y[:, :, ivar])
364
+ penmat = None
365
+ else:
366
+ raise ValueError(f"The number of basis functions = {nbasis} exceeds {n} = the number of points to be smoothed.")
367
+ if onewt:
368
+ temp = basismat.T @ basismat
369
+ if lambda_ > 0:
370
+ temp = temp + lambda_ * penmat
371
+ L = cholesky(temp)
372
+ MapFac = solve(L.T, basismat.T)
373
+ y2cMap = solve(L, MapFac)
374
+ else:
375
+ if matwt:
376
+ temp = basismat.T @ (wtvec @ basismat)
377
+ else:
378
+ temp = basismat.T @ (wtvec * basismat)
379
+
380
+ if lambda_ > 0:
381
+ temp = temp + lambda_ * penmat
382
+ L = cholesky((temp + temp.T) / 2)
383
+ MapFac = solve(L.T, basismat.T)
384
+ if matwt:
385
+ y2cMap = solve(L, MapFac @ wtvec)
386
+ else:
387
+ y2cMap = solve(L, MapFac * np.tile(wtvec, (MapFac.shape[0], 1)))
388
+ df_ = np.trace(y2cMap @ basismat)
389
+
390
+ # Calculate SSE
391
+ if len(dimy) < 3:
392
+ yhat = np.array(basismat[:, :nbasis] @ coef)
393
+ SSE = np.sum(np.square(y[:n, :] - yhat))
394
+ if ynames is None:
395
+ ynames = [f"rep_{i+1}" for i in range(nrep)]
396
+ else:
397
+ SSE = 0
398
+ yhat = np.zeros((n, nrep, nvar))
399
+ for ivar in range(nvar):
400
+ yhat[:, :, ivar] = basismat[:, :nbasis] @ coef[:, :, ivar]
401
+ SSE += np.sum(np.square(y[:n, :, ivar] - yhat[:, :, ivar]))
402
+ if ynames is None:
403
+ ynames = [f"rep_{i+1}" for i in range(nrep)]
404
+ if vnames is None:
405
+ vnames = [f"value_{i+1}" for i in range(nvar)]
406
+
407
+ # Calculate GCV
408
+ if df_ < n:
409
+ if len(dimy) < 3:
410
+ gcv = np.zeros(nrep)
411
+ for i in range(nrep):
412
+ SSEi = np.sum(np.square((y[:n, i] - yhat[:, i])))
413
+ gcv[i] = (SSEi / n) / np.square((n - df_) / n)
414
+ else:
415
+ gcv = np.zeros((nrep, nvar))
416
+ for ivar in range(nvar):
417
+ for i in range(nrep):
418
+ SSEi = np.sum(np.square(y[:n, i, ivar] - yhat[:, i, ivar]))
419
+ gcv[i, ivar] = (SSEi / n) / np.square((n - df_) / n)
420
+ gcv = np.array(gcv).tolist()
421
+ else:
422
+ gcv = None
423
+ if fdnames is None:
424
+ fdnames = {
425
+ 'time': tnames.tolist() if tnames is not None else [f"time_{i+1}" for i in range(n)],
426
+ 'reps': ynames,
427
+ 'values': vnames}
428
+ if len(dimy) < 3:
429
+ coef = np.asmatrix(coef)
430
+ fdobj = fd(coef[:nbasis, :], basisobj, fdnames)
431
+ else:
432
+ fdobj = fd(coef[:nbasis, :, :], basisobj, fdnames)
433
+ if penmat is not None and covariates is not None:
434
+ penmat = penmat[:nbasis, :nbasis]
435
+
436
+ # Return results
437
+ smoothlist = {
438
+ 'fd': fdobj,
439
+ 'df': df_,
440
+ 'gcv': gcv,
441
+ 'beta': beta_,
442
+ 'SSE': SSE,
443
+ 'penmat': penmat,
444
+ 'y2cMap': y2cMap,
445
+ 'argvals': argvals,
446
+ 'y': y0
447
+ }
448
+ return smoothlist
449
+