TNA Group Analysis: Analysis and Comparison of Groups

Companion Tutorial for Transition Network Analysis

tutorial
R
Authors
Affiliation

University of Eastern Finland

University of Eastern Finland

Published

February 6, 2026

1 Introduction

This is the companion tutorial to the main TNA tutorial, focusing on group comparisons, permutation testing, bootstrapping, and data-driven clustering. We assume you have already worked through the main tutorial and understand the basics of building and analyzing a TNA model.

A single TNA model describes the average transition dynamics across all individuals. But averages can hide important differences. Do high and low achievers follow different regulatory strategies? Are there latent subgroups with distinct behavioral patterns? Answering these questions requires moving beyond the aggregate model to group-level analysis.

We cover three complementary approaches:

  1. Group comparison — split data by a known variable and compare transition structures.
  2. Permutation testing — determine whether observed group differences are statistically significant or could have arisen by chance.
  3. Bootstrap validation — quantify the reliability of group-specific edges and centralities.

For data-driven clustering (discovering latent subgroups when no grouping variable exists), see the companion tutorial: TNA Clustering.

1.1 Installation

The tna package is the only package required. It provides all the functions needed for data preparation, model building, visualization, group comparison, permutation testing, bootstrapping, clustering, and sequence analysis.

Install from CRAN:

install.packages("tna")

Or install the development version from GitHub:

# install.packages("remotes")
remotes::install_github("sonsoleslp/tna")

1.2 Setup

We use the same built-in group_regulation_long dataset introduced in the main tutorial. This dataset contains coded collaborative regulation behaviors from student groups, with each row recording an action performed by an actor at a specific time. Crucially, the dataset includes an Achiever column that classifies each actor as “High” or “Low” — this is the grouping variable we will use for between-group comparisons.

The prepare_data() function converts the long-format event log into sequences and automatically preserves the Achiever column as metadata, making it available for group_tna() later.

# Load the built-in collaborative regulation dataset
data("group_regulation_long")

# Convert to sequences, preserving the Achiever metadata column
prepared_data <- prepare_data(
  group_regulation_long,
  action = "Action",   # behavioral states (network nodes)
  actor = "Actor",     # participant IDs (one sequence per actor)
  time = "Time"        # timestamps (for ordering and session splitting)
)

# Build the aggregate TNA model (all sequences combined)
model <- tna(prepared_data)

Each argument controls a different aspect of how the raw data is converted into sequences.

1.2.1 action — what happened

The only required argument. The name of the column containing the events or states to model (e.g., “Plan”, “Monitor”, “Discuss”). These become the nodes in your network. Called with action alone, every row chains into one long sequence — the last event of student A transitions directly into the first event of student B. Fine for a single continuous observation stream, but almost always wrong for multi-participant data.

1.2.2 actor — who did it

The column identifying who performed the action (student ID, user ID, group ID). Creates one sequence per actor instead of one sequence for the entire dataset. This is the single most important argument after action. Events within each actor are sorted by row order, so if your data is already sorted chronologically, this suffices.

1.2.3 time — when it happened

The column containing timestamps. Does two things: (1) sorts events chronologically within each actor, and (2) splits sequences at temporal gaps. If two consecutive events from the same actor are more than 15 minutes apart (the default), they become separate sequences. Change this with time_threshold (in seconds):

# 10-minute gap starts a new sequence
prepared <- prepare_data(df, action = "Action", actor = "Actor",
                         time = "Time", time_threshold = 10 * 60)

1.2.4 order — what came first

A numeric column for event ordering when timestamps are unavailable (step number, turn counter). If both time and order are provided, data is sorted by time first with ties broken by order.

Any columns not specified as action, actor, time, or order are automatically preserved as metadata. The Achiever column (High/Low) is preserved and available for group_tna().

This tutorial uses long-format event data via prepare_data(), but tna() accepts several other input formats directly. Choose whichever matches your data.

1.2.5 Wide Data Frame

Each row is one sequence; each column is a time point. Cell values are categorical state labels. NA values are permitted for variable-length sequences.

