Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/yjunechoe/jlmerclusterperm

Fast cluster-based permutation test for densely-sampled, multi-level time series data (ex: eyetracking, EEG)
https://github.com/yjunechoe/jlmerclusterperm

cluster-based-permutation-test eeg eyetracking mixed-effects-models timeseries

Last synced: 2 months ago
JSON representation

Fast cluster-based permutation test for densely-sampled, multi-level time series data (ex: eyetracking, EEG)

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.align = "center",
fig.path = "man/figures/README-",
asciicast_theme = if (Sys.getenv("IN_PKGDOWN") == "true") "pkgdown" else "readme"
)
asciicast::init_knitr_engine(
echo = TRUE,
echo_input = FALSE,
timeout = 60,
record_env = c("asciicast_cols" = 80),
same_process = TRUE
)
```

# jlmerclusterperm

[![CRAN status](https://www.r-pkg.org/badges/version/jlmerclusterperm)](https://CRAN.R-project.org/package=jlmerclusterperm)
[![jlmerclusterperm status badge](https://yjunechoe.r-universe.dev/badges/jlmerclusterperm)](https://yjunechoe.r-universe.dev/jlmerclusterperm)
[![R-CMD-check](https://github.com/yjunechoe/jlmerclusterperm/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/yjunechoe/jlmerclusterperm/actions/workflows/R-CMD-check.yaml)
[![pkgcheck](https://github.com/yjunechoe/jlmerclusterperm/workflows/pkgcheck/badge.svg)](https://github.com/yjunechoe/jlmerclusterperm/actions?query=workflow%3Apkgcheck)
[![Codecov test coverage](https://codecov.io/gh/yjunechoe/jlmerclusterperm/branch/main/graph/badge.svg)](https://app.codecov.io/gh/yjunechoe/jlmerclusterperm?branch=main)
[![CRAN downloads](https://cranlogs.r-pkg.org/badges/grand-total/jlmerclusterperm)](https://cranlogs.r-pkg.org/badges/grand-total/jlmerclusterperm)

Julia [GLM.jl](https://github.com/JuliaStats/GLM.jl) and [MixedModels.jl](https://github.com/JuliaStats/MixedModels.jl) based implementation of the cluster-based permutation test for time series data, powered by [JuliaConnectoR](https://github.com/stefan-m-lenz/JuliaConnectoR).

```{r, echo = FALSE}
knitr::include_graphics("man/figures/clusterpermute_animation.gif", error = FALSE)
```

## Installation and usage

Install the released version of jlmerclusterperm from CRAN:

```{r, eval = FALSE}
install.packages("jlmerclusterperm")
```

Or install the development version from [GitHub](https://github.com/yjunechoe/jlmerclusterperm) with:

```{r, eval = FALSE}
# install.packages("remotes")
remotes::install_github("yjunechoe/jlmerclusterperm")
```

Using `jlmerclusterperm` requires a prior installation of the Julia programming language, which can be downloaded from either the [official website](https://julialang.org/) or using the command line utility [juliaup](https://github.com/JuliaLang/juliaup). Julia version >=1.8 is required and [1.9](https://julialang.org/blog/2023/04/julia-1.9-highlights/#caching_of_native_code) or higher is preferred for the substantial speed improvements.

Before using functions from `jlmerclusterperm`, an initial setup is required via calling `jlmerclusterperm_setup()`. The very first call on a system will install necessary dependencies (this only happens once and takes around 10-15 minutes).

Subsequent calls to `jlmerclusterperm_setup()` incur a small overhead of around 30 seconds, plus slight delays for first-time function calls. You pay up front for start-up and warm-up costs and get blazingly-fast functions from the package.

```{r setup, include = FALSE}
library(jlmerclusterperm)
jlmerclusterperm_setup(cache_dir = tempdir())
```

```{asciicast setup-io}
# Both lines must be run at the start of each new session
library(jlmerclusterperm)
jlmerclusterperm_setup()
```

See the [Get Started](https://yjunechoe.github.io/jlmerclusterperm/articles/jlmerclusterperm.html) page on the [package website](https://yjunechoe.github.io/jlmerclusterperm/) for background and tutorials.

## Quick tour of package functionalities

### Wholesale CPA with `clusterpermute()`

A time series data:

```{r chickweight, out.width = "75%"}
chickweights <- ChickWeight
chickweights$Time <- as.integer(factor(chickweights$Time))
matplot(
tapply(chickweights$weight, chickweights[c("Time", "Diet")], mean),
type = "b", lwd = 3, ylab = "Weight", xlab = "Time"
)
```

```{asciicast chickweight-io, include = FALSE}
chickweights <- ChickWeight
chickweights$Time <- as.integer(factor(chickweights$Time))
```

Preparing a specification object with `make_jlmer_spec()`:

```{r spec, include = FALSE}
chickweights_spec <- make_jlmer_spec(
formula = weight ~ 1 + Diet,
data = chickweights,
subject = "Chick", time = "Time"
)
```

```{asciicast spec-io}
chickweights_spec <- make_jlmer_spec(
formula = weight ~ 1 + Diet,
data = chickweights,
subject = "Chick", time = "Time"
)
chickweights_spec
```

Cluster-based permutation test with `clusterpermute()`:

```{asciicast JIT, include = FALSE}
clusterpermute(chickweights_spec, threshold = 2.5, nsim = 2)
```

```{asciicast CPA-io}
set_rng_state(123L)
clusterpermute(
chickweights_spec,
threshold = 2.5,
nsim = 100
)
```

Including random effects:

```{asciicast reCPA-io}
chickweights_re_spec <- make_jlmer_spec(
formula = weight ~ 1 + Diet + (1 | Chick),
data = chickweights,
subject = "Chick", time = "Time"
)
set_rng_state(123L)
clusterpermute(
chickweights_re_spec,
threshold = 2.5,
nsim = 100
)$empirical_clusters
```

### Piecemeal approach to CPA

Computing time-wise statistics of the observed data:

```{r empirical_statistics, out.width = "75%"}
empirical_statistics <- compute_timewise_statistics(chickweights_spec)
matplot(t(empirical_statistics), type = "b", pch = 1, lwd = 3, ylab = "t-statistic")
abline(h = 2.5, lty = 3)
```

```{asciicast empirical_statistics-io, include = FALSE}
empirical_statistics <- compute_timewise_statistics(chickweights_spec)
```

Identifying empirical clusters:

```{asciicast empirical_clusters}
empirical_clusters <- extract_empirical_clusters(empirical_statistics, threshold = 2.5)
empirical_clusters
```

Simulating the null distribution:

```{asciicast null_statistics}
set_rng_state(123L)
null_statistics <- permute_timewise_statistics(chickweights_spec, nsim = 100)
null_cluster_dists <- extract_null_cluster_dists(null_statistics, threshold = 2.5)
null_cluster_dists
```

Significance testing the cluster-mass statistic:

```{asciicast calculate_clusters_pvalues}
calculate_clusters_pvalues(empirical_clusters, null_cluster_dists, add1 = TRUE)
```

Iterating over a range of threshold values:

```{asciicast walk_threshold_steps, message = FALSE}
walk_threshold_steps(empirical_statistics, null_statistics, steps = c(2, 2.5, 3))
```

## Acknowledgments

- The paper [Maris & Oostenveld (2007)](https://doi.org/10.1016/j.jneumeth.2007.03.024) which originally proposed the cluster-based permutation analysis.

- The [JuliaConnectoR](https://github.com/stefan-m-lenz/JuliaConnectoR) package for powering the R interface to Julia.

- The Julia packages [GLM.jl](https://github.com/JuliaStats/GLM.jl) and [MixedModels.jl](https://github.com/JuliaStats/MixedModels.jl) for fast implementations of (mixed effects) regression models.

- Existing implementations of CPA in R ([permuco](https://jaromilfrossard.github.io/permuco/), [permutes](https://cran.r-project.org/package=permutes), etc.) whose designs inspired the CPA interface in jlmerclusterperm.

## Citations

If you use jlmerclusterperm for cluster-based permutation test with mixed-effects models in your research, please cite one (or more) of the following as you see fit.

To cite jlmerclusterperm:

- Choe, J. (`r format(Sys.Date(), "%Y")`). jlmerclusterperm: Cluster-Based Permutation Analysis for Densely Sampled Time Data. R package version `r as.character(utils::packageVersion('jlmerclusterperm'))`. [10.32614/CRAN.package.jlmerclusterperm](https://doi.org/10.32614/CRAN.package.jlmerclusterperm).

To cite the cluster-based permutation test:

- Maris, E., & Oostenveld, R. (2007). Nonparametric statistical testing of EEG- and MEG-data. _Journal of Neuroscience Methods, 164_, 177–190. doi: 10.1016/j.jneumeth.2007.03.024.

To cite the Julia programming language:

- Bezanson, J., Edelman, A., Karpinski, S., & Shah, V. B. (2017). Julia: A Fresh Approach to Numerical Computing. _SIAM Review, 59_(1), 65–98. doi: 10.1137/141000671.

To cite the GLM.jl and MixedModels.jl Julia libraries, consult their Zenodo pages:

- GLM: https://doi.org/10.5281/zenodo.3376013
- MixedModels: https://zenodo.org/badge/latestdoi/9106942

```{asciicast close-io, include = FALSE}
JuliaConnectoR::stopJulia()
```

```{r close, include = FALSE}
JuliaConnectoR::stopJulia()
```

```{r srr, include = FALSE}
#' @srrstats {G1.0} References Maris & Oostenveld (2007) which originally proposed the cluster-based permutation analysis.
#' @srrstats {G1.1} Package is an improvement over existing implementations in R (mainly in speed and interpretability).
#' This is explained in the readme and the case study vignettes.
#' @srrstats {G1.2} Lifecycle is active and stable.
#' @srrstats {G1.3} The many moving parts are explained across the readme, the function documentation, and the topics/case study vignettes.
#' Users are assumed to already have familiarity with (genearlized, mixed-effects) regression to use this package.
#' @srrstats {G1.4} `roxygen2` is used throughout the package.
```