The spatsoc
package
provides functionality for analyzing animal relocation data in time and
space to identify potential interactions among individuals and build
gambit-of-the-group data for constructing social networks.
The package contains grouping and edge list generating functions that are used for identifying spatially and temporally explicit groups from input data. In addition, we provide social network analysis functions for randomizing individual identifiers within groups, designed to test whether social networks generated from animal relocation data were based on non-random social proximity among individuals and for generating group by individual matrices.
The functions were developed for application across animal relocation data, for example, proximity based social network analyses and spatial and temporal clustering of points.
# Read in spatsoc's example data
DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc"))
# Use subset of individuals
DT <- DT[ID %in% c('H', 'I', 'J')]
# Cast character column 'datetime' as POSIXct
DT[, datetime := as.POSIXct(datetime, tz = 'UTC')]
DT <- DT[ID %chin% c('H', 'I', 'J')]
ID | X | Y | datetime | population |
---|---|---|---|---|
H | 701724.1 | 5504325 | 2016-11-01 00:00:49 | 1 |
H | 701648.5 | 5504276 | 2016-11-01 02:00:33 | 1 |
I | 711042.0 | 5506384 | 2016-11-01 00:00:24 | 1 |
I | 711229.0 | 5506446 | 2016-11-01 02:00:33 | 1 |
J | 707568.6 | 5500406 | 2016-11-01 00:00:56 | 1 |
J | 707566.5 | 5500404 | 2016-11-01 02:00:21 | 1 |
spatsoc
expects a data.table
for all of its
functions. If you have a data.frame
, you can use
data.table::setDT()
to convert it by reference. If your
data is a CSV, you can use data.table::fread()
to import it
as a data.table
.
The data consist of relocations of 3 individuals over 365 days. Using
these data, we can compare the various grouping methods available in
spatsoc
. Note: these examples will use a subset of the
data, only individuals H, I and J.
The group_times
function is used to group relocations
temporally. It is flexible to a threshold provided in units of minutes,
hours or days. Since GPS fixes taken at regular intervals have some
level of variability, we will provide a time threshold
(threshold
), to consider all fixes within this threshold
taken at the same time. Alternatively, we may want to understand
different scales of grouping, perhaps daily movement trajectories or
seasonal home range overlap.
ID | X | Y | datetime | minutes | timegroup |
---|---|---|---|---|---|
I | 711042.0 | 5506384 | 2016-11-01 00:00:24 | 0 | 1 |
H | 701724.1 | 5504325 | 2016-11-01 00:00:49 | 0 | 1 |
J | 707568.6 | 5500406 | 2016-11-01 00:00:56 | 0 | 1 |
J | 707566.5 | 5500404 | 2016-11-01 02:00:21 | 0 | 2 |
H | 701648.5 | 5504276 | 2016-11-01 02:00:33 | 0 | 2 |
I | 711229.0 | 5506446 | 2016-11-01 02:00:33 | 0 | 2 |
J | 707562.6 | 5500374 | 2016-11-01 04:00:41 | 0 | 3 |
I | 711124.0 | 5506407 | 2016-11-01 04:00:44 | 0 | 3 |
H | 701607.2 | 5504291 | 2016-11-01 04:00:54 | 0 | 3 |
A message is returned when group_times
is run again on
the same DT
, as the columns already exist in the input
DT
and will be overwritten.
## minutes, timegroup columns found in input DT and will be overwritten by this function
ID | X | Y | datetime | hours | timegroup |
---|---|---|---|---|---|
I | 711042.0 | 5506384 | 2016-11-01 00:00:24 | 0 | 1 |
H | 701724.1 | 5504325 | 2016-11-01 00:00:49 | 0 | 1 |
J | 707568.6 | 5500406 | 2016-11-01 00:00:56 | 0 | 1 |
J | 707566.5 | 5500404 | 2016-11-01 02:00:21 | 2 | 2 |
H | 701648.5 | 5504276 | 2016-11-01 02:00:33 | 2 | 2 |
I | 711229.0 | 5506446 | 2016-11-01 02:00:33 | 2 | 2 |
J | 707562.6 | 5500374 | 2016-11-01 04:00:41 | 4 | 3 |
I | 711124.0 | 5506407 | 2016-11-01 04:00:44 | 4 | 3 |
H | 701607.2 | 5504291 | 2016-11-01 04:00:54 | 4 | 3 |
## hours, timegroup columns found in input DT and will be overwritten by this function
ID | X | Y | datetime | block | timegroup |
---|---|---|---|---|---|
H | 702098.7 | 5503564 | 2016-11-01 18:00:43 | 62 | 1 |
I | 715441.6 | 5505076 | 2016-11-03 10:00:47 | 62 | 1 |
I | 714295.9 | 5505609 | 2016-11-04 16:00:21 | 62 | 1 |
J | 706992.2 | 5499685 | 2016-11-06 12:00:51 | 63 | 2 |
H | 701041.9 | 5504692 | 2016-11-08 16:00:41 | 63 | 2 |
J | 705581.0 | 5499068 | 2016-11-09 06:00:16 | 63 | 2 |
J | 706966.4 | 5499702 | 2016-11-12 12:00:13 | 64 | 3 |
J | 705779.7 | 5499300 | 2016-11-14 06:00:54 | 64 | 3 |
J | 707282.3 | 5500593 | 2016-11-14 18:00:42 | 64 | 3 |
The group_pts
function compares the relocations of all
individuals in each timegroup and groups individuals based on a distance
threshold provided by the user. The group_pts
function uses
the “chain rule” where three or more individuals that are all within the
defined threshold distance of at least one other individual are
considered in the same group. For point based spatial grouping with a
distance threshold that does not use the chain rule, see
edge_dist
below.
group_times(DT = DT, datetime = 'datetime', threshold = '15 minutes')
group_pts(DT, threshold = 50, id = 'ID', coords = c('X', 'Y'), timegroup = 'timegroup')
## block, timegroup columns found in input DT and will be overwritten by this function
ID | X | Y | timegroup | group |
---|---|---|---|---|
H | 699126.1 | 5508836 | 771 | 771 |
I | 699130.0 | 5508761 | 771 | 771 |
J | 699138.0 | 5508797 | 771 | 771 |
H | 699930.5 | 5508032 | 772 | 772 |
H | 700139.2 | 5507325 | 773 | 773 |
I | 700131.7 | 5507321 | 773 | 773 |
H | 700012.2 | 5508010 | 774 | 774 |
I | 700015.0 | 5508001 | 774 | 774 |
J | 700002.3 | 5508005 | 774 | 774 |
The group_lines
function groups individuals whose
trajectories intersect in a specified time interval. This represents a
coarser grouping method than group_pts
which can help
understand shared space at daily, weekly or other temporal
resolutions.
utm <- 32736
group_times(DT = DT, datetime = 'datetime', threshold = '1 day')
group_lines(DT, threshold = 50, projection = utm,
id = 'ID', coords = c('X', 'Y'),
timegroup = 'timegroup', sortBy = 'datetime')
## minutes, timegroup columns found in input DT and will be overwritten by this function
## group column will be overwritten by this function
ID | timegroup | group |
---|---|---|
H | 1 | 1 |
I | 1 | 121 |
J | 1 | 204 |
H | 2 | 2 |
I | 2 | 122 |
J | 2 | 205 |
H | 3 | 3 |
I | 3 | 123 |
J | 3 | 206 |
The group_polys
function groups individuals whose home
ranges intersect. This represents the coarsest grouping method, to
provide a measure of overlap across seasons, years or all available
relocations. It can either return the proportion of home range area
overlapping between individuals or simple groups. Home ranges are
calculated using adehabitatHR::kernelUD
or
adehabitatHR::mcp
. Alternatively, a simple features POLYGON
or MULTIPOLYGON object can be provided to the sfPolys
argument along with an id column.
utm <- 32736
group_times(DT = DT, datetime = 'datetime', threshold = '8 days')
group_polys(DT = DT, area = TRUE, hrType = 'mcp',
hrParams = list('percent' = 95),
projection = utm,
coords = c('X', 'Y'), id = 'ID')
## timegroup columns found in input DT and will be overwritten by this function
## Registered S3 methods overwritten by 'adehabitatMA':
## method from
## print.SpatialPixelsDataFrame sp
## print.SpatialPixels sp
ID1 | ID2 | area | proportion |
---|---|---|---|
H | H | 81071930 [m^2] | 100.00000 [percent] |
I | H | 57514743 [m^2] | 45.73709 [percent] |
J | H | 66161291 [m^2] | 49.93401 [percent] |
H | I | 57514743 [m^2] | 70.94286 [percent] |
I | I | 125750781 [m^2] | 100.00000 [percent] |
J | I | 93471355 [m^2] | 70.54578 [percent] |
H | J | 66161291 [m^2] | 81.60814 [percent] |
I | J | 93471355 [m^2] | 74.33064 [percent] |
J | J | 132497451 [m^2] | 100.00000 [percent] |
The edge_dist
function calculates the geographic
distance between between individuals within each timegroup and returns
all paired relocations within the spatial threshold.
edge_dist
uses a distance matrix like group_pts, but, in
contrast, does not use the chain rule to group relocations.
group_times(DT = DT, datetime = 'datetime', threshold = '15 minutes')
edge_dist(DT, threshold = 50, id = 'ID', coords = c('X', 'Y'), timegroup = 'timegroup', fillNA = TRUE)
## block, timegroup columns found in input DT and will be overwritten by this function
timegroup | ID1 | ID2 |
---|---|---|
158 | H | NA |
158 | I | NA |
158 | J | NA |
159 | H | I |
159 | I | H |
159 | J | NA |
160 | H | I |
160 | I | H |
160 | J | NA |
The edge_nn
function calculates the nearest neighbour to
each individual within each time group. If the optional distance
threshold is provided, it is used to limit the maximum distance between
neighbours. edge_nn
returns an edge list of each individual
and their nearest neighbour.
group_times(DT = DT, datetime = 'datetime', threshold = '15 minutes')
edge_nn(DT, id = 'ID', coords = c('X', 'Y'), timegroup = 'timegroup')
## minutes, timegroup columns found in input DT and will be overwritten by this function
timegroup | ID | NN |
---|---|---|
1 | H | J |
1 | I | J |
1 | J | I |
2 | H | J |
2 | I | J |
2 | J | I |
Package dependencies for spatsoc
are sp
,
rgeos
, igraph
, adehabitatHR
and
data.table
. data.table
provides efficient
methods for manipulating large (or small) datasets. As a result, input
DT
for all spatsoc
functions must be a
data.table
and if it isn’t, you can simply use
data.table::setDT(df)
to convert it by reference.