| Title: | Time-Series Network Construction |
|---|---|
| Description: | Constructs distance, visibility, and state-transition networks from univariate time series. The core constructor provides whole-series and sliding-window distance networks, natural and horizontal visibility graphs following Lacasa et al. (2008) <doi:10.1073/pnas.0709247105> and Luque et al. (2009) <doi:10.1103/PhysRevE.80.046103>, and optional state aggregation. Companion verbs expose discretization, trend classification, and an optional bridge to the 'Nestimate' transition-network models. Core network construction uses only packages distributed with R. |
| Authors: | Mohammed Saqr [aut, cre, cph], Sonsoles López-Pernas [aut, cph], Manuel J. Gomez [aut] (affiliation: University of Murcia) |
| Maintainer: | Mohammed Saqr <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.4.1 |
| Built: | 2026-10-03 12:10:09 UTC |
| Source: | https://github.com/mohsaqr/tsn |
Returns one row per state pair, so a transition network can be read, sorted,
or joined as data rather than reached into. as.data.frame() on the
underlying Nestimate object errors, so this method supplies the tidy view.
## S3 method for class 'ts_tna' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series"), ... )## S3 method for class 'ts_tna' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series"), ... )
x |
A |
row.names |
Optional row names. |
optional |
Ignored. |
what |
Which table to return: |
... |
Ignored. |
A base data frame.
set.seed(1) network <- ts_tna(cumsum(rnorm(60)), labels = c("low", "mid", "high")) as.data.frame(network) head(as.data.frame(network, what = "series"))set.seed(1) network <- ts_tna(cumsum(rnorm(60)), labels = c("low", "mid", "high")) as.data.frame(network) head(as.data.frame(network, what = "series"))
A grouped model is a collection of networks, one per group. This method is
the tidy view of it: every table it returns carries a group column, so a
comparison across groups is a data frame you can read, sort, or join rather
than a set of objects you have to reach into one at a time.
## S3 method for class 'ts_tna_group' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series", "groups"), ... )## S3 method for class 'ts_tna_group' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series", "groups"), ... )
x |
A |
row.names |
Optional row names. |
optional |
Ignored. |
what |
Which table to return: |
... |
Ignored. |
A base data frame whose first column is group.
ts_tna() for the group argument that builds these models.
data(esm_srl) networks <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) as.data.frame(networks, what = "groups") head(as.data.frame(networks))data(esm_srl) networks <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) as.data.frame(networks, what = "groups") head(as.data.frame(networks))
Coerce a TSN result to a data frame
## S3 method for class 'tsn' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series"), connected = FALSE, ... )## S3 method for class 'tsn' as.data.frame( x, row.names = NULL, optional = FALSE, what = c("edges", "series"), connected = FALSE, ... )
x |
A |
row.names |
Optional row names. |
optional |
Ignored. |
what |
Which table to return: |
connected |
Return only the retained edges? The edge table lists every
evaluated dyad; |
... |
Ignored. |
A base data frame: the stable TSN dyad schema when
what = "edges", or the source time series when what = "series".
The state-to-state weight matrix behind a ts_tna()-family model: transition
probabilities for ts_tna(), counts for ts_ftna(), and so on. Without this
method as.matrix() falls through to the default, which coerces the object's
component list rather than its network.
## S3 method for class 'ts_tna' as.matrix(x, rownames.force = NA, ...)## S3 method for class 'ts_tna' as.matrix(x, rownames.force = NA, ...)
x |
A |
rownames.force |
Ignored. |
... |
Ignored. |
A named numeric matrix, states in row and column order.
set.seed(1) network <- ts_tna(cumsum(rnorm(60)), labels = c("low", "mid", "high")) as.matrix(network)set.seed(1) network <- ts_tna(cumsum(rnorm(60)), labels = c("low", "mid", "high")) as.matrix(network)
Coerce a TSN result to a weighted adjacency matrix
## S3 method for class 'tsn' as.matrix(x, rownames.force = NA, ...)## S3 method for class 'tsn' as.matrix(x, rownames.force = NA, ...)
x |
A |
rownames.force |
Ignored. |
... |
Ignored. |
A named numeric matrix.
discretize() exposes every internal state discretizer as a first-class
verb. It accepts the same inputs as tsn() (plus a tsn object) and returns
a tidy one-row-per-observation table of discretized states. tsn() routes
its own state aggregation through the same engine, so
tsn(x, "<method>") and discretize(x, method = "<method>") produce
identical state assignments. Scalar methods learn one shared state space
from all selected values. Temporal methods ("ordinal",
"adaptive_magnitude", and "dtw") first compute patterns or windows
within each series, never across an ID boundary, and then use a shared
alphabet or clustering model.
discretize( data, value = NULL, id = NULL, time = NULL, series = NULL, method = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, seed = NULL )discretize( data, value = NULL, id = NULL, time = NULL, series = NULL, method = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, seed = NULL )
data |
A numeric vector, |
value |
Optional value-column name for long data. |
id |
Optional series-ID column name for long data. |
time |
Optional time-column name for long data. |
series |
Optional series IDs or wide-data column names to select. |
method |
Discretization method. One of |
n_states |
Number of states. Not consumed by |
breaks |
Optional interior thresholds for |
labels |
Optional custom state labels. Length must equal the number of
states produced. When |
transform |
Pre-discretization transform: |
m |
Embedding dimension for |
tau |
Embedding lag for |
seed |
Optional seed for the stochastic discretizers ( |
A tidy data frame of class tsn_states with columns id, time,
value, state (a factor), and probability. The discretization model
and any bin boundaries are stored in the model and breaks attributes.
Bandt, C., & Pompe, B. (2002). Permutation entropy: A natural complexity measure for time series. Physical Review Letters, 88, 174102. doi:10.1103/PhysRevLett.88.174102
discretize(c(1, 5, 2, 9, 3, 7, 4, 8), method = "quantile", n_states = 3) discretize( c(1, 5, 2, 9, 3, 7, 4, 8), method = "quantile", n_states = 3, labels = c("low", "mid", "high") ) discretize(c(3, 1, 4, 1, 5, 9, 2, 6), method = "ordinal", m = 3) discretize(c(10, 12, 8, 40, 44, 9), method = "width", transform = "log")discretize(c(1, 5, 2, 9, 3, 7, 4, 8), method = "quantile", n_states = 3) discretize( c(1, 5, 2, 9, 3, 7, 4, 8), method = "quantile", n_states = 3, labels = c("low", "mid", "high") ) discretize(c(3, 1, 4, 1, 5, 9, 2, 6), method = "ordinal", m = 3) discretize(c(10, 12, 8, 40, 44, 9), method = "width", transform = "log")
A fully anonymized intensive longitudinal data set in which 41 students rated their momentary self-regulation, motivation, and anxiety several times per day (47 to 79 occasions each, one or more per day). Every indicator is on a 0-100 scale. The participant identifiers are fictional names and the calendar dates have been shifted by a constant offset — within-person spacing is preserved while no real dates or identities remain. There are 41 missing indicator values in total.
esm_srlesm_srl
A data frame with 2,820 rows and 13 variables:
Fictional participant identifier (41 unique students).
Within-person occasion index, ordered in time.
Anonymized (constant-shifted) assessment date.
Factor with levels "weekday" and "weekend", derived
from date.
Momentary self-efficacy (motivation), 0-100.
Momentary task value (motivation), 0-100.
Momentary planning (self-regulation), 0-100.
Momentary monitoring (self-regulation), 0-100.
Momentary effort regulation (self-regulation), 0-100.
Momentary strategy regulation (self-regulation), 0-100.
Momentary felt motivation (motivation), 0-100.
Momentary enjoyment (motivation), 0-100.
Momentary anxiety, 0-100.
The same data set ships with the authors' 'idiographic' package; the copy
here additionally carries the day_type column, derived from date, so
grouped models (see the group argument of ts_tna()) need no
caller-side preparation.
Package authors' own experience-sampling study, collected by the authors and anonymized as described above (fictional identifiers, constant-shifted dates). Distributed with the package under its license.
Combined views of a ts_tna()-family result. type = "combined"
(default) places each source series — with optional state shading
and/or a classification ribbon — beside a transition network on the
same row. With network = "per_series" (default) every row pairs a
series with its own network (rebuilt via series_networks(), so
all networks share the same node set and are directly comparable);
network = "summary" draws the pooled model instead, spanning all
series rows and titled "Summary". One state colour mapping ties the
shading, ribbons, and network nodes together. type = "network" draws
only the network(s) — a row of per-series networks or the single
summary; type = "series" only the series panels. Every combination
of overlay (shaded or not) and ribbon is available.
## S3 method for class 'ts_tna' plot( x, type = c("combined", "network", "series"), series = NULL, max_series = 3L, network = c("per_series", "summary"), overlay = c("horizontal", "vertical", "none"), ribbon = FALSE, points = FALSE, node_size = c("instrength", "outstrength", "strength"), node_scale = 1, network_width = 0.85, show_weights = TRUE, alpha = 0.28, line_color = "#3B4252", line_width = 1.5, point_size = 0.9, strip_height = 0.09, palette = NULL, legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )## S3 method for class 'ts_tna' plot( x, type = c("combined", "network", "series"), series = NULL, max_series = 3L, network = c("per_series", "summary"), overlay = c("horizontal", "vertical", "none"), ribbon = FALSE, points = FALSE, node_size = c("instrength", "outstrength", "strength"), node_scale = 1, network_width = 0.85, show_weights = TRUE, alpha = 0.28, line_color = "#3B4252", line_width = 1.5, point_size = 0.9, strip_height = 0.09, palette = NULL, legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )
x |
A |
type |
|
series |
Optional series IDs to draw (default: up to |
max_series |
Maximum number of series panels (default |
network |
Which network(s) to draw: |
overlay |
Series shading: |
ribbon |
Whether to run the state strip under each series panel. |
points |
Whether to draw state-coloured observation points. |
node_size |
Node sizing rule: |
node_scale |
Multiplier for cograph's node size range
( |
network_width |
Width of the network column relative to the series
column (default |
show_weights |
Whether to print edge weights on the network. |
alpha |
Shading opacity. |
line_color, line_width, point_size
|
Series styling. |
strip_height |
Ribbon strip height as a fraction of each panel. |
palette |
State colours (preset name, named vector, or vector). |
legend |
Whether to draw the state legend row. |
xlab, ylab
|
Series axis titles. |
cex |
Global text size multiplier. |
grid |
Whether to draw the background grid. |
background |
Panel background colour. |
... |
Forwarded to |
Network panels are rendered exclusively by
cograph::splot() — the full TNA style with self-loops and probability
labels — with node fills matching the state shading and nodes sized by
cograph's native centrality scaling (scale_nodes_by = "instrength" by
default, with loops = FALSE), so heavily-entered states read as larger
and self-transitions do not drown the between-state structure; pass
scale_nodes_by = list("instrength", loops = TRUE) through ... to
include self-transitions. "outstrength" and "strength"
(total) are alternatives, and ... is forwarded to cograph::splot()
for full control (anything you set there overrides these defaults).
show_weights controls cograph's edge labels.
x, invisibly.
set.seed(1) series <- list(a = cumsum(rnorm(80)), b = cumsum(rnorm(80))) network <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) plot(network) plot(network, network = "summary") plot(network, ribbon = TRUE, overlay = "none") plot(network, "network")set.seed(1) series <- list(a = cumsum(rnorm(80)), b = cumsum(rnorm(80))) network <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) plot(network) plot(network, network = "summary") plot(network, ribbon = TRUE, overlay = "none") plot(network, "network")
A grouped model holds one complete ts_tna network per group, and there is
no single picture of all of them, so one group is drawn at a time. The
selected network is rendered by plot.ts_tna() with its full argument
surface — combined series-plus-network views, state shading, ribbons, and
every cograph::splot() option.
## S3 method for class 'ts_tna_group' plot(x, y = NULL, group = NULL, ...)## S3 method for class 'ts_tna_group' plot(x, y = NULL, group = NULL, ...)
x |
A |
y |
Ignored. |
group |
Group label to draw. It may be omitted when the model holds exactly one group. |
... |
Passed to |
x, invisibly.
ts_tna() for the group argument;
as.data.frame.ts_tna_group() for the tidy views of the collection.
data(esm_srl) networks <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) plot(networks, group = "weekday") plot(networks, group = "weekend", type = "network")data(esm_srl) networks <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) plot(networks, group = "weekday") plot(networks, group = "weekend", type = "network")
By default, plot() renders the constructed network through
cograph::splot(). The diagnostic source-series view (with optional state
shading) remains available via type = "series" and does not require
cograph.
## S3 method for class 'tsn' plot(x, type = c("network", "series"), ...)## S3 method for class 'tsn' plot(x, type = c("network", "series"), ...)
x |
A |
type |
What to draw: |
... |
Arguments forwarded to the network or series renderer. See details. |
Network rendering belongs exclusively to cograph. tsn supplies restrained
defaults that keep edges visible and avoid meaningless per-node rainbow
fills; named arguments in ... override any of them. tsn results already
implement the cograph_network contract. Source-series views remain
tsn-specific because they visualize the original observations rather than a
generic network.
For type = "network", use cograph arguments such as layout, labels,
scale_nodes_by, node_size_range, and edge_label_style. For
type = "series", ... accepts series,
overlay, points, trend, columns, max_series, scales, and
palette.
x, invisibly.
network <- tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "hvg") if (requireNamespace("cograph", quietly = TRUE)) { plot(network) plot(network, layout = "spring") } data(srl) states <- tsn( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "quantile" ) plot(states, "series", overlay = "vertical")network <- tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "hvg") if (requireNamespace("cograph", quietly = TRUE)) { plot(network) plot(network, layout = "spring") } data(srl) states <- tsn( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "quantile" ) plot(states, "series", overlay = "vertical")
Plot One Per-Series Transition Network
## S3 method for class 'tsn_series_networks' plot(x, y = NULL, series = NULL, ...)## S3 method for class 'tsn_series_networks' plot(x, y = NULL, series = NULL, ...)
x |
A |
y |
Ignored. |
series |
Series ID to draw. It may be omitted when the collection holds exactly one model. |
... |
Passed to |
x, invisibly.
states <- discretize(c(3, 1, 4, 2, 5, 3, 6, 2, 7)) networks <- series_networks(ts_tna(states)) plot(networks, type = "network")states <- discretize(c(3, 1, 4, 2, 5, 3, 6, 2, 7)) networks <- series_networks(ts_tna(states)) plot(networks, type = "network")
Four views of a discretized series, selected with type. "overlay"
(default) draws each series with translucent state shading behind it;
"ribbon" keeps the series clean and runs a state-classification strip
underneath it instead; "heatmap" draws one row per series with one
coloured tile per observation, which scales to many series where the
faceted views do not; "stack" places an aligned companion series above
the discretized series.
## S3 method for class 'tsn_states' plot( x, type = c("overlay", "ribbon", "heatmap", "stack"), series = NULL, overlay = c("horizontal", "vertical", "none"), lines = "none", min_run = 1L, points = TRUE, max_series = NULL, columns = NULL, palette = NULL, alpha = NULL, line_color = "#3B4252", line_width = 1.6, point_size = 1, strip_height = 0.1, sort = "none", border = FALSE, with = NULL, with_label = "Series", shade = TRUE, color_line = FALSE, ribbons = NULL, ribbon_label = "States", legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )## S3 method for class 'tsn_states' plot( x, type = c("overlay", "ribbon", "heatmap", "stack"), series = NULL, overlay = c("horizontal", "vertical", "none"), lines = "none", min_run = 1L, points = TRUE, max_series = NULL, columns = NULL, palette = NULL, alpha = NULL, line_color = "#3B4252", line_width = 1.6, point_size = 1, strip_height = 0.1, sort = "none", border = FALSE, with = NULL, with_label = "Series", shade = TRUE, color_line = FALSE, ribbons = NULL, ribbon_label = "States", legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )
x |
A |
type |
The view: |
series |
Optional character vector of series IDs to display. |
overlay |
Colour shading for the overlay view: |
lines |
Dashed guide lines complementing the shading:
|
min_run |
For |
points |
Whether to draw observations over each line. |
max_series |
Maximum number of series to draw ( |
columns |
Number of panel columns. |
palette |
State colours: |
alpha |
Shading opacity for the overlay view. |
line_color |
Series line colour. |
line_width |
Series line width. |
point_size |
Observation point size. |
strip_height |
Height of the ribbon strip as a fraction of the panel. |
sort |
Heatmap row order: |
border |
Whether heatmap tiles carry a thin separator border. |
with |
For |
with_label |
Y-axis title of the companion panel. |
shade |
For |
color_line |
For |
ribbons |
For |
ribbon_label |
Strip label for the object's own states in the multi-ribbon view. |
legend |
Whether to draw the legend row. |
xlab, ylab
|
Axis titles. |
cex |
Global text size multiplier. |
grid |
Whether to draw the background grid. |
background |
Panel background colour. |
... |
Reserved for future options. |
x, invisibly.
data(srl) complete <- subset(srl, !is.na(effort)) states <- discretize( complete, value = "effort", id = "name", time = "day", method = "quantile", n_states = 3 ) plot(states, series = "Erik") plot(states, series = "Erik", overlay = "vertical", lines = "horizontal") plot(states, "ribbon", series = "Erik", points = FALSE) plot(states, "heatmap", max_series = 12, sort = "mean") plot(states, "heatmap", palette = "viridis", max_series = 12) # Stack: original series read against the states of its rolling volatility. one <- subset(complete, name == "Erik") volatility <- abs(c(0, diff(one$effort))) vol_states <- discretize( data.frame(name = one$name, day = one$day, vol = volatility), value = "vol", id = "name", time = "day", method = "quantile", n_states = 3 ) plot(vol_states, "stack", with = one$effort, with_label = "Effort", ylab = "Volatility")data(srl) complete <- subset(srl, !is.na(effort)) states <- discretize( complete, value = "effort", id = "name", time = "day", method = "quantile", n_states = 3 ) plot(states, series = "Erik") plot(states, series = "Erik", overlay = "vertical", lines = "horizontal") plot(states, "ribbon", series = "Erik", points = FALSE) plot(states, "heatmap", max_series = 12, sort = "mean") plot(states, "heatmap", palette = "viridis", max_series = 12) # Stack: original series read against the states of its rolling volatility. one <- subset(complete, name == "Erik") volatility <- abs(c(0, diff(one$effort))) vol_states <- discretize( data.frame(name = one$name, day = one$day, vol = volatility), value = "vol", id = "name", time = "day", method = "quantile", n_states = 3 ) plot(vol_states, "stack", with = one$effort, with_label = "Effort", ylab = "Volatility")
Four views of a trend classification, selected with type. "points"
(default) draws each series with observations coloured by trend state;
"ribbon" runs the trend classification as a strip underneath the clean
series line; "heatmap" draws one row per series with one coloured tile
per observation, comparing trend timing across many series; "panels"
stacks each series above its rolling trend metric (the slope or
correlation trend() classified on) so a state change can be read
against the metric that produced it.
## S3 method for class 'tsn_trend' plot( x, type = c("points", "ribbon", "heatmap", "panels"), series = NULL, max_series = NULL, columns = NULL, palette = NULL, line_color = "#9AA3AD", line_width = 1.3, point_size = 1.05, strip_height = 0.1, sort = "none", border = FALSE, flat_band = TRUE, legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )## S3 method for class 'tsn_trend' plot( x, type = c("points", "ribbon", "heatmap", "panels"), series = NULL, max_series = NULL, columns = NULL, palette = NULL, line_color = "#9AA3AD", line_width = 1.3, point_size = 1.05, strip_height = 0.1, sort = "none", border = FALSE, flat_band = TRUE, legend = TRUE, xlab = "Time", ylab = "Value", cex = 1, grid = TRUE, background = "#FFFFFF", ... )
x |
A |
type |
The view: |
series |
Optional character vector of series IDs to display. |
max_series |
Maximum number of series to draw ( |
columns |
Number of panel columns. |
palette |
Optional named colours overriding individual trend states
(e.g. |
line_color |
Series line colour. |
line_width |
Series line width. |
point_size |
Observation point size. |
strip_height |
Ribbon strip height as a fraction of the panel. |
sort |
Heatmap row order: |
border |
Whether heatmap tiles carry a thin separator border. |
flat_band |
For |
legend |
Whether to draw the legend row. |
xlab, ylab
|
Axis titles. |
cex |
Global text size multiplier. |
grid |
Whether to draw the background grid. |
background |
Panel background colour. |
... |
Reserved for future options. |
x, invisibly.
data(srl) complete <- subset(srl, !is.na(effort)) classified <- trend( complete, value = "effort", id = "name", time = "day", window = 7 ) plot(classified, series = "Erik") plot(classified, "ribbon", series = "Erik") plot(classified, "panels", series = "Erik") plot(classified, "heatmap", max_series = 12)data(srl) complete <- subset(srl, !is.na(effort)) classified <- trend( complete, value = "effort", id = "name", time = "day", window = 7 ) plot(classified, series = "Erik") plot(classified, "ribbon", series = "Erik") plot(classified, "panels", series = "Erik") plot(classified, "heatmap", max_series = 12)
Print a TSN network
## S3 method for class 'tsn' print(x, ...)## S3 method for class 'tsn' print(x, ...)
x |
A |
... |
Additional arguments passed to |
x, invisibly.
Print a state discretization
## S3 method for class 'tsn_states' print(x, ...)## S3 method for class 'tsn_states' print(x, ...)
x |
A |
... |
Passed to |
x, invisibly.
Print a trend classification
## S3 method for class 'tsn_trend' print(x, ...)## S3 method for class 'tsn_trend' print(x, ...)
x |
A |
... |
Passed to |
x, invisibly.
Split a pooled ts_tna()-family model into one full model per source
series. Each element is rebuilt with the same network type and the
shared state alphabet (params = list(alphabet = ...)), so every
network has the same node set in the same order — directly comparable
with each other and with the pooled summary model. Each element is a
complete ts_tna netobject: it keeps its own series data, plots with
plot.ts_tna(), and works with compatible Nestimate verbs. Statistical
procedures still require enough independent sequences for their sampling
design; a one-series split is descriptive rather than bootstrap-ready.
series_networks(x, series = NULL)series_networks(x, series = NULL)
x |
A |
series |
Optional series IDs to keep (default: all). |
A named tsn_series_networks collection containing one ts_tna
object per series. Its print, summary, and data-frame methods return a tidy
one-row-per-series index; plot() draws the sole model or a model selected
with its series argument.
set.seed(1) series <- list(a = cumsum(rnorm(80)), b = cumsum(rnorm(80))) pooled <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) networks <- series_networks(pooled) plot(networks, series = "a")set.seed(1) series <- list(a = cumsum(rnorm(80)), b = cumsum(rnorm(80))) pooled <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) networks <- series_networks(pooled) plot(networks, series = "a")
A balanced intensive longitudinal panel in which 36 students reported nine
self-regulated-learning indicators once per study occasion for 156
occasions. Every indicator is on a 0-100 scale, and day is a
within-person occasion index, so the panel feeds tsn(), discretize(),
and the ts_tna() family directly as long data. There are 131 missing
indicator values in total.
srlsrl
A data frame with 5,616 rows and 11 variables:
Student identifier (36 unique students).
Within-person occasion index, 1 through 156.
Self-efficacy, 0-100.
Task value, 0-100.
Planning, 0-100.
Monitoring, 0-100.
Effort regulation, 0-100.
Control of learning, 0-100.
Help seeking, 0-100.
Social support, 0-100.
Organizing, 0-100.
The same data set ships with the authors' 'idiographic' package; the copy here is identical.
Companion data of Saqr, M., & López-Pernas, S. (Eds.),
Advanced Learning Analytics Methods: AI, Precision and Complexity
(https://github.com/lamethods/data2/tree/main/srl), created and
owned by the package authors and distributed under CC BY-NC-SA 4.0
(https://creativecommons.org/licenses/by-nc-sa/4.0/). Rows are
ordered by name and day; values are unchanged. See the package
COPYRIGHTS file for full attribution.
Summarize a TSN network
## S3 method for class 'tsn' summary(object, ...)## S3 method for class 'tsn' summary(object, ...)
object |
A |
... |
Ignored. |
A one-row data frame with columns method, unit, nodes,
dyads, edges, density, minimum_weight, maximum_weight, and
directed. density divides the connected edges by the number of
possible edges for the network family: state networks
(unit = "state") always count self-loops among the possible edges,
because a state can follow itself, while series, window, and time-point
networks never do, because their units cannot pair with themselves. The
denominator therefore depends only on the network type, never on which
edges happen to be observed, so densities are comparable across models
of the same family.
Summarize Per-Series Transition Networks
## S3 method for class 'tsn_series_networks' summary(object, ...) ## S3 method for class 'tsn_series_networks' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'tsn_series_networks' print(x, ...)## S3 method for class 'tsn_series_networks' summary(object, ...) ## S3 method for class 'tsn_series_networks' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'tsn_series_networks' print(x, ...)
object |
A |
... |
Ignored. |
x |
A |
row.names, optional
|
Ignored. |
A tidy data frame with one row per series.
Summarize a state discretization
## S3 method for class 'tsn_states' summary(object, ...)## S3 method for class 'tsn_states' summary(object, ...)
object |
A |
... |
Ignored. |
A tidy data frame with one row per state giving the count,
proportion, and mean value of observations in that state.
Summarize a trend classification
## S3 method for class 'tsn_trend' summary(object, ...)## S3 method for class 'tsn_trend' summary(object, ...)
object |
A |
... |
Ignored. |
A tidy data frame with one row per observed trend state, giving the
count and proportion of observations in that state.
trend() computes a rolling trend metric for each observation and classifies
every point as "Ascending", "Descending", "Flat", "Turbulent",
"Missing Data", or "Initial". It is a faithful base-R port of the
upstream tsn::trend() behaviour: rolling slope (OLS, Theil-Sen, Spearman,
or Kendall) or growth-factor metrics, an epsilon flat band, and a
volatility override that reclassifies noisy segments as turbulent.
trend( data, value = NULL, id = NULL, time = NULL, series = NULL, window = NULL, method = "slope", slope = "robust", epsilon = 0.05, turbulence_threshold = 5, flat_to_turbulent_factor = 1.5, align = "center" )trend( data, value = NULL, id = NULL, time = NULL, series = NULL, window = NULL, method = "slope", slope = "robust", epsilon = 0.05, turbulence_threshold = 5, flat_to_turbulent_factor = 1.5, align = "center" )
data |
A numeric vector, |
value |
Optional value-column name for long data. |
id |
Optional series-ID column name for long data. |
time |
Optional time-column name for long data. |
series |
Optional series IDs or wide-data column names to select. |
window |
Rolling-window width. When |
method |
Trend metric: |
slope |
Slope estimator when |
epsilon |
Flat-band half-width. Default |
turbulence_threshold |
Baseline volatility threshold for the turbulent
override. Default |
flat_to_turbulent_factor |
Multiplier applied to |
align |
Window alignment: |
The metric is first thresholded with epsilon: values above +epsilon
(or above 1 + epsilon for growth factors) are ascending, values below
-epsilon (or 1 - epsilon) are descending, and the remainder are flat.
A rolling volatility measure (coefficient of variation plus half the range
factor of the metric) then overrides these labels with "Turbulent" when it
exceeds turbulence_threshold. Segments already labelled "Flat" use the
higher threshold turbulence_threshold * flat_to_turbulent_factor, making
them more resistant to noise-driven reclassification.
A tidy data frame of class tsn_trend with one row per observation
and columns id, time, value, metric, and state (a factor over the
six trend classes). Print, summary, and plot methods are provided.
set.seed(123) walk <- cumsum(rnorm(120)) trend(walk, window = 15, slope = "ols", epsilon = 0.1) trend(c(1, 2, 3, 4, 5, 4, 3, 2, 1), window = 3, method = "growth_factor")set.seed(123) walk <- cumsum(rnorm(120)) trend(walk, window = 15, slope = "ols", epsilon = 0.1) trend(c(1, 2, 3, 4, 5, 4, 3, 2, 1), window = 3, method = "growth_factor")
ts_tna(), ts_ftna(), ts_cna(), and ts_atna() bridge tsn's
discretization engine to the Nestimate package: a numeric time series (or
several) is discretized into states with any of tsn's discretizers, each
series becomes one state sequence, and Nestimate builds the transition
network — row-normalized probabilities (ts_tna), raw transition counts
(ts_ftna), co-occurrence counts (ts_cna), or attention-weighted
transitions (ts_atna).
ts_tna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_ftna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_cna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_atna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... )ts_tna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_ftna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_cna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... ) ts_atna( data, value = NULL, id = NULL, time = NULL, series = NULL, discretization = "quantile", n_states = 3L, breaks = NULL, labels = NULL, transform = "none", m = NULL, tau = NULL, segment = NULL, overlap = FALSE, group = NULL, seed = NULL, ... )
data |
A numeric vector, |
value |
Optional value-column name for long data. |
id |
Optional series-ID column name for long data. |
time |
Optional time-column name for long data. |
series |
Optional series IDs or wide-data column names to select. |
discretization |
Discretization method passed to |
n_states |
Number of states (default |
breaks |
Optional interior thresholds for
|
labels |
Optional state labels; these become the network's node
names (e.g. |
transform |
Pre-discretization transform: |
m, tau
|
Embedding arguments for |
segment |
Optional block width, in observations, used to cut each series
into several shorter sequences. Sequence-based inference resamples whole
sequences, so a single long series offers nothing to resample; segmenting
supplies the units. Blocks never span an ID boundary, and segmentation is
applied after discretization, so the state alphabet is still learned from
the whole series. At least |
overlap |
When segmenting, slide the block one observation at a time
instead of partitioning (default |
group |
Optional name of a column of |
seed |
Optional seed for the stochastic discretizers ( |
... |
Passed on to the corresponding Nestimate builder
( |
The result is a full Nestimate netobject (also a cograph_network), so
compatible Nestimate descriptive and inferential verbs apply and
cograph::splot() renders it directly. Inference still requires the sample
its method assumes: for example, sequence bootstrap is degenerate for a
single sequence. The object keeps its data: $data holds the wide state
sequences Nestimate built from, $ts_source the tidy per-observation table
(id, time, value, state), and $meta$tsn the discretization and
builder settings, so the network remains traceable back to the raw series.
A single series supports every descriptive verb but no sequence-based test,
because a bootstrap resamples sequences and one series is one sequence. The
segment argument cuts a long series into blocks so that those tests have
units to work with; see its documentation for the trade-off between
partitioned and sliding blocks.
The group argument splits the model instead of pooling it: one network per
condition, cohort, or context, all cut from one shared state alphabet so they
can be compared. The result is a Nestimate netobject_group, so the grouped
Nestimate verbs that suit a transition model apply to it directly. Verbs
needing a precision matrix or a clustering attribute do not, and there is no
grouped plot() method.
Multiple series are supported through every tsn input form (named list,
matrix, wide or long data frame). Scalar discretizers learn from pooled
values. Temporal discretizers compute patterns or windows separately within
each series before assigning one shared state alphabet. Each series
contributes one sequence. Passing an existing discretize() result skips
discretization and uses its states as-is.
A Nestimate netobject of class
c("ts_tna", "netobject", "cograph_network") with the additional fields
$ts_source (tidy id/time/value/state table) and $meta$tsn
(discretization settings). With group, a c("ts_tna_group", "netobject_group") collection holding one such network per group, which
Nestimate's compatible grouped verbs (net_prune(),
state_distribution(), net_centrality(), compare_model(),
permutation()) accept directly and
as.data.frame() renders as a tidy table.
set.seed(1) series <- list( a = cumsum(rnorm(60)), b = cumsum(rnorm(60)), c = cumsum(rnorm(60)) ) network <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) network$weights # Frequency counts instead of probabilities: counts <- ts_ftna(series, n_states = 3) # Reuse an existing discretization: states <- discretize(series, method = "kmeans", n_states = 3) ts_tna(states) # Cut one long series into blocks so sequence-based tests have units: long <- cumsum(rnorm(300)) ts_tna(long, segment = 10, labels = c("low", "mid", "high")) # Sliding lag-1 pairs keep every transition and the exact estimate: ts_tna(long, segment = 2, overlap = TRUE, labels = c("low", "mid", "high")) # One network per day type, on a shared alphabet: data(esm_srl) by_day <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) as.data.frame(by_day, what = "groups")set.seed(1) series <- list( a = cumsum(rnorm(60)), b = cumsum(rnorm(60)), c = cumsum(rnorm(60)) ) network <- ts_tna(series, n_states = 3, labels = c("low", "mid", "high")) network$weights # Frequency counts instead of probabilities: counts <- ts_ftna(series, n_states = 3) # Reuse an existing discretization: states <- discretize(series, method = "kmeans", n_states = 3) ts_tna(states) # Cut one long series into blocks so sequence-based tests have units: long <- cumsum(rnorm(300)) ts_tna(long, segment = 10, labels = c("low", "mid", "high")) # Sliding lag-1 pairs keep every transition and the exact estimate: ts_tna(long, segment = 2, overlap = TRUE, labels = c("low", "mid", "high")) # One network per day type, on a shared alphabet: data(esm_srl) by_day <- ts_tna( subset(esm_srl, !is.na(effort)), value = "effort", id = "name", time = "occasion", group = "day_type", labels = c("low", "mid", "high") ) as.data.frame(by_day, what = "groups")
tsn() is the core entry point for constructing networks from time-series
geometry. It builds distance networks between complete series or sliding
windows, and natural or horizontal visibility networks between time points
or discretized states.
tsn( data, method = "visibility", value = NULL, id = NULL, time = NULL, series = NULL, unit = NULL, distance = "euclidean", connect = "full", window = NULL, step = 1L, neighbors = NULL, threshold = NULL, percentile = NULL, bandwidth = NULL, p = 2, bins = NULL, lag = NULL, tolerance = NULL, similarity = NULL, visibility = "natural", state = NULL, discretization = "gaussian", n_states = 3L, breaks = NULL, m = NULL, tau = NULL, directed = FALSE, limit = NULL, penetrable = 0L, decay = 0, aggregation = "sum", chain = FALSE, normalize = FALSE, seed = NULL )tsn( data, method = "visibility", value = NULL, id = NULL, time = NULL, series = NULL, unit = NULL, distance = "euclidean", connect = "full", window = NULL, step = 1L, neighbors = NULL, threshold = NULL, percentile = NULL, bandwidth = NULL, p = 2, bins = NULL, lag = NULL, tolerance = NULL, similarity = NULL, visibility = "natural", state = NULL, discretization = "gaussian", n_states = 3L, breaks = NULL, m = NULL, tau = NULL, directed = FALSE, limit = NULL, penetrable = 0L, decay = 0, aggregation = "sum", chain = FALSE, normalize = FALSE, seed = NULL )
data |
A numeric vector, |
method |
Network selector. The base families are |
value |
Optional value-column name for long data. |
id |
Optional series-ID column name for long data. |
time |
Optional time-column name for long data. |
series |
Optional series IDs for long data or numeric column names for
wide data. Selection happens inside |
unit |
Node unit. Distance networks use |
distance |
Distance measure for distance networks. One of
|
connect |
Distance-to-network rule. |
window |
Sliding-window width when |
step |
Sliding-window step. |
neighbors |
Number of neighbours when |
threshold |
Maximum distance when |
percentile |
Proportion of shortest distances retained when
|
bandwidth |
Positive kernel scale. Used by |
p |
Minkowski power. |
bins |
Number of marginal quantile bins for |
lag |
Maximum cross-correlation lag for |
tolerance |
Event-time scale for the event-based distances: an optional
upper bound on the adaptive coincidence window for
|
similarity |
Optional similarity kernel mapping edge distances to
weights: |
visibility |
Visibility rule: |
state |
Optional state-column name or state vector. |
discretization |
Internal state-discretization method. One of
|
n_states |
Number of states. Not consumed by
|
breaks |
Optional internal thresholds when
|
m |
Embedding dimension for |
tau |
Embedding lag for |
directed |
Whether edges follow their ordered direction. Visibility
edges then run forward in time; distance edges follow the evaluated unit
order. With |
limit |
Optional maximum visibility distance in the units of |
penetrable |
Number of intermediate points allowed to block visibility. |
decay |
Non-negative exponential edge-decay rate per unit of |
aggregation |
State-edge aggregation rule. |
chain |
When |
normalize |
Distance rescaling applied before the connection rule.
|
seed |
Optional seed for the stochastic discretizers ( |
Every supplied argument must be consumed by the resolved configuration.
An option that the selected method, unit, distance, connect, or
discretization cannot use — for example chain on a visibility network,
limit on a distance network, p without distance = "minkowski", or
breaks without discretization = "threshold" — is rejected with an
error rather than silently ignored, so a typo or a misunderstood
configuration cannot produce a plausible but unintended model. Shortcut
methods ("nvg", "hvg", discretizer names) likewise reject granular
arguments that contradict what the shortcut implies.
For state networks, caller-supplied state values fix the node order:
factors keep their declared level order (an unused level becomes a
zero-degree node), and plain character states are ordered by first
appearance. Discretized states follow the discretizer's numeric state
order. The state column of the stored source series preserves this
factor.
A list-backed network object of class
c("tsn", "netobject", "cograph_network"). Its $table component is the
tidy dyad table; use as.data.frame() for that table,
as.data.frame(x, what = "series") for the canonical source observations,
and as.matrix() for the weighted adjacency matrix.
Lacasa, L., Luque, B., Ballesteros, F., Luque, J., & Nuño, J. C. (2008). From time series to complex networks: The visibility graph. Proceedings of the National Academy of Sciences, 105(13), 4972-4975. doi:10.1073/pnas.0709247105
Luque, B., Lacasa, L., Ballesteros, F., & Luque, J. (2009). Horizontal visibility graphs: Exact results for random time series. Physical Review E, 80, 046103. doi:10.1103/PhysRevE.80.046103
Quian Quiroga, R., Kreuz, T., & Grassberger, P. (2002). Event synchronization: A simple and fast method to measure synchronicity and time delay patterns. Physical Review E, 66, 041904. doi:10.1103/PhysRevE.66.041904
series <- list( first = c(1, 2, 3, 2, 1), second = c(1, 1, 2, 3, 5), third = c(5, 4, 3, 2, 1) ) tsn( data = series, method = "distance", unit = "series", distance = "euclidean", connect = "full" ) # One data argument, one method string. tsn(c(3, 1, 4, 2, 5), "hvg") tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "ordinal") tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "distance") data(srl) tsn( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "gaussian" )series <- list( first = c(1, 2, 3, 2, 1), second = c(1, 1, 2, 3, 5), third = c(5, 4, 3, 2, 1) ) tsn( data = series, method = "distance", unit = "series", distance = "euclidean", connect = "full" ) # One data argument, one method string. tsn(c(3, 1, 4, 2, 5), "hvg") tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "ordinal") tsn(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "distance") data(srl) tsn( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "gaussian" )
vg() is a discoverable verb for the package's flagship construction, the
visibility graph. It is a thin wrapper around tsn() with
method = "visibility": vg(x) is equivalent to tsn(x, "nvg") and
vg(x, "horizontal") is equivalent to tsn(x, "hvg"). Every input shape
and every visibility-relevant argument that tsn() accepts is forwarded
through ..., and the result is the same dual-class tsn/netobject/
cograph_network object.
vg(data, type = c("natural", "horizontal"), ...)vg(data, type = c("natural", "horizontal"), ...)
data |
A numeric vector, |
type |
Visibility rule: |
... |
Any other |
A tidy tsn network object (also a netobject and a
cograph_network), equivalent to the corresponding tsn() call. The
stored provenance call records vg() rather than tsn().
tsn() for the full argument set and the distance-network family.
vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7)) vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "horizontal") network <- vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "horizontal", directed = TRUE) if (requireNamespace("cograph", quietly = TRUE)) { plot(network) } data(srl) states <- vg( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "quantile" ) plot(states, "series", overlay = "vertical")vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7)) vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "horizontal") network <- vg(c(3, 1, 4, 2, 5, 3, 6, 2, 7), "horizontal", directed = TRUE) if (requireNamespace("cograph", quietly = TRUE)) { plot(network) } data(srl) states <- vg( srl, value = "effort", id = "name", time = "day", series = "Erik", unit = "state", discretization = "quantile" ) plot(states, "series", overlay = "vertical")