About this tutorial
This tutorial introduces how to interface with EWSNet, a machine learning model trained to predict critical transitions, tipping points, and regime shifts (Deb et al. 2022). We will only focus on how to set up your R session to interact with EWSNet and how to interpret the output rather than the theory and mathematics underlying the model. If you are interest in those details, please refer to the EWSNet specific website and documentation or the associated publication.
NOTE This version of EWSNet differs from that published by Deb et al. (2022) in that is has been retrained using a range of time series lengths (minimum = 15). This improves the accuracy of EWSNet over a range of time series lengths but we recommend that the minimum length to be tested should be 15 data points.
Getting started
set.seed(123) #to ensure reproducible data
library(EWSmethods)
library(ggplot2)
options(timeout = max(600, getOption("timeout"))) #due to possible internet issues, increase the timeout options from 60 seconds to 600
As EWSNet has been written and developed in Python, for R to interact
with it, we need to exploit the reticulate
R package.
reticulate
provides the tools to run Python code in R and
transfer objects between the two languages but tends to run much
smoother in RStudio rather than base R. It is therefore recommended that
you use the RStudio
IDE when using the EWSNet portion of EWSmethods
.
The following sections will show how to setup and run EWSNet in
EWSmethods
before troubleshooting a few common errors
stemming from the Python-reticulate
-R interface.
1. Initialising EWSNet
Rather than requiring the user to learn reticulate
and
setup the R session themselves, EWSmethods
provides a
single function capable of checking your machine for Python, installing
it if it’s not found (along with the critical packages), creating a new
Python environment to hold these packages, and then activating that
environment when ready. To prevent the user accidentally installing
Python or packages, the function does require confirmation inputs from
the user and so needs to be run at the start of any new R
session.
For example, to create a new Python environment called
"EWSNET_env"
and install Python, the function would be
written as below. The environment name ("EWSNET_env"
) will
be critical to running the later functions.
#prepares your session using 'reticulate' and asks to install Anaconda (if no appropriate Python found) and/or a Python environment before activating that environment with the necessary Python packages
ewsnet_init(envname = "EWSNET_env", pip_ignore_installed = FALSE)
#> Error : Specified conda binary '/home/runner/.local/share/r-miniconda/bin/conda' does not exist.
If successful, you will have had to input "y"
to allow
EWSmethods
to download and activate the Python environment
and now see the message
"EWSNET_env successfully found and activated. Necessary Python packages installed"
).
If not, please refer to the Troubleshooting section at the end of the
tutorial.
To double check the environment activation, you could use
reticulate
functions to check first what environment is
active and second what Python packages have been loaded:
library(reticulate)
#print which Python environment `EWSmethods` is using
reticulate::py_config()
#> python: /home/runner/.local/share/r-miniconda/envs/test/bin/python
#> libpython: /home/runner/.local/share/r-miniconda/envs/test/lib/libpython3.10.so
#> pythonhome: /home/runner/.local/share/r-miniconda/envs/test:/home/runner/.local/share/r-miniconda/envs/test
#> version: 3.10.14 (main, May 6 2024, 19:42:50) [GCC 11.2.0]
#> numpy: /home/runner/.local/share/r-miniconda/envs/test/lib/python3.10/site-packages/numpy
#> numpy_version: 1.24.3
#>
#> NOTE: Python version was forced by use_python() function
#list all packages currently loaded in to "EWSNET_env"
py_packages <- reticulate::py_list_packages()
head(py_packages)
#> package version requirement channel
#> 1 _libgcc_mutex 0.1 _libgcc_mutex=0.1 pkgs/main
#> 2 _openmp_mutex 5.1 _openmp_mutex=5.1 pkgs/main
#> 3 absl-py 2.1.0 absl-py=2.1.0 pypi
#> 4 alabaster 1.0.0 alabaster=1.0.0 pypi
#> 5 astunparse 1.6.3 astunparse=1.6.3 pypi
#> 6 babel 2.16.0 babel=2.16.0 pypi
EWSmethods
also does not come bundled with the necessary
model weights to make predictions. This is due the size of the weight
files being ~220 MB which is not appropriate for all users of the
package. To download these weights, we can use the
ewsnet_reset()
function which can either remove
no-longer-needed weights or re/download from https://ewsnet.github.io.
ewsnet_reset(remove_weights = FALSE)
If successful, you will have had to input "y"
to allow
EWSmethods
to download the pretrained weights.
2. Predictions from EWSNet
To give an example on how to use ewsnet_predict()
we
need some test data. Here, we will use some random noise around a mean
of 0 which we expect to be predicted as
"No Transition"
.
data("simTransComms")
pre_simTransComms <- subset(simTransComms$community1,time < inflection_pt)
plot(pre_simTransComms[,3], xlab = "Year", ylab = "Density")
We then simply provide this vector to ewsnet_predict()
while also specifying the Python environment, the scaling of the data
and ensemble number (how many models to average the prediction
over).
ewsnet_prediction <- ewsnet_predict(pre_simTransComms[,3], scaling = TRUE, ensemble = 25, envname = "EWSNET_env")
ewsnet_prediction
#> [1] "Call 'ewsnet_init()' before attempting to use ewsnet_predict(), or check your spelling of envname"
Interpreting EWSNet
As with any machine learning model, interpreting prediction probabilities is difficult. In EWSNet’s case, as three possible predictions can be made - No transition, Smooth transition, Critical transition - a chance prediction is one that is approximately 0.33 (1.0 divided by 3 is ~0.33).
Therefore any probability greater than 0.33 implies a stronger than chance prediction and anything greater than 0.6 warrants serious scrutiny.
Similarly, the real world manifestation of a Smooth or Critical
transition is unclear (Kefi et al 2013, Gsell et al
2016). EWSNet therefore considers a "Smooth Transition"
prediction to indicate a directional trend in the system whereas a
"Critical Transition"
indicates a rapid non-linear change.
A "No Transition"
prediction consequently suggests a stable
period.
The below figure visually depicts the models that have been used to train these predictions and how those predictions relate to time series data.
Predictions through time
An additional way to use EWSNet is to explore how predictions change through time. By iteratively adding in new data, we can see how those predictions evolve.
For example, using our test data, we could use this code to identify transitions that may have happened in the past:
#define the range of indexes to test over
expanding_range <- 50:length(pre_simTransComms[,3])
#pre-define our out file
expanding_ewsnet <- data.frame(expanding_range, matrix(NA,ncol=3 )) |>
`colnames<-`(c("cutoff_ind","No transition",'Smooth','Critical'))
#call `ewsnet_predict()` for each index
for(i in seq_along(expanding_range)){
ews.tmp <- ewsnet_predict(pre_simTransComms[1:expanding_range[i],3],scaling = TRUE, ensemble = 25, envname = "EWSNET_env")
expanding_ewsnet[i,] <- c(expanding_range[i],ews.tmp$no_trans_prob,ews.tmp$smooth_trans_prob,ews.tmp$critical_trans_prob)
}
plot_ewsnet <- reshape(expanding_ewsnet,
direction = "long",
varying = colnames(expanding_ewsnet)[-1],
v.names = "prob",
times = colnames(expanding_ewsnet)[-1],
timevar = "Prediction") |>
sort_by(~list(cutoff_ind),decreasing = FALSE) |>
`rownames<-`(NULL)
#plot the results
ggplot(plot_ewsnet,
aes(x=cutoff_ind,y=prob)) +
geom_point(aes(col=Prediction)) + theme_bw() +
xlab("Assessment index") + ylab("Prediction probability")
Here we see how prediction probabilities fluctuate with new data, with the trends in probabilities also providing information on how the system has changed over time.
3. Finetuning EWSNet
In the circumstance where training data is available, it may be preferable to finetune EWSNet. Finetuning alters the EWSNet model weights based upon the training data in an attempt to improve predictions. For example, the user could simulate their own collapsing time series of the same length as their test data. EWSNet would then be tuned to identify features specific to the time series of interest.
An example is given below using a mock data set matched to the same
length of pre_simTransComms
- 191 data points.
x <- matrix(nrow = length(pre_simTransComms[,3]), ncol = 10)
x <- sapply(1:dim(x)[2], function(i){
x[,i] <- rnorm(length(pre_simTransComms[,3]),mean=20,sd=10)})
# create dummy data
y <- sample(0:2,10,replace = TRUE)
# create labels. 0 = no transition, 1 = smooth transition, 2 = critical transition
ewsnet_finetune(x = x, y = y, scaling = TRUE, envname = "EWSNET_env")
Each of the 25 scaled model weights have resultingly been finetuned
based upon the new training data. Calling
ewsnet_predict(scaling = T)
will therefore use these new
weights.
In this example, as the training data has been randomly generated, the prediction quality will decrease, however it goes to show how weights can be updated/improved if new data comes available.
4. Resetting EWSNet
Following finetuning, it may be desirable to reset the model weights
to their default. Using the ewsnet_reset()
function, the
user can direct EWSmethods
to the path of the default
weights (these can be redownloaded from the EWSNet github) which will
overwrite the current model weights stored by
EWSmethods
.
ewsnet_reset(remove_weights = FALSE)
You may want to remove Python downloads and environment setup by
EWSmethods
and/or any downloaded EWSNet weights. You can
achieve this using ewsnet_init()
and the
conda_refresh =
argument, and ewsnet_reset()
respectively.
conda_clean(envname = "EWSNET_env") # removes Python, its packages and the "EWSNET_env" environment
ewsnet_reset(remove_weights = TRUE) # removes any downloaded EWSNet weights
Quick reference
Function name | Purpose |
---|---|
ewsnet_init() |
Prepares the session to interface with Python. Critical first step |
ewsnet_predict() |
Using the Python environment initialised by
ewsnet_init() , builds the EWSNet model and makes
predictions from the user supplied time series |
ewsnet_finetune() |
Retrains the initial EWSNet model weights based upon new user provided training data |
ewsnet_reset() |
Overwrites the model weights with the default weights downloaded from EWSNet github |
conda_clean() |
Removes the Python installation and environment setup by
ewsnet_init()
|
Greater detail on each function can be found at the Reference page.
Troubleshooting
1. reticulate
is activating a different environment
to the one I gave to ewsnet_init()
This is the main error when using EWSmethods
. The first
solution is to simply restart the R session and rerun
ewsnet_init()
. If reticulate
is loaded before
ewsnet_init()
is run, then the default
reticulate
environment "r-reticulate"
is
activated instead of your EWSNet environment. Therefore ensure no
reticulate
command or library(reticulate)
is
run prior to ewsnet_init()
.
If the error remains and your RStudio version is >=1.4, you may
need to edit your Python interpreter settings in RStudio’s preferences.
Go to Preferences -> Python and untick “Automatically activate
project-level Python environments”. Then restart your R session and
rerun ewsnet_init()
.
The final solution we are aware of involves deactivating
reticulate
’s default behaviour in your global R environment
settings. Running bypass_reticulate_autoinit()
will disable
reticulate
’s ability to load a Python environment without a
user request. Restart your R session and rerun
ewsnet_init()
once ready.
2. ewsnet_predict()
is returning Python
errors
These errors are extremely difficult to debug through R .
Fortunately, in our experience, such errors are legacies of previous
issues such as incorrect initialising of the Python environment, the
crashing of an R session, or killing of the running function. The error
is therefore often solved by restarting the R session and rerunning
ewsnet_init()
.
If the error remains, please submit a bug report here.
3. I want to uninstall Python and its environments
conda_clean()
provides the functionality to do this:
conda_clean(envname = "envname")
.
This function will remove any downloaded Python versions, packages or environments to allow a fresh install or permanent removal.
References
Deb S., Sidheekh S., Clements C.F., Krishnan N.C. & Dutta P.S. (2022) Machine learning methods trained on simple models can predict critical transitions in complex natural systems. Royal Society Open Science, 9, 211475. doi:10.1098/rsos.211475
Gsell AS, Scharfenberger U, Özkundakci D, Walters A, Hansson LA, Janssen AB, Nõges P, Reid PC, Schindler DE, Van Donk E, Dakos V & Adrian R. (2016) Evaluating early-warning indicators of critical transitions in natural aquatic ecosystems. PNAS, 113(50):E8089-E8095. doi:10.1073/pnas.1608242113
Kéfi S., Dakos V., Scheffer M., Van Nes E.H. & Rietkerk, M. (2013) Early warning signals also precede non-catastrophic transitions. Oikos, 122: 641-648. doi:10.1111/j.1600-0706.2012.20838.x