data("group_regulation")
model <- tna(group_regulation)

# If extra columns exist, select sequence columns with `cols`:
model <- tna(group_regulation, cols = T1:T26)

1.2.6 Pre-Computed Transition Matrix

A square numeric matrix where element [i, j] is the weight of the transition from state i to state j. Row and column names define the state labels.

mat <- matrix(
  c(0.1, 0.6, 0.3,
    0.4, 0.2, 0.4,
    0.3, 0.3, 0.4),
  nrow = 3, byrow = TRUE,
  dimnames = list(c("A", "B", "C"), c("A", "B", "C"))
)
model <- tna(mat, inits = c(A = 0.5, B = 0.3, C = 0.2))

1.2.7 TraMineR Sequence Object (stslist)

Sequence objects created by TraMineR::seqdef() can be passed directly to tna().

data("engagement")
model <- tna(engagement)

1.2.8 One-Hot Encoded Data

Binary (0/1) data where each column is a feature. import_onehot() computes co-occurrence weights and returns a tna model directly.

model <- import_onehot(binary_data, feature1:feature6, window = "window_id")

1.2.9 Summary

Input Format Function Description
Long event log prepare_data() then tna() Timestamped events with actors
Wide data frame tna(df) Rows = sequences, columns = time points
Pre-computed matrix tna(mat) Square weight matrix with named rows and columns
TraMineR sequence tna(seqobj) Object from TraMineR::seqdef()
One-hot binary data import_onehot() Co-occurrence model from binary feature data

2 Group Analysis with Known Variables

When a meaningful grouping variable is available (e.g., achievement level, course section, experimental condition), we can build separate TNA models for each group and directly compare their transition structures. Because prepare_data() preserved the Achiever column as metadata, we can use group_tna() to split the data into groups automatically:

# Split data by the Achiever variable and build one TNA model per group
gtna <- group_tna(prepared_data, group = "Achiever")

This creates two complete TNA models (one for “High”, one for “Low”), each with its own transition probability matrix, initial probabilities, and sequence data.

Each group is a standard tna object accessible with $:

# Transition probability matrix for the High achievers group
knitr::kable(round(gtna$High$weights, 3))
adapt cohesion consensus coregulate discuss emotion monitor plan synthesis
adapt 0.00 0.26 0.52 0.00 0.04 0.14 0.03 0.01 0.00
cohesion 0.00 0.04 0.54 0.08 0.04 0.12 0.02 0.15 0.01
consensus 0.00 0.02 0.08 0.17 0.23 0.08 0.04 0.36 0.01
coregulate 0.02 0.04 0.11 0.01 0.23 0.20 0.10 0.27 0.02
discuss 0.02 0.06 0.42 0.07 0.17 0.11 0.02 0.01 0.11
emotion 0.00 0.33 0.34 0.02 0.12 0.06 0.03 0.09 0.00
monitor 0.01 0.05 0.16 0.05 0.37 0.10 0.02 0.23 0.02
plan 0.00 0.03 0.29 0.02 0.06 0.18 0.08 0.33 0.00
synthesis 0.14 0.03 0.58 0.01 0.03 0.06 0.00 0.14 0.00
# Initial state probabilities for the Low achievers group
knitr::kable(t(round(gtna$Low$inits, 3)))
0.01 0.04 0.22 0.03 0.17 0.13 0.16 0.22 0.02
# Summary statistics for both groups
summary(gtna)

2.1 Visualizing Group Networks

Similar to standard TNA, almost all types of analysis work the same way and require no extra arguments. Only plot() is needed here with the group model — TNA recognizes that it is a group model and plots all of its networks automatically. Plotting the group models side by side reveals structural differences at a glance. Thicker edges indicate higher transition probabilities; the minimum and cut arguments control which edges are displayed.

# Side-by-side network plots; minimum hides edges below 0.05, cut fades below 0.1
plot(gtna, minimum = 0.05, cut = 0.1)
Figure 1: Transition networks by achievement group
Figure 2: Transition networks by achievement group

