-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.qmd
More file actions
175 lines (128 loc) · 8.09 KB
/
README.qmd
File metadata and controls
175 lines (128 loc) · 8.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
---
format: gfm
---
<!-- README.md is generated from README.qmd. Please edit README.qmd, not README.md. -->
```{r}
#| include: false
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# experdyn <img src="man/figures/logo.png" align="right" height="180" alt="" />
[](https://github.com/RealityBending/experdyn/actions/workflows/R-CMD-check.yaml)
[](https://github.com/RealityBending/experdyn/actions/workflows/pkgdown.yaml)
**experdyn** provides tools for analysing ESM/EMA (Experience Sampling Method / Ecological Momentary Assessment) time series through the lens of **nonlinear dynamics and complexity science**.
Participants in ESM studies answer repeated short questionnaires throughout the day, producing irregularly-timed multivariate time series of psychological states (mood, arousal, stress, ...). **experdyn** offers a complete pipeline from raw timestamps to interpretable nonlinear measures.
## Why?
Most psychological analyses of ESM data focus on **means, variances, and linear relationships** - asking, for example, how a person's average mood or its day-to-day variability predicts wellbeing. These summaries are informative, but they discard the *order* of observations and therefore miss the temporal structure of the signal. Nonlinear dynamics takes a different stance: rather than summarising what a participant *is*, it asks **how a participant moves** - how its states evolve, recur, and diverge over time. Complexity science formalises this by reconstructing the participant's underlying *attractor* (its habitual trajectory through state space) and quantifying its geometry. A highly regular, periodic attractor yields low entropy and high determinism; a random, diffuse one yields the opposite. Between these extremes, healthy psychological functioning is thought to occupy a region of **bounded complexity** - flexible enough to adapt to context, yet structured enough to remain coherent. These properties are invisible to variance-based summaries but captured naturally by measures such as **multivariate sample entropy** (predictability of state-space trajectories) and **recurrence quantification analysis** (how often and in what patterns the participant revisits previous states). The result is a richer portrait of intra-individual dynamics that complements, rather than replaces, conventional approaches.
## Installation
Install the development version from GitHub:
```r
# install.packages("remotes")
remotes::install_github("RealityBending/experdyn")
```
```{r}
library(experdyn)
```
## Example data
A typical ESM dataset has a timestamp column per observation, one column identifying the participant, and one or more psychological variables. **Any numeric column other than the timestamp and participant identifier is treated as a variable** - no specific naming convention is required.
```{r data}
set.seed(42)
n_per <- 40 # observations per participant
make_participant <- function(id, t0, seed) {
set.seed(seed)
times <- t0 + cumsum(sample(c(3600, 5400, 7200), n_per, replace = TRUE))
data.frame(
Participant = id,
timestamp = times,
Valence = cumsum(rnorm(n_per, sd = 0.6)),
Arousal = cumsum(rnorm(n_per, sd = 0.4))
)
}
esm_data <- rbind(
make_participant("P01", as.POSIXct("2025-06-01 09:00:00"), seed = 1),
make_participant("P02", as.POSIXct("2025-06-01 09:15:00"), seed = 2),
make_participant("P03", as.POSIXct("2025-06-01 08:45:00"), seed = 3),
make_participant("P04", as.POSIXct("2025-06-01 08:45:00"), seed = 4)
)
head(esm_data)
```
## Preprocessing
Raw ESM data are irregularly sampled. `resample_timeseries()` detects
overnight gaps (by default > 6 h), splits data into contiguous subseries, and
interpolates each variable onto a regular 60-minute grid using natural cubic
splines (linear interpolation is also available).
```{r resample, fig.height=5}
resampled <- resample_timeseries(
esm_data,
time_col = "timestamp",
participant_col = "Participant",
target_frequency = 60,
verbose = TRUE
)
resampled$plot
```
## State-Space Embedding
Before building the state-space, choose the time delay $\tau$ (via Average Mutual Information) and embedding dimension $m$ (via False Nearest Neighbours) for each variable.
```{r embed_params, fig.height=4}
params <- estimate_embedding_parameters(resampled, plot = TRUE)
params
params$plot
```
Then, we can use `make_statespace()` to apply Takens' delay-embedding theorem: each point in the reconstructed state-space is a vector of lagged observations. In a real analysis you would pass `params$recommended_delay` and `params$recommended_dim`; here we use fixed values so the README example is reproducible regardless of any randomness in the parameter estimation step.
```{r statespace}
ss <- make_statespace(
resampled,
delay = 1,
dimensions = 2
)
ss
```
The `plot_statespace()` function projects the high-dimensional embedding to 2-D using UMAP (or PCA as a fallback) so that the attractor geometry is visible.
```{r plot_statespace, fig.height=4}
plot_statespace(ss, color_by = "ID")
```
## Indices
### Multivariate Sample Entropy (MvSampEn)
MSE quantifies the complexity (unpredictability) of the signal. Higher values indicate more irregular, less predictable dynamics.
```{r mvsampen}
mse <- compute_mvsampen(ss, r = 0.2)
mse
```
### Recurrence Quantification Analysis (RQA)
RQA characterises how often and how consistently the system revisits previous
states. Key measures:
- **RR** - Recurrence Rate: overall density of recurrences.
- **DET** - Determinism: proportion of recurrences on diagonal lines (periodic
/ predictable structure).
- **L** / **Lmax** - Mean / maximum diagonal line length.
- **ENTR** - Shannon entropy of diagonal line lengths (structural richness).
- **LAM** / **TT** - Laminarity and Trapping Time (intermittent, laminar
episodes).
```{r rqa}
rqa <- compute_rqa(ss, r = 1.5, verbose = TRUE)
rqa
```
The **recurrence plot** reveals the temporal structure at a glance: diagonal
lines indicate periodic recurrences; isolated points indicate stochastic
behaviour.
```{r plot_rqa, fig.height=4}
plot_rqa(rqa, facet_by = "participant")
```
## Roadmap
Below are candidate features and improvements planned for future releases. Contributions and suggestions welcome via [GitHub Issues](https://github.com/RealityBending/experdyn/issues).
### New complexity measures
- **Multiscale Sample Entropy (MSE)** - apply SampEn at multiple coarse-graining scales to capture complexity across timescales, as introduced by Costa et al. (2002).
- **Permutation Entropy** - ordinal-pattern based entropy; computationally lightweight and robust to noise, useful as a complement or sanity-check to MvSampEn.
- **Detrended Fluctuation Analysis (DFA)** - estimate long-range temporal correlations and fractal scaling exponents, relevant for distinguishing 1/f noise from white noise in ESM data.
- **Correlation Dimension (D2)** - estimate the fractal dimension of the reconstructed attractor via the Grassberger–Procaccia algorithm.
- **Lyapunov Exponent** - quantify the rate of divergence of nearby trajectories as a direct measure of chaotic dynamics.
### Temporal dynamics within participants
- **Windowed / rolling RQA and entropy** - slide a fixed-width window across each subseries to produce time-varying complexity trajectories, enabling study of intra-individual change across the day or week.
- **Change-point detection** - identify structural transitions in the attractor based on rolling RQA measures (e.g., sudden drop in DET indicating a phase transition).
### Performance and scalability
- **Rcpp acceleration for RQA and MvSampEn** - replace the pure-R O(n²) distance loops with compiled C++ routines via `Rcpp`, enabling routine use on longer series (n > 300).
- **Sparse / chunked distance matrix** - avoid materialising the full n×n distance matrix; enumerate recurrences on-the-fly using spatial indexing (e.g., k-d trees).