##Introduction

Often, when constructing networks through time, nodes enter and leave the network. When this is due to a permanent removal this can add bias that might need to be corrected. In this vignette, we present some tools to correct for biases when a node is known to be absent from part of the moving window (e.g., birth only part way through a window, or died part way through a window).

The vignette is organized as follows:

  1. Trim individulas from networks where they were only partially observable.
  2. Use weighted means for network measures where nodes where only partially observable.

Load some libraries

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

##1. Trim individuals

This first method simply trims individuals from networks where they do not have the potential to be observed (i.e., they are not born yet, or have died). This method can be particularly useful when modeling node or dyad level changes across time. The netTS package provides a “trim_nodes” and “trim_dyads” function to cut time series to within first and last observations of a particular node or dyad.

First take a look without using the trim function

#calculate node degree through time
node.degree <- nodeTS(groomEvents, windowsize = days(30), windowshift = days(10), measureFun = degree)
## [1] "48 networks extracted"
#remove node degree measures when the window was beyond the first or last observation of that node (i.e., remove extrapolations). The "trim_dyads" function is the equivalent for dyadTS outputs.
node.degree.trim<-trim_nodes(node.degree, groomEvents)

#Highlight one individual
node.degree.Razo<-node.degree%>%dplyr::select(Razo,windowstart)
node.degree.trim.Razo<-node.degree.trim%>%dplyr::select(Razo,windowstart)

#reshape the data from wide to long format for plotting
m.deg<-melt(node.degree.Razo, id.vars=c("windowstart"))
m.deg.trim<-melt(node.degree.trim.Razo, id.vars=c("windowstart"))

#plot both trimmed (red) and non-trimmed (blue) time series
ggplot(m.deg, aes(y=value,x=windowstart, color=variable))+geom_line(size=4, col="blue") + geom_line(data=m.deg.trim, aes(y=value,x=windowstart, color=variable),size=2, col="red")+theme_classic()
## Warning: Removed 20 rows containing missing values (geom_path).
## Warning: Removed 24 rows containing missing values (geom_path).

##2. Weighted means

This second method is useful for graph level measures that are means of node level measures. The idea here is to take the weighted mean, where the weight for each node is the portion of time the node was available for observation within a window. E.g., if a node died half way through a window then the weight of that node would be 0.5 rather than 1.

Setup a function to calculate the weighted mean

#calculate first and last observation time for each individual
firstLast <- node_first_last(groomEvents)

#create a function that will calculate weighted mean
mean.degree.weighted <- function(x){
  
  #calculate node values (this can be any node level measure)
  node_d<-degree(x)
  
  #calculate the weighted mean based on the proportion of time within this window 
  w_mean_d<-weighted_mean(node_d, inOut=firstLast,net=x)
  
  #return the a single weighted mean value
  return(w_mean_d)
  
}


#for comparison: mean degree without weighted mean
mean.degree <- function(x){
  
  #calculate node values
  mean_d<-mean(degree(x))
  
  #return the value
  return(mean_d)
  
}

Calculate the weighted mean

#calculate non-weighted
mean_degree <- graphTS(groomEvents, windowsize = days(60), windowshift = days(10), measureFun = mean.degree)
## [1] "45 networks extracted"
#calculate weighted
mean_degree_W <- graphTS(groomEvents, windowsize = days(60), windowshift = days(10), measureFun = mean.degree.weighted)
## [1] "45 networks extracted"
#plot the two to compare
ggplot(mean_degree, aes(y=measure,x=windowstart)) + geom_line(col="blue") + geom_line(data=mean_degree_W,aes(y=measure,x=windowstart), col="red" ) + theme_classic()