2.2 Group-Level Frequency and Mosaic Plots

State frequency and mosaic plots offer complementary views of how state usage differs between groups. The frequency plot shows raw counts, while the mosaic plot displays proportional composition.

# Bar chart of state frequencies for each group
plot_frequencies(gtna)
Figure 3: State frequencies by group
# Mosaic plot showing proportional state composition by group
plot_mosaic(gtna)
Figure 4: Mosaic plot comparing groups

2.2.1 Difference Plot

While side-by-side plots are useful, plot_compare() makes differences explicit by overlaying both networks and coloring edges by direction of difference. This makes it easy to spot which transitions are stronger in one group versus the other.

# Overlay both networks; edges colored by which group is stronger
plot_compare(gtna$High, gtna$Low, minimum = 0.01, cut = 0.1)
Figure 5: Difference network between High and Low achievers

2.3 Model Comparison with compare()

The compare() function provides a comprehensive numerical comparison between two TNA models. It computes the difference in every edge weight, summarizes overall divergence, and compares centrality rankings — giving you a full picture of how much and where the two groups differ.

# Compute comprehensive numerical comparison between the two group models
comp <- compare(gtna$High, gtna$Low)

2.3.1 Difference Matrix

Each cell is the difference in transition probability (High minus Low). Positive values indicate transitions that are stronger in the High group; negative values indicate transitions stronger in the Low group.

# Each cell: High minus Low transition probability (positive = stronger in High)
round(comp$difference_matrix, 3)
            adapt cohesion consensus coregulate discuss emotion monitor   plan
adapt       0.000   -0.015     0.056     -0.030  -0.032   0.030  -0.007 -0.002
cohesion    0.005    0.037     0.086     -0.085  -0.043   0.006  -0.036  0.023
consensus  -0.001    0.011     0.003     -0.036   0.096   0.019  -0.024 -0.068
coregulate  0.011    0.000    -0.048     -0.018  -0.071   0.058   0.018  0.050
discuss    -0.096    0.029     0.210     -0.024  -0.052   0.013  -0.012  0.002
emotion     0.002    0.001     0.035     -0.024   0.044  -0.031  -0.010 -0.021
monitor     0.000   -0.012     0.001     -0.013  -0.010   0.010   0.001  0.018
plan        0.001    0.012     0.007      0.013  -0.015   0.067   0.000 -0.088
synthesis  -0.158   -0.009     0.191     -0.052  -0.059  -0.010  -0.021  0.120
           synthesis
adapt          0.000
cohesion       0.006
consensus      0.001
coregulate     0.000
discuss       -0.070
emotion        0.005
monitor        0.005
plan           0.003
synthesis      0.000

2.3.2 Summary Metrics

# Overall divergence metrics between the two group networks
comp$summary_metrics

2.3.3 Network-Level Properties

# Network-level properties for each group (density, reciprocity, etc.)
comp$network_metrics

2.3.4 Centrality Differences

# Differences in centrality measures between the two groups
comp$centrality_differences

2.4 Permutation Testing

2.4.1 Why Permutation Tests?

The compare() function quantifies the magnitude of differences between two group models, but magnitude alone does not establish statistical significance. Observed differences may reflect genuine structural divergence between groups, or they may be stochastic variation that would arise under any random partition of the data. Without a formal inferential procedure, there is no principled basis for distinguishing the two.

Permutation testing addresses between-group comparisons, which are particularly susceptible to inflated Type I error rates when multiple edges are tested simultaneously. By randomly reassigning group labels while preserving the internal sequential structure of each case, the procedure constructs exact null distributions for edge-level and centrality-level differences, accompanied by effect sizes (van Borkulo et al., 2023). This preserves the temporal dependency structure that parametric tests on summary statistics necessarily violate, and provides a principled basis for distinguishing substantive group differences from stochastic variation.

