spatsoc can be used in social network analysis to generate gambit of the group format data from GPS relocation data, perform data stream randomization and generate group by individual matrices.

Gambit of the group format data is generated using the grouping functions:

  • group_times
  • group_pts
  • group_lines
  • group_polys

Data stream randomization is performed using the randomizations function.

Group by individual matrices are generated using the get_gbi function.

Generate gambit of the group data

spatsoc provides users with one temporal (group_times) and three spatial (group_pts, group_lines, group_polys) functions to generate gambit of the group data from GPS relocations. Users can consider spatial grouping at three different scales combined with an appropriate temporal grouping threshold. The gambit of the group data is then used to generate a group by individual matrix and build the network.

1. Load packages and prepare data

spatsoc expects a data.table for all DT arguments and date time columns to be formatted POSIXct.

Next, we will group relocations temporally with group_times and spatially with one of group_pts, group_lines, group_polys. Note: these are mutually exclusive, only select one spatial grouping function at a time.

2. a) group_pts

Point based grouping by calculating distance between relocations in each timegroup. Depending on species and study system, relevant temporal and spatial grouping thresholds are used. In this case, relocations within 5 minutes and 50 meters are grouped together.

2. b) group_lines

Line based grouping by measuring intersection of, optionally buffered, trajectories for each individual in each timegroup. Longer temporal thresholds are used to measure, for example, intersecting daily trajectories.

Build observed network

Once we’ve created groups using group_times and one of the spatial grouping functions, we can generate a group by individual matrix.

The following code chunk showing get_gbi can be used for outputs from any of group_pts, group_lines or group_polys(area = FALSE). For the purpose of this vignette however, we will consider the outputs from group_pts (2. a)) for the following code chunk.

Note: we show this example creating the group by individual matrix and network for only 2016 to illustrate how spatsoc can be used for simpler data with no splitting of temporal or spatial subgroups (e.g.: yearly, population). See the random network section for how to use spatsoc in social network analysis for multi-year or other complex data.

3. get_gbi

Note: spatsoc::get_gbi is identical in function to asnipe::get_group_by_individual, but is more efficient (some benchmarks measuring >10x improvements) thanks to data.table::dcast.

4. asnipe::get_network

Next, we can use asnipe::get_network to build the observed social network. Ensure that the argument “data_format” is “GBI”. Use other arguments that are relevant to your analysis, here we calculate a Simple ratio index.

Data stream randomization

Three types of data stream randomization are provided by spatsoc’s randomizations function:

  • step: randomizes identities of relocations between individuals within each time step.
  • daily: randomizes identities of relocations between individuals within each day.
  • trajectory: randomizes daily trajectories within individuals (Spiegel et al. 2016).

The results of randomizations must be assigned. The function returns the id and datetime columns provided (and anything provided to splitBy). In addition, columns ‘observed’ and ‘iteration’ are returned indicating observed rows and which iteration rows correspond to (where 0 is the observed).

As with spatial grouping functions, these methods are mutually exclusive. Pick one type and rebuild the network after randomization.

Note: the coords argument is only required for trajectory type randomization, since after randomizing with this method, the ‘coords’ are needed to redo spatial grouping (with group_pts, group_lines or group_polys).

5. a) type = 'step'

'step' randomizes identities of relocations between individuals within each time step. The datetime argument expects an integer group created by group_times. The group argument expects the column name of the group generated from the spatial grouping functions.

Four columns are returned when type = 'step' along with id, datetime and splitBy columns:

  • ‘randomID’ - randomly selected ID from IDs within each time step
  • ‘observed’ - observed rows (TRUE/FALSE)
  • ‘iteration’ - which iteration rows correspond to (0 is observed)

5. b) type = 'daily'

'daily' randomizes identities of relocations between individuals within each day. The datetime argument expects a datetime POSIXct format column.

Four columns are returned when type = 'daily' along with id, datetime and splitBy columns:

  • ‘randomID’ - randomly selected ID for each day
  • ‘jul’ - julian day
  • ‘observed’ - observed rows (TRUE/FALSE)
  • ‘iteration’ - which iteration rows correspond to (0 is observed)

5. c) type = 'trajectory'

'trajectory' randomizes daily trajectories within individuals (Spiegel et al. 2016). The datetime argument expects a datetime POSIXct format column.

Five columns are returned when type = 'trajectory' along with id, datetime and splitBy columns:

  • random date time (“random” prefixed to datetime argument)
  • ‘jul’ - observed julian day
  • ‘observed’ - observed rows (TRUE/FALSE)
  • ‘iteration’ - which iteration rows correspond to (0 is observed)
  • ‘randomJul’ - random julian day relocations are swapped to from observed julian day

Build random network

Once we’ve randomized the data stream with randomizations, we can build the random network.

We will use the get_gbi function directly when type is either ‘step’ or ‘daily’. For type = 'trajectory', we will recalculate spatial groups with one of group_pts, group_lines, group_polys for the randomized data. In this case, the example shows group_pts.

Since we want to create a group by individual matrix for each random iteration (and in this case, each year), we will use mapply to work on subsets of the randomized data.

Note: building the random networks depends on the type used and therefore, the following chunks are mutually exclusive. Use the one that corresponds to the randomization type you used above.

6. a) type = 'step'

randomizations with type = 'step' returns a ‘randomID’ which should be used instead of the observed ‘ID’ to generate the group by indiviual matrix.

After get_gbi, we use asnipe::get_network to build the random network.

6. b) type = 'daily'

randomizations with type = 'step' returns a ‘randomID’ which should be used instead of the observed ‘ID’ to generate the group by indiviual matrix.

After get_gbi, we use asnipe::get_network to build the random network.

In this case, we will generate a fake column representing a “population” to show how we can translate the mapply chunk above to three (or more variables).

6. c) type = 'trajectory'

randomizations with type = 'trajectory' returns a random date time which should be used instead of the observed date time to generate random gambit of the group data.

First, we pass the randomized data to group_times using the random date time for datetime.

After get_gbi, we use asnipe::get_network to build the random network.

Network metrics

Finally, we can calculate some network metrics. Please note that there are many ways of interpreting, analyzing and measuring networks, so this will simply show one option.

7. Calculate observed network metrics

To calculate observed network metrics, use the network (net) produced in 4. from 2016 data.

8. Calculate random network metrics

With the list of random networks from 6., we can generate a list of graphs with igraph::graph.adjacency (for example) and calculate random network metrics.

This example uses the netLs created by 6. a) which was split by year and iteration.

9. Compare observed and random metrics

Instead of calculating observed and random metrics separately (shown in 7. and 8.), we can calculate metrics for both at the same time and compare.

This chunk expects the outputs from 5. a), skipping steps 6.-8.

Note: by removing the !(observed) subset from randStep performed in 6. a), we will include observed rows where iteration == 0. This will return a gbiLs where the observed and random rows are included in the same data.table.