Skip to contents

1 Introduction

Nestimate is a general-purpose network estimation package. It provides a unified build_network() interface that accepts raw sequence data and constructs networks using multiple methods: transition probabilities, partial correlations, regularized networks (GLASSO), co-occurrence, and more. The result is a netobject that works directly with cograph’s splot() — no conversion needed.

Beyond estimation, Nestimate provides bootstrap stability analysis, permutation-based group comparisons, higher-order network construction (HON, HYPA), and motif analysis. All output objects dispatch through splot() automatically.

2 Data

We use group_regulation_long — a long-format dataset of 9 collaborative regulation behaviors coded across student groups, with achievement group labels (High vs Low).

data("group_regulation_long")
head(group_regulation_long)
# A tibble: 6 × 6
  Actor Achiever Group Course Time                Action
  <int> <chr>    <dbl> <chr>  <dttm>              <chr>
1     1 High         1 A      2025-01-01 08:27:07 cohesion
2     1 High         1 A      2025-01-01 08:35:20 consensus
3     1 High         1 A      2025-01-01 08:42:18 discuss
4     1 High         1 A      2025-01-01 08:50:00 synthesis
5     1 High         1 A      2025-01-01 08:52:25 adapt
6     1 High         1 A      2025-01-01 08:57:31 consensus

3 Estimating Networks

build_network() estimates a network from raw data. The method argument selects the estimator.

net <- build_network(group_regulation_long,
  action = "Action", actor = "Actor", method = "relative")
net
Transition Network (relative probabilities) [directed]
  Weights: [0.001, 0.498]  |  mean: 0.116

  Weight matrix:
             adapt cohesion consensus coregulate discuss emotion monitor  plan
  adapt      0.000    0.273     0.477      0.022   0.059   0.120   0.033 0.016
  cohesion   0.003    0.027     0.498      0.119   0.060   0.116   0.033 0.141
  consensus  0.005    0.015     0.082      0.188   0.188   0.073   0.047 0.396
  coregulate 0.016    0.036     0.135      0.023   0.274   0.172   0.086 0.239
  discuss    0.071    0.048     0.321      0.084   0.195   0.106   0.022 0.012
  emotion    0.002    0.325     0.320      0.034   0.102   0.077   0.036 0.100
  monitor    0.011    0.056     0.159      0.058   0.375   0.091   0.018 0.216
  plan       0.001    0.025     0.290      0.017   0.068   0.147   0.076 0.374
  synthesis  0.235    0.034     0.466      0.044   0.063   0.071   0.012 0.075
             synthesis
  adapt          0.000
  cohesion       0.004
  consensus      0.008
  coregulate     0.019
  discuss        0.141
  emotion        0.003
  monitor        0.016
  plan           0.002
  synthesis      0.000

  Initial probabilities:
  consensus     0.214  ████████████████████████████████████████
  plan          0.204  ██████████████████████████████████████
  discuss       0.175  █████████████████████████████████
  emotion       0.151  ████████████████████████████
  monitor       0.144  ███████████████████████████
  cohesion      0.060  ███████████
  synthesis     0.019  ████
  coregulate    0.019  ████
  adapt         0.011  ██

splot() renders the netobject directly:

splot(net)
Figure 1: Collaborative regulation — relative transition probabilities

One line builds different network types:

build_network(group_regulation_long, action = "Action", actor = "Actor", method = "frequency")
build_network(group_regulation_long, action = "Action", actor = "Actor", method = "attention")
build_network(group_regulation_long, action = "Action", actor = "Actor", method = "co_occurrence")
build_network(group_regulation_long, action = "Action", actor = "Actor", method = "glasso")
build_network(group_regulation, method = "pcor")

4 Bootstrap Stability

bootstrap_network() resamples the data and refits the model at each iteration, identifying which edges are stable and which are sampling artifacts.

set.seed(265)
boot <- bootstrap_network(net, iter = 1000)
boot
  Edge                   Mean     95% CI          p
  -----------------------------------------------
  cohesion → consensus   0.498  [0.474, 0.521]  ***
  adapt → consensus    0.478  [0.430, 0.523]  ***
  synthesis → consensus   0.466  [0.427, 0.507]  ***
  consensus → plan     0.396  [0.383, 0.407]  ***
  monitor → discuss    0.375  [0.351, 0.401]  ***
  ... and 46 more significant edges

Bootstrap Network  [Transition Network (relative) | directed]
  Iterations : 1000  |  Nodes : 9
  Edges      : 47 significant / 71 total
  CI         : 95%  |  Inference: stability  |  CR [0.75, 1.25]

4.1 Network plots

Significant edges appear solid; non-significant edges appear dashed grey.

splot(boot)
Figure 2: Solid = stable edges, dashed = unstable
splot(boot, display = "significant")
Figure 3: Significant edges only
splot(boot, show_stars = TRUE)
Figure 4: With significance stars
splot(boot, show_ci = TRUE)
Figure 5: With 95% confidence intervals