The permutation approach is especially appropriate for TNA because transition probability matrices are high-dimensional, dependent structures for which standard parametric assumptions (normality, independence, homoscedasticity) do not hold. The test makes no distributional assumptions; it derives significance directly from the data.

NoteHow the Permutation Test Works
  1. Observe: Record the actual difference in each edge weight and centrality measure between the two groups.
  2. Shuffle: Randomly reassign sequences to groups, breaking the association between group membership and transition behavior while preserving the internal sequential structure of each case.
  3. Recompute: Build new TNA models from the shuffled data and calculate new differences.
  4. Repeat: Iterate 1,000 times (or more) to construct the null distribution — the distribution of differences expected if group membership had no systematic relationship with transition dynamics.
  5. Compare: The p-value for each edge is the proportion of permuted differences that equal or exceed the observed difference in absolute magnitude.

A small p-value (< 0.05) indicates that the observed difference is unlikely under the null hypothesis of no group effect, providing evidence of a genuine structural difference. The accompanying effect size quantifies the magnitude of that difference relative to the variability in the null distribution.

2.4.2 Running the Test

All you need is to pass the group TNA model directly. TNA recognizes it as a group model and compares the groups automatically.

set.seed(265)  # for reproducibility
# Test whether edge and centrality differences between groups exceed chance
Permutation <- permutation_test(
  gtna,
  iter = 1000,  # number of random group reassignments
  measures = c("InStrength", "OutStrength", "Betweenness")
)

The measures argument specifies which centrality measures to test in addition to edge weights. With iter = 1000, the smallest achievable p-value is 0.001, which provides adequate resolution for most analyses. For publication-quality results where precise small p-values are needed, increase to 5,000–10,000 iterations.

2.4.3 Edge-Level Results

Each row reports one edge (transition) with its observed difference, effect size, and p-value:

# Results are nested by comparison pair; extract the first (and only) comparison
perm_results <- Permutation[[1]]
perm_results$edges$stats
Column Meaning Interpretation
edge_name The transition (from -> to) Which behavioral transition is being tested
diff_true Observed difference (High minus Low) Direction and magnitude of the group difference
effect_size Difference / SD of permuted differences Standardized effect size (analogous to Cohen’s d). Values > 0.5 indicate moderate effects; > 0.8 large effects
p_value Proportion of permutations as extreme as observed Statistical significance. Values < 0.05 are conventionally significant

2.4.4 Statistically Significant Edges

Filtering for p < 0.05 identifies the transitions for which the observed group difference exceeds what would be expected under the null hypothesis:

# Filter for statistically significant edges and sort by effect size
sig_perm <- perm_results$edges$stats[perm_results$edges$stats$p_value < 0.05, ]
sig_perm <- sig_perm[order(-abs(sig_perm$effect_size)), ]
sig_perm
ImportantReading the Results
  • Positive diff_true: The transition is more probable in the High group than the Low group.
  • Negative diff_true: The transition is more probable in the Low group.
  • Large |effect_size|: The difference is not only statistically significant but substantively meaningful. Effect sizes provide information that p-values alone cannot: a highly significant result with a small effect size may reflect a trivial difference detected through large sample size.
  • Non-significant edges: Even where compare() reported a nonzero difference, a non-significant p-value indicates that such a difference is consistent with chance variation. These edges should not be treated as evidence of group divergence.

2.4.5 Centrality-Level Results

Beyond individual edges, the permutation test evaluates whether group differences in node-level centrality measures are statistically significant. This determines whether certain states occupy structurally different positions in the two groups’ networks — information that cannot be obtained from edge-level tests alone:

# Filter for significant centrality differences between groups
sig_cent <- perm_results$centralities$stats[perm_results$centralities$stats$p_value < 0.05, ]
sig_cent

A significant centrality difference indicates that the state’s role in the network architecture differs between groups. For instance, if “Monitor” has significantly higher betweenness centrality in the High group, this indicates that monitoring occupies a more central bridging position in the regulatory process of high achievers — a structural difference that has direct implications for understanding how self-regulation operates differently across achievement levels.

