#devtools::install_github("MiriamLL/sula")
library(sula)
<-(GPS_raw) GPS_raw
Kernel UD considerations
Some things to consider before making kernel density estimations.
Intro
This post is to exemplify some considerations when calculating kernel density analyses.
Before start calculating kernel density analyses, its useful to consider some sources of error that might change your results.
For the exercises, test data is from masked boobies.
To access the data you have to install the package sula: devtools::install_github(“MiriamLL/sula”)
To manipulate the data we will use functions from the package tidyverse
library(tidyverse)
For spatial manipulations we will use functions from the packages sp and sf
library(sp)
library(sf)
For creating the polygons of kernel density we will use the package adehabitathr
library(adehabitatHR)
Individuals
Some individuals might drive kernel density calculations in one or other direction as effect of different number of recordings (or days recorded) per individual.
Unpaired
To illustrate this, lets see the calculations using together one individual sampled for 1 day and other for 5 days
Individual one day
<-GPS_raw %>%
ID_1dayfilter(IDs=='GPS01') %>%
filter(DateGMT %in% c('02/11/2017'))
Individual 5 days
<-GPS_raw %>%
ID_5daysfilter(IDs=='GPS03')
Unpaired days
<-rbind(ID_1day,ID_5days) Unpaired
Transform to spatial object.
<-as.data.frame(Unpaired)
Unpairedcoordinates(Unpaired) <- c("Longitude", "Latitude")
class(Unpaired)
Calculate kernelUD.
<-kernelUD(Unpaired[,3],h='href') UnpairedUD
Obtain polygons.
<- getverticeshr(UnpairedUD, percent = 95, unout = c("m2"))
UnpairedUD95 <- getverticeshr(UnpairedUD, percent = 50, unout = c("m2")) UnpairedUD50
Here you can check on you polygons visually.
<-st_as_sf(UnpairedUD95)
Unpaired95<-st_as_sf(UnpairedUD50) Unpaired50
ggplot()+
geom_sf(data = Unpaired95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Unpaired50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
Paired
To compare, lets now see the kernel density calculated with these same individuals but recorded at similar number of days (3 days)
<-GPS_raw %>%
ID_01filter(IDs=='GPS01') %>%
filter(DateGMT %in% c('02/11/2017','03/11/2017','04/11/2017','05/11/2017'))
<-GPS_raw %>%
ID_03filter(IDs=='GPS03') %>%
filter(DateGMT %in% c('02/11/2017','03/11/2017','04/11/2017','05/11/2017'))
<-rbind(ID_01,ID_03) Paired
Transform to spatial object.
<-as.data.frame(Paired)
Pairedcoordinates(Paired) <- c("Longitude", "Latitude")
class(Paired)
Calculate kernelUD.
<-kernelUD(Paired[,3],h='href') PairedUD
Obtain polygons.
<- getverticeshr(PairedUD, percent = 95, unout = c("m2"))
PairedUD95 <- getverticeshr(PairedUD, percent = 50, unout = c("m2")) PairedUD50
Here you can check on you polygons visually.
<-st_as_sf(PairedUD95)
Paired95<-st_as_sf(PairedUD50) Paired50
ggplot()+
geom_sf(data = Paired95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Paired50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
As you can see the resulting areas would be different.
To solve this problem, you might want to make sure to have tracking data of similar number of days or recordings.
Intervals
Do you have similar recordings in time?
If some devices have gaps, or record at different intervals, you might underestimate or overestimate specific areas.
For this example, lets see one individuals
<-GPS_raw %>%
GPS01filter(IDs=='GPS01')
Gaps.
Using the column of hours, lets extract all the recordings after 5 pm.
$Hour <- as.numeric(substr(GPS01$TimeGMT, 1, 2))
GPS01<-GPS01 %>%
Gapsfilter(Hour <= 17)
Transform to spatial object.
<-as.data.frame(Gaps)
Gapscoordinates(Gaps) <- c("Longitude", "Latitude")
Calculate kernelUD.
<-kernelUD(Gaps[,3],h='href') GapsUD
Obtain polygons.
<- getverticeshr(GapsUD, percent = 95, unout = c("m2"))
GapsUD95 <- getverticeshr(GapsUD, percent = 50, unout = c("m2")) GapsUD50
Here you can check on you polygons visually.
<-st_as_sf(GapsUD95)
Gaps95<-st_as_sf(GapsUD50) Gaps50
ggplot()+
geom_sf(data = Gaps95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Gaps50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
Complete
In contrast, the kernel density calculations without gaps would give different results.
<-GPS_raw %>%
Completefilter(IDs=='GPS01')
Transform to spatial object.
<-as.data.frame(Complete)
Completecoordinates(Complete) <- c("Longitude", "Latitude")
Calculate kernelUD.
<-kernelUD(Complete[,3],h='href') CompleteUD
Obtain polygons.
<- getverticeshr(CompleteUD, percent = 95, unout = c("m2"))
CompleteUD95 <- getverticeshr(CompleteUD, percent = 50, unout = c("m2")) CompleteUD50
Here you can check on you polygons visually.
<-st_as_sf(CompleteUD95)
Complete95<-st_as_sf(CompleteUD50) Complete50
ggplot()+
geom_sf(data = Complete95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Complete50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
To solve the problem with gaps, you can interpolate the data to fill the gaps and have similar intervals. However, caution should be taken if you have large gaps, it would create a line.
Behaviour
Do you want to know the general areas that the animal used or just where it was feeding?
It depends on your question, but if you are interested in specific behaviours, for example feeding areas, the kernel density analyses might be bring very different results than when using all movement data.
Foraging
Here, we are using only areas where the animal was foraging.
Load data
<-as.data.frame(GPS_raw)
GPS_raw<-subset(GPS_raw,GPS_raw$IDs=='GPS01') GPS01
Use an specific period
<-recortar_periodo(GPS_data=GPS01,
GPS_bcinicio='02/11/2017 18:10:00',
final='05/11/2017 14:10:00',
dia_col='DateGMT',
hora_col='TimeGMT',
formato="%d/%m/%Y %H:%M:%S")
Convert to the correct format
$tStamp<-paste(GPS_bc$DateGMT,GPS_bc$TimeGMT)
GPS_bc$tStamp <- as.POSIXct(strptime(GPS_bc$tStamp,"%d/%m/%Y %H:%M:%S"),"GMT")
GPS_bc$lon<- as.numeric(GPS_bc$Longitude)
GPS_bc$lat<- as.numeric(GPS_bc$Latitude)
GPS_bc$id <- as.factor(GPS_bc$IDs) GPS_bc
Keep only the important columns
<-GPS_bc %>%
GPS_bc::select('id','tStamp','lon','lat') dplyr
Load the package
library(EMbC)
Run the function
<-EMbC::stbc(GPS_bc[2:4],info=-1) BC_clustering
Add the behavioral classifications
$Behaviours<-(BC_clustering@A) GPS_bc
Rename it so you can understand what each behaviour means
<-mutate(GPS_bc, BC = ifelse(GPS_bc$Behaviours == "1", "Resting",
GPS_bcifelse(GPS_bc$Behaviours == "2", "Intense foraging",
ifelse(GPS_bc$Behaviours == "3", 'Travelling',
ifelse(GPS_bc$Behaviours == "4", "Relocating",
"Unknown")))))
Filter to keep only foraging
<-GPS_bc %>%
Foragingfilter(BC=='Intense foraging')
Transform to spatial object
<-as.data.frame(Foraging)
Foragingcoordinates(Foraging) <- c("lon", "lat")
Calculate kernelUD.
Note Here the href is of 0.0048 which is giving the error of subscript out of bounds Lets then better calculate using other h value
#ForagingUD<-kernelUD(Foraging[,3],h='href')
#ForagingUD95 <- getverticeshr(ForagingUD, percent = 95, unout = c("m2"))
The new h value is of 0.01
<-kernelUD(Foraging[,3],h=0.009)
ForagingUD ForagingUD
Obtain polygons.
<- getverticeshr(ForagingUD, percent = 95, unout = c("m2"))
ForagingUD95 <- getverticeshr(ForagingUD, percent = 50, unout = c("m2")) ForagingUD50
Here you can check on you polygons visually.
<-st_as_sf(ForagingUD95)
Foraging95<-st_as_sf(ForagingUD50) Foraging50
ggplot()+
geom_sf(data = Foraging95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Foraging50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
All recordings
Here, we are using all the areas.
<-GPS_bc %>%
GPS_bc::select('id','tStamp','lon','lat') dplyr
<-as.data.frame(GPS_bc)
Behascoordinates(Behas) <- c("lon", "lat")
Calculate kernelUD.
<-kernelUD(Behas,h='href')
BehasUD BehasUD
Obtain polygons.
<- getverticeshr(BehasUD, percent = 95, unout = c("m2"))
BehasUD95 <- getverticeshr(BehasUD, percent = 50, unout = c("m2")) BehasUD50
Here you can check on you polygons visually.
<-st_as_sf(BehasUD95)
Behas95<-st_as_sf(BehasUD50) Behas50
ggplot()+
geom_sf(data = Behas95,color='#006d77',fill = "#006d77",alpha=0.3,size=1)+
geom_sf(data = Behas50,color='#5f0f40',fill = "#5f0f40",alpha=0.3,size=1)+
labs(x = "Longitude", y="Latitude")+
theme_bw()
If you want to classify the behaviour, please check the post on EmBC