|
8 | 8 | #' \phi_1(x) = 1 \quad\text{and}\quad |
9 | 9 | #' \phi_j(x) = \sqrt{2}\cos(\pi (j-1) x). |
10 | 10 | #' } |
| 11 | +#' The multi-indices \eqn{\mathbf{j}} are generated in a specific order to |
| 12 | +#' maximize statistical efficiency. |
| 13 | +#' All inputs are standardized to lie in the unit hypercube \eqn{[0, 1]^d}. |
11 | 14 | #' |
| 15 | +#' @inheritParams b_rff |
| 16 | +#' @param p The number of basis functions to generate. |
| 17 | +#' |
| 18 | +#' @returns A matrix of tensor-product Sobolev space basis features. |
| 19 | +#' |
| 20 | +#' @references |
| 21 | +#' Zhang, T., & Simon, N. (2023). Regression in tensor product spaces by the |
| 22 | +#' method of sieves. _Electronic journal of statistics_, 17(2), 3660. |
| 23 | +#' |
| 24 | +#' @examples |
| 25 | +#' data(quakes) |
| 26 | +#' |
| 27 | +#' m = ridge(depth ~ b_tpsob(lat, long, p = 100), quakes) |
| 28 | +#' plot(fitted(m), quakes$depth) |
| 29 | +#' |
| 30 | +#' x = 1:150 |
| 31 | +#' y = as.numeric(BJsales) |
| 32 | +#' m = lm(y ~ b_tpsob(x, p = 10)) |
| 33 | +#' plot(x, y) |
| 34 | +#' lines(x, fitted(m), col="blue") |
| 35 | +#' @export |
12 | 36 | b_tpsob <- function( |
13 | 37 | ..., |
14 | 38 | p = 100, |
15 | | - stdize = c("scale", "box", "symbox", "none"), |
16 | 39 | shift = NULL, |
17 | 40 | scale = NULL |
18 | | -) {} |
| 41 | +) { |
| 42 | + x = as.matrix(cbind(...)) |
| 43 | + n = nrow(x) |
| 44 | + d = ncol(x) |
| 45 | + |
| 46 | + std = do_std(x, "box", shift, scale) |
| 47 | + x = std$x |
| 48 | + |
| 49 | + rlang::check_installed("Sieve", "for this basis function.") |
| 50 | + idx = Sieve::create_index_matrix(d, p + 1L, interaction_order = p) |
| 51 | + idx = idx[1L + seq_len(p), -1, drop = FALSE] |
| 52 | + |
| 53 | + m = matrix(nrow = n, ncol = p) |
| 54 | + for (j in seq_len(p)) { |
| 55 | + resc = 2^(sum(idx[j, ] > 1L) / 2) |
| 56 | + m[, j] = resc * row_prod(cos(pi * x * rep(idx[j, ] - 1L, each = n))) |
| 57 | + } |
| 58 | + |
| 59 | + attr(m, "shift") = std$shift |
| 60 | + attr(m, "scale") = std$scale |
| 61 | + attr(m, "call") = rlang::current_call() |
| 62 | + class(m) = c("b_tpsob", "matrix", "array") |
| 63 | + |
| 64 | + m |
| 65 | +} |
| 66 | + |
| 67 | + |
| 68 | +#' @export |
| 69 | +predict.b_tpsob <- function(object, newdata, ...) { |
| 70 | + if (missing(newdata)) { |
| 71 | + return(object) |
| 72 | + } |
| 73 | + rlang::eval_tidy(makepredictcall(object, attr(object, "call")), newdata) |
| 74 | +} |
| 75 | + |
| 76 | +#' @export |
| 77 | +makepredictcall.b_tpsob <- function(var, call) { |
| 78 | + if ( |
| 79 | + as.character(call)[1L] == "b_tpsob" || |
| 80 | + (is.call(call) && identical(eval(call[[1L]]), b_tpsob)) |
| 81 | + ) { |
| 82 | + at = attributes(var)[c("shift", "scale")] |
| 83 | + call[names(at)] = at |
| 84 | + } |
| 85 | + call |
| 86 | +} |
0 commit comments