Skip to content

Commit 137e104

Browse files
committed
v2.4
2025-11-16 21:04:27
1 parent 3c785a1 commit 137e104

File tree

11 files changed

+210
-16
lines changed

11 files changed

+210
-16
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ remotes::install_github("nickpoison/astsa/astsa_build")
4747

4848
> We'll send this version to CRAN when the 2nd edition of [Time Series: A Data Analysis Approach ...](https://www.routledge.com/Time-Series-A-Data-Analysis-Approach-Using-R/Shumway-Stoffer/p/book/9781041031642) is published. The planned publication date is Jan/Feb 2026.
4949
50+
- added `filter` and `lag` from the `stats` package to `astsa` ... this way, if `astsa` is loaded after `dplyr`, these scripts will work as originally intended. It just decreases the chance that `dplyr` is the _pain in the ass_ that it is (also, there is minimal chance `stats` is loaded after `dplyr`)
51+
5052
- added 🆕 `arma.check` 🆕  to check a given model (seasonal ok) for causality, invertibility, and parameter redundancy with option (`redundancy.tol`) to specify how close the inverse roots have to be to report a warning of parameter redundancy or over-parameterization (default is .1).
5153

5254
- in `arma.spec`, using ideas from `arma.check`, added user option `redundancy.tol`.

astsa_2.4.tar.gz

2.52 KB
Binary file not shown.

astsa_build/NAMESPACE

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ importFrom("grDevices", "adjustcolor", "col2rgb", "cm.colors", "dev.flush",
99
"rgb2hsv", "xy.coords")
1010
importFrom("stats", "acf", "AIC", "ar", "ar.yw", "arima", "ARMAtoMA", "as.ts",
1111
"BIC", "Box.test", "ccf", "coef", "cor", "cov2cor", "df.kernel",
12-
"diffinv", "dnorm", "fft", "filter", "frequency", "is.ts",
13-
"is.tskernel", "kernapply", "kernel", "lag", "lm", "loess",
12+
"diffinv", "dnorm", "fft", "frequency", "is.ts",
13+
"is.tskernel", "kernapply", "kernel", "lm", "loess",
1414
"lowess", "mvfft", "na.fail", "na.omit", "na.pass", "naprint",
1515
"nextn", "optim", "pacf", "pchisq", "pf", "plot.ts", "ppoints",
1616
"predict", "qf", "qnorm", "qqnorm", "qt", "quantile", "resid",
1717
"rgamma", "rnorm", "runif", "sd", "spec.ar", "spec.pgram",
1818
"spec.taper", "summary.lm", "time", "ts", "ts.intersect",
19-
"ts.plot", "tsp", "var", "vcov")
19+
"ts.plot", "tsp", "var", "vcov")
20+
# `filter` and `lag` removed from above because they are now part of `astsa`
2021
importFrom("utils", "setTxtProgressBar", "txtProgressBar")
2122

2223

astsa_build/R/filter.R

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# this is stats::filter 'as.is'
2+
3+
filter <- function(x, filter, method = c("convolution", "recursive"),
4+
sides = 2L, circular = FALSE, init=NULL)
5+
{
6+
method <- match.arg(method)
7+
x <- as.ts(x)
8+
storage.mode(x) <- "double"
9+
xtsp <- tsp(x)
10+
n <- as.integer(NROW(x))
11+
if (is.na(n)) stop("invalid value of nrow(x)", domain = NA)
12+
nser <- NCOL(x)
13+
filter <- as.double(filter)
14+
nfilt <- as.integer(length(filter))
15+
if (is.na(n)) stop("invalid value of length(filter)", domain = NA)
16+
if(anyNA(filter)) stop("missing values in 'filter'")
17+
18+
if(method == "convolution") {
19+
if(nfilt > n) stop("'filter' is longer than time series")
20+
sides <- as.integer(sides)
21+
if(is.na(sides) || (sides != 1L && sides != 2L))
22+
stop("argument 'sides' must be 1 or 2")
23+
circular <- as.logical(circular)
24+
if (is.na(circular)) stop("'circular' must be logical and not NA")
25+
if (is.matrix(x)) {
26+
y <- matrix(NA, n, nser)
27+
for (i in seq_len(nser))
28+
y[, i] <- .Call(C_cfilter, x[, i], filter, sides, circular)
29+
} else
30+
y <- .Call(C_cfilter, x, filter, sides, circular)
31+
} else {
32+
if(missing(init)) {
33+
init <- matrix(0, nfilt, nser)
34+
} else {
35+
ni <- NROW(init)
36+
if(ni != nfilt)
37+
stop("length of 'init' must equal length of 'filter'")
38+
if(NCOL(init) != 1L && NCOL(init) != nser) {
39+
stop(sprintf(ngettext(nser,
40+
"'init' must have %d column",
41+
"'init' must have 1 or %d columns",
42+
domain = "R-stats"),
43+
nser), domain = NA)
44+
}
45+
if(!is.matrix(init)) dim(init) <- c(nfilt, nser)
46+
}
47+
ind <- seq_len(nfilt)
48+
## NB: this .Call alters its third argument
49+
if (is.matrix(x)) {
50+
y <- matrix(NA, n, nser)
51+
for (i in seq_len(nser))
52+
y[, i] <-
53+
.Call(C_rfilter, x[, i], filter,
54+
c(rev(init[, i]), double(n)))[-ind]
55+
} else
56+
y <-
57+
.Call(C_rfilter, x, filter,
58+
c(rev(init[, 1L]), double(n)))[-ind]
59+
60+
}
61+
# y <- drop(y)
62+
tsp(y) <- xtsp
63+
class(y) <- if(nser > 1L) c("mts", "ts") else "ts"
64+
y
65+
}
66+