2.4.6 Visualization

The permutation plot displays only the edges that reached statistical significance, providing a clear visual summary of the confirmed group differences:

# Only edges with p < 0.05 are displayed
plot(Permutation, minimum = 0.01, cut = 0.1)
Figure 6: Significant group differences in transition probabilities

2.5 Bootstrap Validation of Group Models

2.5.1 Why Bootstrap Group Models?

Permutation testing establishes which between-group differences are statistically significant, but it does not address the reliability of the individual group models themselves. A group-specific transition probability of 0.15 is a point estimate. Without further validation, there is no basis for determining whether this estimate reflects a stable property of the underlying process or whether it would shift substantially under a different sample of sequences.

Bootstrapping addresses the replicability of individual edges within each group. By resampling sequences with replacement and reconstructing the transition matrix across a large number of iterations, the procedure generates empirical sampling distributions for each edge weight, thereby distinguishing transitions that are stable properties of the underlying process from those whose presence is contingent on the particular sample at hand (Saqr, Lopez-Pernas, & Tikka, 2025). Edges that do not consistently exceed a defined threshold or that deviate beyond an acceptable consistency range are identified as non-significant, yielding a model in which every retained transition has demonstrated resampling support.

NoteBootstrap and Permutation Test: Complementary Confirmatory Roles

These two procedures address distinct inferential questions and are both necessary for a rigorous group analysis:

Method Inferential Target What It Confirms
Permutation test Between-group differences Whether observed differences in edge weights and centralities exceed what would be expected under random group assignment
Bootstrap Within-group edge stability Whether individual edges within each group model are replicable properties of the data or artifacts of sampling variability

A group difference can be statistically significant (permutation) even when the constituent group estimates are individually imprecise (bootstrap), and an edge can be stable within one group (bootstrap) while not differing significantly from the other group (permutation). Neither test subsumes the other. Together, they provide a complete inferential framework: the bootstrap identifies which transitions reliably exist within each group, and the permutation test identifies which transitions reliably differ between groups.

2.5.2 Bootstrapping the Group Model

Just like permutation_test(), bootstrap() accepts the group model directly. TNA recognizes it as a group model and bootstraps each group automatically:

set.seed(265)  # for reproducibility
# Pass the group model directly; TNA bootstraps each group automatically
boot_groups <- bootstrap(gtna, iter = 1000, level = 0.05)

2.5.3 Interpreting Bootstrap Results

Each bootstrap summary reports, for every edge, whether it demonstrated resampling stability. An edge marked sig = TRUE appeared consistently across 1,000 resampled datasets; an edge marked sig = FALSE did not survive this replicability criterion and should not be treated as a confirmed feature of the group’s transition structure:

High achievers: significant edge

# Edges that survived the bootstrap stability criterion
boot_high_df <- boot_groups$High$summary[boot_groups$High$summary$sig == TRUE, ]
boot_high_df

Low achievers: significant edges

# Edges that survived the bootstrap stability criterion
boot_low_df <- boot_groups$Low$summary[boot_groups$Low$summary$sig == TRUE, ]
boot_low_df
Column Meaning
from, to The transition being evaluated
mean Average edge weight across bootstrap resamples
ci_lower, ci_upper 95% confidence interval for the edge weight
sig TRUE if the edge demonstrated resampling stability — the transition is a confirmed feature of the network

Edges where sig = TRUE constitute the replicable structure of the group model. Edges where sig = FALSE may appear in the point-estimate network but lack the resampling support necessary for substantive interpretation.

2.5.4 Visualizing Bootstrapped Networks

The plot below displays only the edges that survived the bootstrap procedure for each group — the confirmed, replicable transition structure. As with other group-level functions, plot() recognizes the group bootstrap object and plots all groups automatically:

# TNA plots both group bootstrap networks automatically
plot(boot_groups, cut = 0.1)
Figure 7: Bootstrap-validated networks by achievement group
Figure 8: Bootstrap-validated networks by achievement group

