trendseries 1.6.0
augment_trends(),augment_rolling(), anddecompose_series()now handle date-column names that overlap generated column names, preserving the date column and applying the usual numeric suffix to the generated column.extract_trends()andaugment_trends()now apply the first window to methods such as WMA in mixed vector-window requests, with a warning, instead of silently using the default window.extract_trends()andaugment_trends()now honor Kalman smoothing as the measurement-to-process noise ratio and preserve individually supplied noise variances. Explicitly supplying both variances takes precedence over the ratio.extract_trends()andaugment_trends()now report STL and UCM estimator fallbacks even with.quiet = TRUE. Quiet augmentation also consolidates warnings and identifies affected groups.augment_trends(),augment_rolling(),decompose_series(), andindex_series()now keep groups distinct when their labels contain periods or combine missing values with the literal string"NA".augment_trends()anddecompose_series()now reject interior missing values in daily and weekly series instead of silently removing those observations before estimation. Leading and trailing missing values and irregular trading calendars remain supported.augment_rolling()now warns about every group whose year-to-date accumulation starts mid-year.index_series()now detects frequency independently within each group, including groups with different dating conventions or frequencies.Centered even-window moving averages now return padded
NAvalues when the series cannot support the N+1 filter weights.roll_series()andaugment_rolling()now honorna_rm = TRUEfor centered even-window means by renormalizing the observed weights while retaining boundary padding.Fixed
augment_trends(),augment_rolling(),decompose_series(),deseason_series(), anddetrend_series()returning rows in join or group order rather than preserving the caller’s input order.Fixed
augment_trends()dropping the warnings raised by the filter it dispatched to. A fallback to another estimator, such as a failed UCM fit or STL on a non-seasonal series, now reaches the caller, along with the group it came from. A warning raised for several groups is reported once.Fixed
augment_trends(),augment_rolling(), anddecompose_series()dropping rows whose grouping column isNA. Those rows are now treated as one more series and returned with the rest.
Irregular and daily series
Fixed
augment_trends(),augment_rolling(), anddecompose_series()returning an all-NAcolumn for daily and weekly series. Results were converted back to a data frame through thetstime index, which advances by1/252per observation while a daily calendar skips weekends and holidays. The regenerated dates therefore drifted from the real ones, and the join back onto the input matched nothing. Results now carry the dates the series was built from, so they rejoin the rows they were computed from.Fixed
augment_trends()andaugment_rolling()duplicating rows for semi-annual data. The merge key floored dates to the calendar unit, mapping any frequency other than 12 or 4 to the year, which put both halves of a year on one key. The key now follows the frequency.Fixed
window = "ytd"resetting off-calendar for daily and weekly series. The year came from thetstime index, which advances a year everyfrequencyobservations, so the reset drifted further from January each year. Year-to-date accumulations now reset on the calendar year. Atspassed directly toroll_series()carries no dates, so"ytd"is rejected there for those frequencies.augment_trends()andaugment_rolling()now reject a repeated date in a daily or weekly series. Two rows cannot occupy one position, and results are matched back by date.Rebuilt the
trend_macolumn ofcoffee_arabicaandcoffee_robusta, which wasNAfor every row because the datasets were generated while the join above was broken. The column now holds the 22-observation right-aligned moving average its documentation describes.
Indexing
- New
index_series()rescales one or more data-frame series to a configurable base value, using either the earliest observation or the mean over a year or date range, with support for grouped data and multiple value columns.
Centered moving averages
Fixed the placement of the 2xN moving average used by
extract_trends()andaugment_trends()whenmethods = "ma"is called with an evenwindowandalign = "center". The filter weights were correct but sat one period early, so the trend led the series by one month for a monthly 2x12 and by one quarter for a quarterly 2x4. Composing two centeredRcppRollpasses caused this: for an even window,align = "center"placesn / 2observations after the anchor and onlyn / 2 - 1before it, and the offset survives the second pass. The 2xN filter is now applied directly as the symmetric weightsc(1/2, 1, ..., 1, 1/2) / N, which also padsN / 2positions at each end instead ofN / 2 - 1at the start andN / 2 + 1at the end. Odd windows and non-centered alignments are unaffected, as are the other moving average methods.roll_series()andaugment_rolling()apply the same 2xN filter forstats = "mean"with an even window andalign = "center", so the rolling mean and thematrend method agree given the same window and alignment. The other statistics have no such correction and use a window with one extra period after the anchor.
Rolling aggregations
Fixed rolling and year-to-date aggregations returning a backend identity value for a window with no observed values under
na_rm = TRUE. A"sum"returned0, a"chain"returned0, a"min"returnedInf, a"max"returned-Inf, a"mean"returnedNaN, and an"sd"returned0. All six now returnNA, as does"sd"for a window holding a single value.roll_series()andaugment_rolling()now warn when a year-to-date accumulation starts mid-year. The first year of a series beginning in, say, July accumulates from July rather than from January, so it is not comparable with the years that follow. The values are unchanged.Fixed the chain scale warning never reaching a grouped
augment_rolling()call. The warning was gated on.quiet, which the grouped path sets for every group..quietnow suppresses progress messages only. The scale and calendar checks run once for the whole call rather than once per group.window = "ytd"now requires a seasonal frequency. Annual data previously returned the series unchanged, since each year holds one observation.roll_series()andaugment_rolling()now warn about arguments the requested combination ignores:alignunderwindow = "ytd", andpercent = TRUEwithoutstats = "chain".A grouped
augment_rolling()call with a window longer than some group now names every group that is too short, with its number of rows. The error previously came from whichever group failed first and named none of them.
Documentation
Documented that
augment_rolling()preserves the caller’s input row order.Reorganized the pkgdown articles and package vignettes. The Trend Extraction Methods catalogue now lives on the documentation site as a pkgdown article.
Updated vignette and article plots to use the
ekioplotvisual identity. The package is listed inSuggestsand is used only when building the vignettes.
trendseries 1.5.0
Rolling and year-to-date aggregations
New
augment_rolling()androll_series()add rolling and year-to-date aggregations, mirroring theaugment_trends()/extract_trends()pair.augment_rolling()takes a data frame and addsroll_{stat}_{window}columns (e.g.roll_sum_12);roll_series()takes ats,xts, orzooobject and returnstsresults. Six statistics are available:"sum","chain","mean","sd","min", and"max".stats = "chain"calculatesprod(1 + r) - 1which assumes the series is a rate, e.g., monthly inflation rate. Usepercent = TRUEwhen rates are in percentage points; a warning is issued when the values look mis-scaled for the declared setting.window = "ytd"computes an expanding year-to-date accumulation that resets each January, for any of the six statistics.aligndefaults to"right", the convention for accumulated economic indicators, rather than the centered default used for trends.Grouped series are supported via
group_cols, and multiplevalue_colentries are suffixed with the column name.Rolling statistics are kept in a registry separate from the trend methods. A rolling sum is not in the units of the series, so it is not a trend and cannot be passed to
detrend_series().
Missing values and period grids
Series with gaps were previously handled differently by each entry point, and the disagreements were silent. Missing value handling is now one policy, applied everywhere: a gap inside the observed span is rejected, and missing values at the edges are excluded from estimation rather than rejected.
augment_trends(),decompose_series(),deseason_series(), anddetrend_series()no longer return silently misdated results for series with interior gaps. These functions assumed the series had no gaps. Because observations are positioned by period, a missing period shifted every later value one slot earlier, so results merged back onto the wrong dates and the series lost its final period. Interior gaps and duplicated periods are now rejected, whether the gap comes from a row with a missing value or from a period absent from the data.extract_trends()now rejects missing values inside the observed span of ats,xts, orzooinput. Previously they were passed straight to the filters, where the outcome depended on the method and was usually silent:stl,spline, andhamiltonraised an error,hp,bk, andcfreturned an all-NAseries, and the recursive methods (ewma,bn) propagated the gap to every later observation. Impute the gaps before extracting a trend.Leading and trailing missing values continue to work.
extract_trends()excludes them from estimation and returns the result on the time base of the input, withNAfor the periods that were never observed.augment_rolling()androll_series()are the exception, by design. A rolling window has well-defined local semantics for a gap, so rows with missing values keep their calendar position andna_rmcontrols whether an affected window yieldsNAor is computed from the observations present.df_to_ts()was the last entry point still building a misdated series from a gapped input, and it now applies the same check. A missing or duplicated period is rejected instead of shifting every later observation one slot earlier. Rows are also sorted before conversion, and a row with no date is dropped with a warning rather than left in place to occupy a period it cannot be positioned in. Missing values are kept, which is what leaves the series correctly dated.df_to_ts()now counts the starting period in units of the frequency. It previously used the calendar month whatever the frequency, so a quarterly series beginning in April started at Q4, an annual series dated March started two years late, and a semiannual series beginning in July started at H1. Monthly series were unaffected.Series whose frequency has no exact calendar period (weekly, daily) are not grid-checked. Their starting period is now placed proportionally within the year rather than defaulting to the first period.
Empty input
Fixed the error raised when a data frame has no rows.
augment_trends(),augment_rolling(),decompose_series(),deseason_series(), anddetrend_series()now say the input has no rows. The message previously came from frequency detection or from a complete-cases check further downstream, and named neither the argument nor the problem.Fixed
augment_trends()anddecompose_series()returningNULLfor a grouped call on a data frame with no rows.Fixed
augment_trends()anddecompose_series()failing on a grouped call when the grouping column is a factor with unused levels.split()turns an unused level into an empty group, which was sent through the conversion path and rejected for having no complete cases. Empty groups are now dropped, asaugment_rolling()already did.
Documentation
Function documentation has been tightened, and the missing value policy is now stated on the arguments it applies to.
Reworded the README, the vignettes, and the help pages: cut the fixed method counts that go stale on each release, replaced promises that the components sum back exactly with what the functions do, and removed the duplicated sections in Getting Started.
Added
"henderson"to the documentedmethodsoptions ofaugment_trends()andextract_trends(). The method has always been accepted, but the help pages listed the other nineteen.
trendseries 1.4.0
CRAN release: 2026-07-14
This release combines the 1.3.0 development series, which was never published on CRAN, with the 1.4.0 changes.
New Features
-
decompose_series()is now exported and available for use. This pipe-friendly function decomposes a time series into trend, seasonal, and remainder components, addingtrend_*,seasonal_*, andremainder_*columns to the input data frame. Five methods are available:"stl"(default),"regression","classic"(classical decomposition via centred moving averages,stats::decompose()),"bsm"(Basic Structural state-space Model estimated by the Kalman smoother,stats::StructTS()), and"seats"(X-13ARIMA-SEATS via the optionalseasonalpackage, a Suggested dependency only required for this method). It supports grouped decomposition viagroup_cols, and the components add back up to the original series. See the new Decomposing Series vignette. Additional conveniences:-
methodsaccepts a vector (e.g.c("stl", "classic")), adding each method’s components as separate columns for side-by-side comparison. -
transform = "log"provides a uniform multiplicative decomposition across every method (decompose on the log scale, exponentiate back). -
seasadj = TRUEadds aseasadj_{method}column with the seasonally adjusted series.
-
deseason_series()is a new convenience wrapper arounddecompose_series()focused on seasonal adjustment. It adds aseasadj_{method}column with the deseasoned series (methods"stl"or"seats"), and optionally the full trend/seasonal/remainder decomposition viacomponents = TRUE.detrend_series()is a new convenience wrapper aroundaugment_trends()that returns the detrended series, i.e. the deviation from the trend (the cycle in economics).transform = "log"returns the log deviation from trend (approximately the percentage deviation, the output-gap convention), andcomponents = TRUEalso keeps the fittedtrend_{method}columns.
Bug Fixes
- The Hamilton filter now uses frequency-aware default parameters, as documented. The defaults were hardcoded to the quarterly values (
h = 8,p = 4) regardless of frequency, so monthly series were filtered with a two-quarter horizon instead of the recommended two-year one. Monthly data now defaults toh = 24,p = 12(Hamilton 2018); quarterly behaviour is unchanged. Because the monthly defaults are larger, monthly series now require at least 37 observations (h + p + 1) and the first 35 trend values areNA(previously 13 and 11). Passparams = list(hamilton_h = , hamilton_p = )to reproduce old results.
Internal Improvements
Removed the
gluedependency. The two remainingglue::glue()calls were replaced by the interpolationclialready provides.Removed dead internal code left over from earlier refactors: the unused
.ensure_odd_window()and.check_deprecated_params()helpers, leftoverzlemareferences, and staleHoltWinters/roll_mediannamespace imports.The list of valid methods is now defined in a single internal registry, which
augment_trends()andextract_trends()both read from. The valid decomposition methods fordecompose_series()are defined there as well.The unified parameter validation (
window,smoothing,band,align,params) shared byaugment_trends()andextract_trends()now lives in a single internal helper, shared by both functions.
Documentation
Added a Trend Extraction Methods vignette cataloguing all 20 trend methods by family.
Added a Detrending Series vignette covering
detrend_series(): the deseason-then-detrend workflow for seasonal data, percentage deviations from trend viatransform = "log", method comparison (HP vs Hamilton), and grouped detrending.Removed outdated references to the
TTRpackage from theaugment_trends()andextract_trends()documentation. The EWMAwindowparameter is now documented by what it does: it setsalpha = 2 / (window + 1).
trendseries 1.2.0
CRAN release: 2026-05-02
Breaking Changes
- The
group_varsargument inaugment_trends()is deprecated in favour ofgroup_cols, and calls withgroup_varsnow issue a deprecation warning. Replacegroup_vars = ...withgroup_cols = ...;group_varswill be removed in a future release.
New Features
augment_trends()accepts multiple value columns through a character vector invalue_col. Trends are extracted for each column and namedtrend_{method}_{col}(e.g.trend_stl_consumption).The UCM trend estimator now uses fixed variance components with signal-to-noise ratios derived from Hodrick-Prescott filter lambdas, producing smoother trends by default. The
smoothingparameter overrides the default.Added two Transport for London datasets:
transit_london_monthly, monthly totals of reported bus and Tube journeys, andtransit_london_avgs, monthly averages of the reported daily journey counts.
trendseries 1.1.0
CRAN release: 2025-11-12
Release Date: November 2025
Breaking Changes
Removed Butterworth and Savitzky-Golay filters: The Butterworth low-pass filter and the Savitzky-Golay polynomial smoothing have been removed to focus the package on core econometric methods. The
signalpackage dependency has been removed.Removed exponential smoothing methods: Simple and double exponential smoothing (
exp_simple,exp_double) have been removed. Users can continue using EWMA for exponential smoothing. Theforecastpackage dependency has been removed.
trendseries 1.0.1
Release Date: January 2025
Breaking Changes
- Removed ZLEMA filter: The Zero-Lag Exponential Moving Average (ZLEMA) has been removed from the package. This method was not commonly used in economic analysis and added unnecessary complexity. Users needing zero-lag smoothing can use EWMA with appropriate alpha values.
New Features
- Added Spencer filter: Classic 15-term Spencer moving average filter for trend extraction. The Spencer filter uses symmetric weights designed to preserve cubic polynomial trends while providing smooth results. Implementation uses linear extrapolation at endpoints for simplicity and computational efficiency.
Bug Fixes and Improvements
Moving Average Enhancements
-
Implemented econometrically correct 2xN MA for centered even-window moving averages:
- When using centered alignment with even windows (e.g., 12 for monthly data, 4 for quarterly), the simple moving average now automatically applies the proper 2xN double-smoothing technique
- This matches the X-13ARIMA-SEATS standard for seasonal adjustment
- Example:
window=12, align="center"now correctly applies a 2x12 MA instead of naive centering - Non-centered alignments (right/left) and odd windows continue to use regular single MA
-
Fixed misleading “2x” notation in messages:
- Previous versions displayed “2x12” in messages but didn’t actually implement double smoothing
- Now the “2x” notation only appears when the 2xN algorithm is actually used
- Messages clearly indicate: “Computing 2x12-period MA (auto-adjusted for even-window centering)” vs “Computing 12-period MA with right alignment”
-
Added comprehensive tests for 2xN MA:
- 5 new test cases validating correct behavior for monthly and quarterly data
- Tests confirm 2xN MA differs from simple MA for even-window centered cases
- All 106 MA filter tests passing
trendseries 1.0.0
The first production release of trendseries, an R package for extracting trends from economic time series.
Trend extraction
Two functions cover the main workflows. augment_trends() takes a data frame and adds one trend_{method} column per requested method, with grouped operations through dplyr. extract_trends() takes ts, xts, or zoo objects and returns ts results.
Four families cover the methods in this release.
- Econometric filters: HP (one-sided and two-sided), Baxter-King, Christiano-Fitzgerald, Hamilton, Beveridge-Nelson, and a state-space UCM.
- Moving averages: simple, weighted, exponential, zero-lag, triangular, median, and Gaussian.
- Smoothing: STL, loess, splines, polynomial trends, and simple and double exponential smoothing.
- Signal processing: Kalman smoother, Savitzky-Golay, Butterworth, and kernel smoothing.
Both functions share one parameter system across every method, with window, smoothing, band, align, and params. Defaults track the series frequency, so the HP filter sets lambda to 1600 for quarterly and 14400 for monthly data, moving averages default to four-quarter or twelve-month windows, and bandpass filters use the 6-to-32-quarter business cycle range. Monthly and quarterly series are the main target; STL and the moving average methods also run on daily and other frequencies.
Datasets
Ten economic datasets ship with the package.
- Brazilian data (BCB):
gdp_construction,ibcbr,vehicles,oil_derivatives, andelectric. - UK data (ONS):
retail_householdsandretail_autofuel. - Coffee prices (CEPEA):
coffee_arabicaandcoffee_robusta, both daily. - Metadata:
series_metadata.
Quick example
library(trendseries)
gdp_construction |>
augment_trends(value_col = "index", methods = c("hp", "bk", "ma"))Links
- Website: https://viniciusoike.github.io/trendseries/
- Repository: https://github.com/viniciusoike/trendseries
Built on mFilter, hpfilter, RcppRoll, forecast, dlm, signal, and tsbox. MIT license; requires R 4.1.0 or later.
