/topodetective

infer topology of species interactions from time series of species abundance

Primary LanguageR

topodetective

The goal of topodetective is to infer topology of species interactions from time series of species abundance. We use a regression-based method, which can efficiently enumerate all possible topologies.

Installation

You can install the development version of InferInteractions from GitHub with:

# install.packages("devtools")
devtools::install_github("clsong/InferInteractions")

Example

This is a basic example which shows you how to solve a common problem:

library(tidyverse)
library(topodetective)

get_classic_dynamics("4_species_chaos") # choose a population dynamic
time_range <- seq(0, 50, by = .1)

set.seed(12345)
ts <- generate_time_series_LV(
  topology = topology_ground,
  state_initial = state_initial,
  time_range = time_range,
  noise = T,
  noise_level = .05
) # simulate a dynamic

plot_time_series(ts)

We then infer system parameters from time series alone. We choose all possible topologies.

reg_model <- choose_regression_model("linear") # 'lasso' and 'ridge' are also available

fitted_models <- ts %>%
  differentiate_ts() %>%
  group_split(species) %>%
  map(fit_interaction_parameters) %>%
  bind_rows(.id = 'species') %>%
  mutate(species = paste0("x", species))

We then simulate the dynamics with the inferred parameters. We compare the fit.

set.seed(123)
topology_fitted <- fitted_models %>%
  group_by(species) %>%
  top_n(3, R2) %>% 
  sample_n(1) %>%
  ungroup()

ts_simu <- simualte_fitted_dynamics(topology_fitted)
evaluate_fit(ts, ts_simu)
#> Warning in sim - obs: longer object length is not a multiple of shorter object
#> length

#> Warning in sim - obs: longer object length is not a multiple of shorter object
#> length

#> Warning in sim - obs: longer object length is not a multiple of shorter object
#> length

#> Warning in sim - obs: longer object length is not a multiple of shorter object
#> length
#> [1] 0.01567233

plot_true_vs_simu(ts, ts_simu)

The fitted topology is different from the true topology.

 library(ggraph)

bind_rows(
  topology_ground %>% 
    mutate(facet = 'Groundtruth'),
  topology_fitted %>% 
    mutate(facet = 'Fitted'),
) %>% 
  plot_interaction_topology(facet = T)