-
Notifications
You must be signed in to change notification settings - Fork 3
/
README.Rmd
231 lines (190 loc) · 7.81 KB
/
README.Rmd
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
---
title: splines2
output: github_document
---
[![CRAN_Status_Badge][r-pkg-badge]][cran-url]
[![Total_Downloads][cranlog-total]][cran-url]
[![Downloads from the RStudio CRAN mirror][cranlog-badge]][cran-url]
[![Build Status][gha-icon]][gha-url]
[![codecov][codecov-main]][codecov]
[![JDS][jds-badge]](https://doi.org/10.6339/21-JDS1020)
```{r setup, echo = FALSE}
knitr::opts_chunk$set(comment = "", cache = TRUE)
options(width = 100, digits = 5)
```
**Package website**: [release][pkgdown-url] | [development][pkgdown-dev]
The R package **splines2** is intended to be a user-friendly *supplementary*
package to the base package **splines**.
## Features
The package **splines2** provides functions to construct basis matrices of
- B-splines
- M-splines
- I-splines
- convex splines (C-splines)
- periodic splines
- natural cubic splines
- generalized Bernstein polynomials
- their integrals (except C-splines) and derivatives of given order by
closed-form recursive formulas
In addition to the R interface, **splines2** provides a C++ header-only library
integrated with **Rcpp**, which allows the construction of spline basis
functions directly in C++ with the help of **Rcpp** and **RcppArmadillo**.
Thus, it can also be treated as one of the **Rcpp\*** packages.
A toy example package that uses the C++ interface is available
[here][example-pkg].
## Installation of CRAN Version
You can install the released version from [CRAN][cran-url].
```R
install.packages("splines2")
```
## Development
The latest version of the package is under development at [GitHub][github-url].
If it is able to pass the automated package checks, one may install it by
```R
if (! require(remotes)) install.packages("remotes")
remotes::install_github("wenjie2wang/splines2", upgrade = "never")
```
## Getting Started
The [Online document][pkgdown-url] provides a reference for all functions and
contains the following vignettes:
- [Demonstration of the common usages in R through examples][pkg-demo].
- [Introduction to the usage with Rcpp][pkg-wi-rcpp]
## Performance
Since version 0.3.0, the implementation of the main functions has been rewritten
in C++ with the help of the **Rcpp** and **RcppArmadillo** packages.
The computational performance has thus been boosted and comparable with the
function `splines::splineDesign()`.
Some quick micro-benchmarks are provided below for reference.
```{r bench-setup}
library(microbenchmark)
options(microbenchmark.unit="relative")
library(splines)
library(splines2)
set.seed(123)
x <- runif(1e3)
degree <- 3
ord <- degree + 1
internal_knots <- seq.int(0.1, 0.9, 0.1)
boundary_knots <- c(0, 1)
all_knots <- sort(c(internal_knots, rep(boundary_knots, ord)))
## check equivalency of outputs
my_check <- function(values) {
all(sapply(values[- 1], function(x) {
all.equal(unclass(values[[1]]), unclass(x), check.attributes = FALSE)
}))
}
```
For B-splines, function `splines2::bSpline()` provides equivalent results with
`splines::bs()` and `splines::splineDesign()`, and is about 3x faster than
`bs()` and 2x faster than `splineDesign()` for this example.
```{r bench-bSpline}
## B-splines
microbenchmark(
"splines::bs" = bs(x, knots = internal_knots, degree = degree,
intercept = TRUE, Boundary.knots = boundary_knots),
"splines::splineDesign" = splineDesign(x, knots = all_knots, ord = ord),
"splines2::bSpline" = bSpline(
x, knots = internal_knots, degree = degree,
intercept = TRUE, Boundary.knots = boundary_knots
),
check = my_check
)
```
Similarly, for derivatives of B-splines, `splines2::dbs()` provides equivalent
results with `splines::splineDesign()`, and is about 2x faster.
```{r bench-dbs}
## Derivatives of B-splines
derivs <- 2
microbenchmark(
"splines::splineDesign" = splineDesign(x, knots = all_knots,
ord = ord, derivs = derivs),
"splines2::dbs" = dbs(x, derivs = derivs, knots = internal_knots,
degree = degree, intercept = TRUE,
Boundary.knots = boundary_knots),
check = my_check
)
```
The **splines** package does not contain an implementation for integrals of
B-splines. Thus, we performed a comparison with package **ibs** (version
`r packageVersion("ibs")`), where the function `ibs::ibs()`
was also implemented in **Rcpp**.
```{r bench-ibs}
## integrals of B-splines
set.seed(123)
coef_sp <- rnorm(length(all_knots) - ord)
microbenchmark(
"ibs::ibs" = ibs::ibs(x, knots = all_knots, ord = ord, coef = coef_sp),
"splines2::ibs" = as.numeric(
splines2::ibs(x, knots = internal_knots, degree = degree,
intercept = TRUE, Boundary.knots = boundary_knots) %*%
coef_sp
),
check = my_check
)
```
The function `ibs::ibs()` returns the integrated B-splines instead of the
integrals of spline basis functions. Thus, we applied the same coefficients to
the basis functions from `splines2::ibs()` for equivalent results, which was
still much faster than `ibs::ibs()`.
For natural cubic splines (based on B-splines), `splines::ns()` uses the QR
decomposition to find the null space of the second derivatives of B-spline basis
functions at boundary knots, while `splines2::nsp()` utilizes the
closed-form null space derived from the second derivatives of cubic B-splines,
which produces nonnegative basis functions (within boundary) and is more
computationally efficient.
```{r bench-ns}
microbenchmark(
"splines::ns" = ns(x, knots = internal_knots, intercept = TRUE,
Boundary.knots = boundary_knots),
"splines2::nsp" = nsp(
x, knots = internal_knots, intercept = TRUE,
Boundary.knots = boundary_knots
)
)
```
The functions `bSpline()` and `mSpline()` produce periodic spline basis
functions based on B-splines and M-splines, respectively, when `periodic = TRUE`
is specified.
The `splines::periodicSpline()` returns a periodic interpolation spline (based
on B-splines) instead of basis matrix.
We performed a comparison with package **pbs** (version `r packageVersion("pbs")`),
where the function `pbs::pbs()` produces a basis matrix of periodic B-spline
by using `splines::spline.des()`.
```{r bench-periodic}
microbenchmark(
"pbs::pbs" = pbs::pbs(x, knots = internal_knots, degree = degree,
intercept = TRUE, periodic = TRUE,
Boundary.knots = boundary_knots),
"splines2::bSpline" = bSpline(
x, knots = internal_knots, degree = degree, intercept = TRUE,
Boundary.knots = boundary_knots, periodic = TRUE
),
"splines2::mSpline" = mSpline(
x, knots = internal_knots, degree = degree, intercept = TRUE,
Boundary.knots = boundary_knots, periodic = TRUE
)
)
```
<details><summary>Session Information for Benchmarks</summary>
```{r session-info}
sessionInfo()
```
</details>
## License
[GNU General Public License][gpl] (≥ 3)
[r-pkg-badge]: https://www.r-pkg.org/badges/version/splines2
[cranlog-badge]: https://cranlogs.r-pkg.org/badges/splines2
[cranlog-total]: https://cranlogs.r-pkg.org/badges/grand-total/splines2
[cran-url]: https://CRAN.R-project.org/package=splines2
[gha-icon]: https://github.com/wenjie2wang/splines2/workflows/R-CMD-check/badge.svg
[gha-url]: https://github.com/wenjie2wang/splines2/actions
[github-url]: https://github.com/wenjie2wang/splines2
[pkgdown-url]: https://wwenjie.org/splines2
[pkgdown-dev]: https://wwenjie.org/splines2/dev
[example-pkg]: https://github.com/wenjie2wang/example-pkg-Rcpp-splines2
[pkg-demo]: https://wwenjie.org/splines2/articles/splines2-intro
[pkg-wi-rcpp]: https://wwenjie.org/splines2/articles/splines2-wi-rcpp
[codecov]: https://app.codecov.io/gh/wenjie2wang/splines2
[codecov-main]: https://codecov.io/gh/wenjie2wang/splines2/branch/main/graph/badge.svg
[jds-badge]: https://img.shields.io/badge/JDS-10.6339%2F21--JDS1020-brightgreen
[gpl]: https://www.gnu.org/licenses/