astsa_build/R/lag.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# this is stats::lag 'as.is'
2+
3+
lag <- function(x, ...) UseMethod("lag")
4+
5+
lag.default <- function(x, k = 1, ...)
6+
{
7+
if(k != round(k)) {
8+
k <- round(k)
9+
warning("'k' is not an integer")
10+
}
11+
x <- hasTsp(x)
12+
p <- tsp(x)
13+
tsp(x) <- p - (k/p[3L]) * c(1, 1, 0)
14+
x
15+
}

astsa_build/R/zzz.R

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
palette("default")
77
}
88

9+
# no need for below because filter and lag are in astsa as of v2.4
910
# warn if dplyr is loaded
10-
.onAttach <- function(libname, pkgname) {
11-
if ('package:dplyr' %in% search()) {
12-
warning("\nThe package `dplyr` is loaded and it most likely will corrupt
13-
the base scripts `filter` and `lag` that a time series analyst
14-
uses frequently. See `?astsa` or `help(astsa)` for remedies.
15-
A simple one is to detach it: `detach(package:dplyr)`"
16-
)
17-
}
18-
}
11+
#.onAttach <- function(libname, pkgname) {
12+
# if ('package:dplyr' %in% search()) {
13+
#warning("\nThe package `dplyr` is loaded and it most likely will corrupt
14+
#the base scripts `filter` and `lag` that a time series analyst
15+
#uses frequently. See `?astsa` or `help(astsa)` for remedies.
16+
#A simple one is to detach it: `detach(package:dplyr)`"
17+
#)
18+
# }
19+
#}
1920

2021

2122
# below were used for `stats::pairs` in `ar.boot` and `ar.mcmc` and