4.2 Forest plots

Forest plots show edge weights and confidence intervals in a compact format. Three layouts are available:

Figure 6: Linear forest plot
plot_bootstrap_forest(boot, layout = "circular")
Figure 7: Circular forest plot
plot_bootstrap_forest(boot, layout = "grouped")
Figure 8: Grouped by source node

5 Group Networks

Pass group = to build_network() to estimate a separate network per group. splot() renders all groups in an automatic grid.

grp_net <- build_network(group_regulation_long, method = "relative",
  action = "Action", actor = "Actor", time = "Time", group = "Achiever")
names(grp_net)
[1] "High" "Low" 
splot(grp_net)
Figure 9: High vs Low achievers on a common weight scale

common_scale = TRUE (default) makes edge widths directly comparable across panels:

splot(grp_net, common_scale = FALSE)
Figure 10: Each group on its own scale

6 Permutation Testing

permutation_test() tests whether each edge differs significantly between two groups.

set.seed(265)
perm <- Nestimate::permutation_test(grp_net$High, grp_net$Low, iter = 1000)
perm
Permutation Test:Transition Network (relative probabilities) [directed]
  Iterations: 1000  |  Alpha: 0.05
  Nodes: 9  |  Edges tested: 78  |  Significant: 42
splot(perm)
Figure 11: Green = High > Low, red = Low > High (p < 0.05)
splot(perm, show_nonsig = TRUE)
Figure 12: All edges — significant solid, non-significant dashed
splot(perm, show_stars = TRUE, show_effect = TRUE)
Figure 13: With significance stars and effect sizes

7 Motifs

Nestimate objects work directly with cograph’s motif analysis. motifs() counts MAN triad types; subgraphs() identifies specific node triples.

mot <- cograph::motifs(net, significance = TRUE, n_perm = 100, seed = 42)
mot
Motif Census
Level: aggregate | States: 9 | Pattern: triangle
Significance: permutation (n_perm=100)

Type distribution:

210 300
  1   1

Top 2 results:
 type count expected     z      p  sig
  300    77      6.3 21.25 0.0000 TRUE
  210     7     21.6 -2.30 0.0216 TRUE
plot(mot, type = "types")
Figure 14: Triad type distribution
plot(mot, type = "significance")
Figure 15: Over- and under-represented triad types

Named subgraphs — which states form which patterns:

sg <- cograph::subgraphs(net, significance = FALSE, top = 10)
sg
NULL
plot(mot, type = "patterns")
Figure 16: MAN triad pattern diagrams

8 Higher-Order Networks

When first-order Markov models are insufficient, Nestimate detects higher-order sequential dependencies.

8.1 HON

build_hon() identifies transitions where prior context changes the outgoing distribution:

hon <- build_hon(net)
hon
Higher-Order Network (HON)
  Nodes:        719 (9 first-order states)
  Edges:        2855
  Max order:    5 (requested 5)
  Min freq:     1
  Trajectories: 2000

8.2 HYPA

build_hypa() detects paths that occur significantly more or less often than expected:

hypa <- build_hypa(net)
table(hypa$scores$anomaly)

normal   over  under
  1921    546    117 
over <- hypa$scores[hypa$scores$anomaly == "over", ]
head(over[order(-over$ratio), c("path", "ratio", "observed", "expected")], 8)
                                                path    ratio observed
114         synthesis -> adapt -> monitor -> discuss 76.45996        7
386          plan -> consensus -> adapt -> consensus 57.45136        5
806          plan -> consensus -> synthesis -> adapt 48.61269        5
1457         monitor -> discuss -> plan -> consensus 39.49781        5
2530 discuss -> synthesis -> coregulate -> consensus 38.46743        5
2535      discuss -> synthesis -> coregulate -> plan 38.46743        6
822     consensus -> coregulate -> adapt -> cohesion 36.11228        6
2492   discuss -> synthesis -> cohesion -> consensus 35.18896        7
       expected
114  0.09155119
386  0.08703014
806  0.10285380
1457 0.12658930
2530 0.12998008
2535 0.15597610
822  0.16614845
2492 0.19892604

8.3 Simplicial visualization

plot_simplicial(net, max_pathways = 6, title = "Higher-Order Pathways")
Figure 17: Top higher-order pathways
plot_simplicial(net, max_pathways = 9, dismantled = TRUE, ncol = 3)
Figure 18: Individual pathway panels

9 The Dispatch Chain

Every Nestimate object routes through splot():

splot(net)      # netobject       → network plot
splot(boot)     # net_bootstrap   → stability-styled
splot(grp_net)  # netobject_group → multi-panel grid
splot(perm)     # net_permutation → difference network

All standard splot() arguments (layout, node_fill, edge_color, title, etc.) work with every object type.

References