Install netTS, load some libraries

#if netTS is not yet installed you can use the following code to install it from github:
#devtools::install_github("tbonne/netTS")

library(netTS)
library(lubridate)
library(ggplot2)
library(igraph)
library(reshape2)

Introduction

This vignette for the netTS package is meant to provide information on how to use permutations to compare network measures over time. It will first introduce the two pre-built methods for permutations and then introduce how a user specified function can be developed.

We use grooming data of vervet monkeys as an example:

head(groomEvents)
##     ID PartnerID                date
## 1 Laur      Malc 2015-07-01 12:32:19
## 2 Malc      Laur 2015-07-01 12:33:01
## 3 Ubun      Wall 2015-07-01 16:08:26
## 4 Wall      Ubun 2015-07-01 16:09:52
## 5 Dott      Jasm 2015-07-02 09:59:27
## 6 Jasm      Dott 2015-07-02 10:01:58

We will use mean betweenness for these examples:

mean_betweenness <- function (net) {
  md <- mean(betweenness(net))
    return(md)
}

Permutations on the events data

This first method permutes the original events data, i.e., before the construction of the network (see Farine (2017)).

#1. Extract measurements correcting for sampling effort and compare to networks constructed from permuting the events in the data frame.
net.strength <- graphTS(groomEvents[1:1200,], windowsize = days(30), windowshift = days(10), measureFun = mean_betweenness, directed=TRUE,effortFun = effort.scan, effortData = df.scans, permutationFun = perm.events, nperm=1000)
## [1] "13 networks extracted"
## [1] "perm"
#2. Plot the results
graphTS.plot(net.strength, plotCI = T)

Permutations of the edge weights

This second method permutes the weights on the network. Here the degree distribution and the distribution of weights remain the same but the specific weights for each edge are permuted.

#1. Extract measurements correcting for sampling effort and compare to networks constructed from permuting edge weights.
net.betweenness <- graphTS(groomEvents[1:1200,], windowsize = days(30), windowshift = days(10), measureFun = mean_betweenness, directed=TRUE,effortFun = effort.scan, effortData = df.scans, permutationFun = perm.edge.weights, nperm=1000)
## [1] "13 networks extracted"
## [1] "perm"
#2. Plot the results
graphTS.plot(net.betweenness, plotCI = T)

Permutations using user specified functions

In this section we develop a function to permute the data/network. This function should take as inputs a data frame of events and the measurement function used.

The netTS package also adds the following inputs from netts: 1) whether the graph should be constructed as directed (directed), 2) should it be converted to SRI values (SRI), 3) effort during this window (effortFun / effortData), 4) the number of permutations to use (nperm), the quantile range to return (probs). If any of these values can be of use in the permutation, you can simply add them as inputs to your function. For example, below we make use of “nperm” and the “effortFun” calculated in each window to estimate the permuted values.

This permutation below randomly rewires the network, keeping the degree distribution the same.

#user specified function
my.permutation.function <- function(data=df.window, measureFun=mean_betweenness, nperm){
  
  #create a network of the data within a window
  net.original <- create.a.network(data, directed=TRUE,SRI=FALSE)
  
  #vector to store the permutation measures
  Perm.measure<-vector()

  #perform a series of permutations
  for(i in 1:nperm){

    #permute edges
    net.per <- igraph::rewire(net.original, with=keeping_degseq(niter = vcount(net.original) * 10) )

    # Get measure
    Perm.measure[length(Perm.measure)+1]<- measureFun(net.per)

  }
  
  return(quantile(Perm.measure, probs = c(0.025, 0.975), na.rm=T))
}

Run the user specified permutation

#1. Extract measurements and compare to networks constructed from permuting edges.
net.betweenness.edgeP <- graphTS(groomEvents[1:1200,], windowsize = days(30), windowshift = days(10), measureFun = mean_betweenness, directed=TRUE, effortFun = effort.scan ,effortData = df.scans, permutationFun = my.permutation.function, nperm = 1000)
## [1] "13 networks extracted"
## [1] "perm"
#2. Plot the results
graphTS.plot(net.betweenness.edgeP, plotCI = T)

Note 1: The two examples above show how permuting the network in different ways can lead to very different results (i.e., no difference in the second and large difference in the third example using mean betweeness). The aim here is to show that it is possible to setup exactly how the permutation is done, facilitating better comparisons between the observed and ‘null’ networks.

Note 2: The number of permutations needed will vary based on the size of the dataset, but in general can be estimated by looking at how the values change as you increase the number of permutations. As the number of permutations increases the value should become more stable. A plot of the value by the number of permutations can help in choosing an adequate number of permutations to use.

References:

Farine, D.R. (2017) A guide to null models for animal social network analysis. Methods in Ecology and Evolution, 8, 1309-1320.