transitiontrees is built to slot into the wider
mohsaqr sequence-analysis ecosystem (TraMineR,
tna, Nestimate, cograph). You do
not have to re-export or re-format your data:
context_tree() takes wide sequence data
directly, and it also accepts a fitted transition/network
object (tna, Nestimate), auto-detected by its
S3 class – reading the sequences the object already carries and fitting
the suffix tree on exactly those, over the same state set.
It also speaks TraMineR’s missing-data convention with
no dependency on the package: in wide input, the void code
% and the missing code * (alongside
NA and "") are treated as gaps, never as
states. So a matrix exported from a TraMineR state-sequence
via as.matrix() drops straight in.
This vignette shows the hand-offs on one shared dataset and confirms
they agree. The tna and Nestimate sections
only run if those packages are installed; the wide-data section needs no
extra package.
Hand the wide frame straight to context_tree().
tree_wide <- context_tree(engagement, max_depth = 2L, min_count = 5L)
tree_wide$alphabet
#> [1] "Active" "Average" "Disengaged"
n_nodes(tree_wide)
#> [1] 13A TraMineR user reaches this same tree with
context_tree(as.matrix(seq)) – the void/missing codes are
dropped automatically, so there is no need to declare the alphabet or
strip the void by hand.
tna transition-network objectA tna model carries its underlying sequences in its
$data slot. context_tree() reads them and
decodes through the model’s label set.
library(tna)
#> 'tna' package version 1.2.2
#> ------------------------------------------------------
#> Tikka, S., López-Pernas, S., and Saqr, M. (2025).
#> tna: An R Package for Transition Network Analysis.
#> Applied Psychological Measurement.
#> https://doi.org/10.1177/01466216251348840
#> ------------------------------------------------------
#> Please type 'citation("tna")' for more citation information.
#> See the package website at https://sonsoles.me/tna/
#>
#> Attaching package: 'tna'
#> The following objects are masked _by_ '.GlobalEnv':
#>
#> engagement, group_regulation_long
#> The following objects are masked from 'package:transitiontrees':
#>
#> engagement, group_regulation_long
model_tna <- tna(engagement)
class(model_tna)
#> [1] "tna"
tree_tna <- context_tree(model_tna, max_depth = 2L, min_count = 5L)
tree_tna
#> <transitiontrees> 13 nodes, depth <= 2, 3 states [unpruned]
#> alphabet : Active, Average, Disengaged
#> fit on : 1000 sequences, 24555 observations
#> smoothing: floor(ymin=0.001, rule=interpolate) min_count = 5
#> (start) n=24555 -> Active (0.51)
#> |-- Active n=11894 -> Active (0.86)
#> | |-- Active n=9766 -> Active (0.86)
#> | |-- Average n=1473 -> Active (0.86)
#> | `-- Disengaged n=312 -> Active (0.85)
#> |-- Average n=5063 -> Average (0.55)
#> | |-- Active n=1031 -> Average (0.54)
#> | |-- Average n=2670 -> Average (0.54)
#> | `-- Disengaged n=1043 -> Average (0.57)
#> `-- Disengaged n=6598 -> Disengaged (0.79)
#> |-- Active n=581 -> Disengaged (0.82)
#> |-- Average n=719 -> Disengaged (0.73)
#> `-- Disengaged n=4960 -> Disengaged (0.79)Nestimate network objectNestimate::build_tna() (and the other
build_*() constructors) return a netobject
that likewise carries the sequence frame and a $nodes label
table. Same hand-off:
library(Nestimate)
#>
#> Attaching package: 'Nestimate'
#> The following objects are masked from 'package:tna':
#>
#> cluster_data, group_regulation_long, plot_mosaic
model_nest <- build_tna(engagement)
class(model_nest)
#> [1] "netobject" "cograph_network"
tree_nest <- context_tree(model_nest, max_depth = 2L, min_count = 5L)
tree_nest
#> <transitiontrees> 13 nodes, depth <= 2, 3 states [unpruned]
#> alphabet : Active, Average, Disengaged
#> fit on : 1000 sequences, 24555 observations
#> smoothing: floor(ymin=0.001, rule=interpolate) min_count = 5
#> (start) n=24555 -> Active (0.51)
#> |-- Active n=11894 -> Active (0.86)
#> | |-- Active n=9766 -> Active (0.86)
#> | |-- Average n=1473 -> Active (0.86)
#> | `-- Disengaged n=312 -> Active (0.85)
#> |-- Average n=5063 -> Average (0.55)
#> | |-- Active n=1031 -> Average (0.54)
#> | |-- Average n=2670 -> Average (0.54)
#> | `-- Disengaged n=1043 -> Average (0.57)
#> `-- Disengaged n=6598 -> Disengaged (0.79)
#> |-- Active n=581 -> Disengaged (0.82)
#> |-- Average n=719 -> Disengaged (0.73)
#> `-- Disengaged n=4960 -> Disengaged (0.79)Because all three objects wrap the same sequences, the fitted trees are identical – same alphabet, same nodes, same observation count.
identical(tree_wide$nodes, tree_tna$nodes)
#> [1] TRUE
identical(tree_tna$nodes, tree_nest$nodes)
#> [1] TRUE
data.frame(
route = c("wide", "tna", "Nestimate"),
n_nodes = c(n_nodes(tree_wide), n_nodes(tree_tna), n_nodes(tree_nest)),
nobs = c(model_fit(tree_wide)$nobs, model_fit(tree_tna)$nobs,
model_fit(tree_nest)$nobs))
#> route n_nodes nobs
#> 1 wide 13 24555
#> 2 tna 13 24555
#> 3 Nestimate 13 24555The tree shares one symbol space with the source model, so the whole
pathway API – common_pathways(),
divergent_pathways(), bootstrap_pathways(),
the plots – composes onto an already-estimated network with no
conversion step.
The hand-off works only when the object actually carries its sequences. A pure graph projection – nodes, edges and weights with the raw sequences nulled out (an aggregated transition network) – is rejected, on purpose: the original sequences cannot be recovered from edge weights, so fabricating them would be silently wrong. The same invariant rejects a bare numeric transition matrix.
graph_only <- build_tna(engagement)
graph_only$data <- NULL # strip the stored sequences
context_tree(graph_only) # -> informative error, not a fabricated fit
#> Error:
#> ! This netobject/cograph_network object carries no sequence data anywhere (no usable $data / $sequences / $seqdata / embedded netobject). It looks like a pure graph - an aggregated transition network - and transitiontrees fits on raw sequences, not on aggregated transitions: the original sequences cannot be recovered from edge weights (the same reason numeric transition matrices are rejected). Pass a sequence-bearing object instead, e.g. a wide-format transition/network object that still carries its raw sequences, or the original wide sequence data.frame.transitiontrees fits on raw sequences. If you have only
an aggregated network, go back to the sequence data it was built
from.
The grouped constructors compose too. context_tree()
recognises a group_tna / netobject_group (a
named list of per-group models) and fits one tree per group, returning a
transitiontrees_group that prune_tree(),
compare_trees(), and compare_groups() consume
directly – see the Advanced analysis vignette for the group
workflow.