Comparing these validated networks to the raw group networks reveals which features of each group’s transition structure survive statistical scrutiny. Transitions present in the raw model but absent from the bootstrapped model were contingent on the particular sample and should not form the basis of substantive conclusions.

3 Group-Level Sequence Analysis

3.1 Comparing Subsequence Patterns

While compare() compares transition matrices (single-step probabilities), compare_sequences() compares the actual multi-step subsequence patterns in each group. This captures higher-order dynamics that pairwise transitions miss. For example, a three-step pattern like Plan -> Monitor -> Adapt may be common in one group but rare in another, even if each individual pairwise transition looks similar.

The function uses Fisher’s exact test on subsequence frequencies, with Bonferroni correction for multiple comparisons:

# Compare multi-step subsequence frequencies between groups (lengths 2-5)
seq_comp <- compare_sequences(gtna, sub = 2:5, min_freq = 5)
seq_comp
plot(seq_comp)
Figure 9: Most differentially frequent patterns between groups

compare() looks at pairwise transition probabilities (e.g., “how likely is Adapt -> Plan?”). compare_sequences() looks at multi-step subsequence patterns (e.g., “how often does Plan -> Monitor -> Adapt appear?”). Subsequences capture higher-order dynamics that pairwise transitions miss.

Argument Description Default
sub Subsequence lengths to compare 2:5
min_freq Minimum frequency to test 5
adjust Multiple comparison correction "bonferroni"

3.2 Sequence Plots by Group

Sequence plots provide a visual overview of the raw sequences, split by group. The index plot shows each individual sequence as a horizontal bar, while the distribution plot shows the proportion of each state at each sequence position.

# Each row is one sequence, colored by state; faceted by Achiever group
plot_sequences(prepared_data, group = "Achiever")
Figure 10: Sequence index plot by achievement group
# Proportion of each state at each position, by group
plot_sequences(prepared_data, group = "Achiever", type = "distribution")
Figure 11: State distribution by achievement group

4 Summary of Statistical Testing

Descriptive comparison of transition networks — visual inspection, difference matrices, centrality rankings — is a necessary starting point but is insufficient for drawing conclusions. Without inferential procedures, there is no basis for distinguishing genuine structural properties from sampling artifacts, or genuine group differences from stochastic variation. This tutorial demonstrated two complementary confirmatory procedures that address distinct inferential targets:

Method Inferential Target What It Establishes Key Output
Permutation test Between-group differences Whether observed differences in transition probabilities and centralities exceed what would be expected under random group assignment p-values, effect sizes for each edge and centrality measure
Bootstrap Within-group edge stability Whether individual transitions within each group model are replicable properties of the data or sample-contingent artifacts Confidence intervals, significance flags for each edge

Neither procedure subsumes the other. A permutation-significant difference between groups can involve edges that are individually imprecise within each group; conversely, a bootstrap-stable edge within one group may not differ significantly from the corresponding edge in another group.

Recommended workflow:

  1. Build group models with group_tna() and inspect them visually.
  2. Use compare() to quantify the direction and magnitude of differences.
  3. Run permutation_test() to determine which differences are statistically significant, obtaining both p-values and effect sizes.
  4. Run bootstrap() on each group model to identify which edges constitute replicable features of each group’s transition structure.
  5. Report and interpret only edges and differences that survive the relevant inferential test. Edges that failed the bootstrap should not be interpreted substantively; group differences that failed the permutation test should not be reported as findings.

References

Citation

BibTeX citation:
@misc{saqr2026,
  author = {Saqr, Mohammed and López-Pernas, Sonsoles},
  title = {TNA {Group} {Analysis:} {Analysis} and {Comparison} of
    {Groups}},
  date = {2026-02-06},
  url = {https://sonsoleslp.github.io/posts/tna-group/},
  langid = {en}
}
For attribution, please cite this work as:
Saqr, Mohammed, and Sonsoles López-Pernas. 2026. “TNA Group Analysis: Analysis and Comparison of Groups.” https://sonsoleslp.github.io/posts/tna-group/.