astsa_build/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ We do not always push the latest version of the package to CRAN, but [the latest
2828

2929
---
3030

31-
&#9940; __WARNING:__ If loaded, the package `dplyr` may (and probably will) corrupt the base scripts `filter` and `lag` that a time series analyst uses often. An easy fix if you’re analyzing time series (or teaching a class) is to (tell students to) do the following if `dplyr` is going being used:
31+
&#9940; __WARNING:__ If loaded, the package `dplyr` may (and probably will) mask the base scripts `filter` and `lag` that a time series analyst uses often. An easy fix if you’re analyzing time series (or teaching a class) is to (tell students to) do the following if `dplyr` is going being used:
3232

3333
```r
3434
# [1] either detach it if it's loaded but no longer needed
3535
detach(package:dplyr)
3636

3737
# [2] or fix it yourself when loading dplyr
3838
# this is a great idea from https://stackoverflow.com/a/65186251
39-
library(dplyr, exclude = c("filter", "lag")) # remove the culprits
39+
library(dplyr, exclude = c("filter", "lag")) # load without the culprits
4040
dlag = dplyr::lag # then correct ...
4141
dfilter = dplyr::filter # ... the blunders
4242
# Now use `dlag` and `dfilter` in dplyr scripts and

astsa_build/man/arma.check.Rd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Check an ARMA Model for Causality, Invertibility, and Parameter Redundancy
55
}
66
\description{
7-
For a give ARMA model (including seasonal models), reports whether the model is causal,
7+
For a given ARMA model (including seasonal models), reports whether the model is causal,
88
invertible, or (approximately) over-parameterized.
99
}
1010
\usage{

astsa_build/man/astsa-package.Rd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ LazyData: \tab yes\cr
2121
\author{
2222
David Stoffer <stoffer@pitt.edu>
2323
}
24-
\section{Warning}{If loaded, the \code{dplyr} package corrupts the base scripts \code{filter} and \code{lag} among other things. In this case, whenever you analyze time series data, we suggest you either:
24+
\section{Warning}{If loaded after \code{astsa}, the package \code{dplyr} will mask the base scripts \code{filter} and \code{lag} among other things. In this case, whenever you analyze time series data, we suggest you either:
2525

2626
(1) Detach it if it's loaded but not being used:
2727
\preformatted{ detach(package:dplyr)

astsa_build/man/filter.Rd

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
% taken from the stats package almost 'as is'
2+
3+
\name{filter}
4+
\alias{filter}
5+
\title{Linear Filtering for Time Series}
6+
\usage{
7+
filter(x, filter, method = c("convolution", "recursive"),
8+
sides = 2, circular = FALSE, init)
9+
}
10+
\arguments{
11+
\item{x}{a univariate or multivariate time series.}
12+
13+
\item{filter}{a vector of filter coefficients in reverse time order
14+
(as for AR or MA coefficients).}
15+
16+
\item{method}{Either \code{"convolution"} or \code{"recursive"} (and
17+
can be abbreviated). If \code{"convolution"} a moving average is
18+
used: if \code{"recursive"} an autoregression is used.}
19+
20+
\item{sides}{for convolution filters only. If \code{sides = 1} the
21+
filter coefficients are for past values only; if \code{sides = 2}
22+
they are centered around lag 0. In this case the length of the
23+
filter should be odd, but if it is even, more of the filter
24+
is forward in time than backward.}
25+
26+
\item{circular}{for convolution filters only. If \code{TRUE}, wrap
27+
the filter around the ends of the series, otherwise assume
28+
external values are missing (\code{NA}).}
29+
30+
\item{init}{for recursive filters only. Specifies the initial values
31+
of the time series just prior to the start value, in reverse
32+
time order. The default is a set of zeros.}
33+
}
34+
\description{
35+
Applies linear filtering to a univariate time series or to each series
36+
separately of a multivariate time series.
37+
}
38+
\value{
39+
A time series object.
40+
}
41+
\details{
42+
Missing values are allowed in \code{x} but not in \code{filter}
43+
(where they would lead to missing values everywhere in the output).
44+
45+
Note that the recursive filter gives
46+
\deqn{x_t = \phi_1 x_{t-1} + \cdots + \phi_p x_{t-p} + w_t}{x[t] =
47+
phi[1]*x[t-1] + \dots + phi[p]*x[t-p] + w[t] }
48+
49+
The convolution filter is
50+
\deqn{x_t = \theta_0 w_{t+o} + \cdots + \theta_{q-1} w_{t+o-(q-1)}}{x[t] = theta[0]*w[t+o] + \dots + theta[q]*x[i+o-(q-1)]}
51+
52+
where \code{o} is the offset: see \code{sides} for how it is determined.
53+
}
54+
\note{
55+
This is \code{stats::filter}. Because of the mess created by \code{dplyr}, now if \code{astsa} is loaded after \code{dplyr}, this will take back the script as originally intended.
56+
}
57+
58+
\examples{
59+
# convolution (default)
60+
wgts = c(.5, rep(1,11), .5)/12
61+
soif = filter(soi, sides=2, filter=wgts)
62+
tsplot(cbind(soi, soif), col=2*2:1, lwd=1:2, spaghetti=TRUE)
63+
64+
# recursive
65+
w = rnorm(300) # 50 extra to avoid startup problems
66+
x = filter(w, filter=c(1.5, -.75), method="recursive")[-(1:50)]
67+
tsplot(x, main="autoregression", col=4, gg=TRUE)
68+
}
69+
\keyword{ts}

0 commit comments

Comments
 (0)