{"id":19496662,"url":"https://github.com/yjunechoe/jlmerclusterperm","last_synced_at":"2025-07-09T01:12:01.225Z","repository":{"id":149899599,"uuid":"616166571","full_name":"yjunechoe/jlmerclusterperm","owner":"yjunechoe","description":"Fast cluster-based permutation test for densely-sampled, multi-level time series data (ex: eyetracking, EEG)","archived":false,"fork":false,"pushed_at":"2024-11-10T17:48:41.000Z","size":20916,"stargazers_count":11,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-10T18:35:13.206Z","etag":null,"topics":["cluster-based-permutation-test","eeg","eyetracking","mixed-effects-models","timeseries"],"latest_commit_sha":null,"homepage":"https://yjunechoe.github.io/jlmerclusterperm/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yjunechoe.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":"codemeta.json"}},"created_at":"2023-03-19T19:49:15.000Z","updated_at":"2024-11-10T17:48:45.000Z","dependencies_parsed_at":"2024-02-19T18:15:47.191Z","dependency_job_id":"4cbb9f86-adae-4774-8853-03762d2457d6","html_url":"https://github.com/yjunechoe/jlmerclusterperm","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yjunechoe%2Fjlmerclusterperm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yjunechoe%2Fjlmerclusterperm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yjunechoe%2Fjlmerclusterperm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yjunechoe%2Fjlmerclusterperm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yjunechoe","download_url":"https://codeload.github.com/yjunechoe/jlmerclusterperm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224019553,"owners_count":17242175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cluster-based-permutation-test","eeg","eyetracking","mixed-effects-models","timeseries"],"created_at":"2024-11-10T21:41:52.404Z","updated_at":"2025-04-25T22:31:23.924Z","avatar_url":"https://github.com/yjunechoe.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.align = \"center\",\n  fig.path = \"man/figures/README-\",\n  asciicast_theme = if (Sys.getenv(\"IN_PKGDOWN\") == \"true\") \"pkgdown\" else \"readme\"\n)\nasciicast::init_knitr_engine(\n  echo = TRUE,\n  echo_input = FALSE,\n  timeout = 60,\n  record_env = c(\"asciicast_cols\" = 80),\n  same_process = TRUE\n)\n```\n\n# jlmerclusterperm \u003ca href=\"https://yjunechoe.github.io/jlmerclusterperm/\"\u003e\u003cimg src=\"man/figures/logo.png\" align=\"right\" height=\"150\" /\u003e\u003c/a\u003e\n\n\u003c!-- badges: start --\u003e\n[![CRAN status](https://www.r-pkg.org/badges/version/jlmerclusterperm)](https://CRAN.R-project.org/package=jlmerclusterperm)\n[![jlmerclusterperm status badge](https://yjunechoe.r-universe.dev/badges/jlmerclusterperm)](https://yjunechoe.r-universe.dev/jlmerclusterperm)\n[![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)\n[![pkgcheck](https://github.com/yjunechoe/jlmerclusterperm/workflows/pkgcheck/badge.svg)](https://github.com/yjunechoe/jlmerclusterperm/actions?query=workflow%3Apkgcheck)\n[![Codecov test coverage](https://codecov.io/gh/yjunechoe/jlmerclusterperm/branch/main/graph/badge.svg)](https://app.codecov.io/gh/yjunechoe/jlmerclusterperm?branch=main)\n[![CRAN downloads](https://cranlogs.r-pkg.org/badges/grand-total/jlmerclusterperm)](https://cranlogs.r-pkg.org/badges/grand-total/jlmerclusterperm)\n\u003c!-- badges: end --\u003e\n\nJulia [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).\n\n```{r, echo = FALSE}\nknitr::include_graphics(\"man/figures/clusterpermute_animation.gif\", error = FALSE)\n```\n\n## Installation and usage\n\n### Zero-setup test drive\n\nAs of March 2025, **Google Colab** supports Julia. This means `{jlmerclusterperm}` *just works* out of the box. Try it out in a [demo notebook](https://colab.research.google.com/drive/1pTXGbuoQKka5Tm8qnyaHrMHs0Z-ALD7k?usp=sharing) that runs some of the code from the [Ito et al. 2018 case study vignette](https://yjunechoe.github.io/jlmerclusterperm/articles/Ito-et-al-2018.html).\n\n### Local setup\n\nInstall the released version of jlmerclusterperm from CRAN:\n\n```{r, eval = FALSE}\ninstall.packages(\"jlmerclusterperm\")\n```\n\nOr install the development version from [GitHub](https://github.com/yjunechoe/jlmerclusterperm) with:\n\n```{r, eval = FALSE}\n# install.packages(\"remotes\")\nremotes::install_github(\"yjunechoe/jlmerclusterperm\")\n```\n\nUsing `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 \u003e=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.\n\nBefore 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).\n\nSubsequent 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.\n\n```{r setup, include = FALSE}\nlibrary(jlmerclusterperm)\njlmerclusterperm_setup(cache_dir = tempdir())\n```\n\n```{asciicast setup-io}\n# Both lines must be run at the start of each new session\nlibrary(jlmerclusterperm)\njlmerclusterperm_setup()\n```\n\n\nSee 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.\n\n## Quick tour of package functionalities\n\n### Wholesale CPA with `clusterpermute()`\n\nA time series data:\n\n```{r chickweight, out.width = \"75%\"}\nchickweights \u003c- ChickWeight\nchickweights$Time \u003c- as.integer(factor(chickweights$Time))\nmatplot(\n  tapply(chickweights$weight, chickweights[c(\"Time\", \"Diet\")], mean),\n  type = \"b\", lwd = 3, ylab = \"Weight\", xlab = \"Time\"\n)\n```\n\n```{asciicast chickweight-io, include = FALSE}\nchickweights \u003c- ChickWeight\nchickweights$Time \u003c- as.integer(factor(chickweights$Time))\n```\n\nPreparing a specification object with `make_jlmer_spec()`:\n\n```{r spec, include = FALSE}\nchickweights_spec \u003c- make_jlmer_spec(\n  formula = weight ~ 1 + Diet,\n  data = chickweights,\n  subject = \"Chick\", time = \"Time\"\n)\n```\n\n```{asciicast spec-io}\nchickweights_spec \u003c- make_jlmer_spec(\n  formula = weight ~ 1 + Diet,\n  data = chickweights,\n  subject = \"Chick\", time = \"Time\"\n)\nchickweights_spec\n```\n\nCluster-based permutation test with `clusterpermute()`:\n\n```{asciicast JIT, include = FALSE}\nclusterpermute(chickweights_spec, threshold = 2.5, nsim = 2)\n```\n\n```{asciicast CPA-io}\nset_rng_state(123L)\nclusterpermute(\n  chickweights_spec,\n  threshold = 2.5,\n  nsim = 100\n)\n```\n\nIncluding random effects:\n\n```{asciicast reCPA-io}\nchickweights_re_spec \u003c- make_jlmer_spec(\n  formula = weight ~ 1 + Diet + (1 | Chick),\n  data = chickweights,\n  subject = \"Chick\", time = \"Time\"\n)\nset_rng_state(123L)\nclusterpermute(\n  chickweights_re_spec,\n  threshold = 2.5,\n  nsim = 100\n)$empirical_clusters\n```\n\n### Piecemeal approach to CPA\n\nComputing time-wise statistics of the observed data:\n\n```{r empirical_statistics, out.width = \"75%\"}\nempirical_statistics \u003c- compute_timewise_statistics(chickweights_spec)\nmatplot(t(empirical_statistics), type = \"b\", pch = 1, lwd = 3, ylab = \"t-statistic\")\nabline(h = 2.5, lty = 3)\n```\n\n```{asciicast empirical_statistics-io, include = FALSE}\nempirical_statistics \u003c- compute_timewise_statistics(chickweights_spec)\n```\n\nIdentifying empirical clusters:\n\n```{asciicast empirical_clusters}\nempirical_clusters \u003c- extract_empirical_clusters(empirical_statistics, threshold = 2.5)\nempirical_clusters\n```\n\nSimulating the null distribution:\n\n```{asciicast null_statistics}\nset_rng_state(123L)\nnull_statistics \u003c- permute_timewise_statistics(chickweights_spec, nsim = 100)\nnull_cluster_dists \u003c- extract_null_cluster_dists(null_statistics, threshold = 2.5)\nnull_cluster_dists\n```\n\nSignificance testing the cluster-mass statistic:\n\n```{asciicast calculate_clusters_pvalues}\ncalculate_clusters_pvalues(empirical_clusters, null_cluster_dists, add1 = TRUE)\n```\n\nIterating over a range of threshold values:\n\n```{asciicast walk_threshold_steps, message = FALSE}\nwalk_threshold_steps(empirical_statistics, null_statistics, steps = c(2, 2.5, 3))\n```\n\n## Acknowledgments\n\n- The paper [Maris \u0026 Oostenveld (2007)](https://doi.org/10.1016/j.jneumeth.2007.03.024) which originally proposed the cluster-based permutation analysis.\n\n- The [JuliaConnectoR](https://github.com/stefan-m-lenz/JuliaConnectoR) package for powering the R interface to Julia.\n\n- 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.\n\n- 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.\n\n## Citations\n\nIf 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.\n\nTo cite jlmerclusterperm:\n\n- 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).\n\nTo cite the cluster-based permutation test:\n\n- Maris, E., \u0026 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.\n\nTo cite the Julia programming language:\n\n- Bezanson, J., Edelman, A., Karpinski, S., \u0026 Shah, V. B. (2017). Julia: A Fresh Approach to Numerical Computing. _SIAM Review, 59_(1), 65–98. doi: 10.1137/141000671.\n\nTo cite the GLM.jl and MixedModels.jl Julia libraries, consult their Zenodo pages: \n\n- GLM: https://doi.org/10.5281/zenodo.3376013\n- MixedModels: https://zenodo.org/badge/latestdoi/9106942\n\n\n```{asciicast close-io, include = FALSE}\nJuliaConnectoR::stopJulia()\n```\n\n```{r close, include = FALSE}\nJuliaConnectoR::stopJulia()\n```\n\n```{r srr, include = FALSE}\n#' @srrstats {G1.0} References Maris \u0026 Oostenveld (2007) which originally proposed the cluster-based permutation analysis.\n#' @srrstats {G1.1} Package is an improvement over existing implementations in R (mainly in speed and interpretability).\n#'  This is explained in the readme and the case study vignettes.\n#' @srrstats {G1.2} Lifecycle is active and stable.\n#' @srrstats {G1.3} The many moving parts are explained across the readme, the function documentation, and the topics/case study vignettes.\n#'  Users are assumed to already have familiarity with (genearlized, mixed-effects) regression to use this package.\n#' @srrstats {G1.4} `roxygen2` is used throughout the package.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyjunechoe%2Fjlmerclusterperm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyjunechoe%2Fjlmerclusterperm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyjunechoe%2Fjlmerclusterperm/lists"}