#### boyce index
#### functions calculating Boyce index (Hirzel et al. 2006) by Blaise Petitpierre & Frank Breiner(28.06.2013)
# fit: A vector or Raster-Layer containing the predicted suitability values
#obs: A vector containing the predicted suitability values or xy-coordinates (if fit is a Raster-Layer) of the validation points (presence records)
#### internal function calculating predicted-to-expected ratio for each class-interval
boycei <- function(interval, obs, fit) {
fit.bin <- fit
obs.bin <- obs
fit.bin[fit[] >= interval[1] & fit[] <= interval[2]] <- "i"
fit.bin[fit.bin != "i"] <- 0
obs.bin[obs[] >= interval[1] & obs[] <= interval[2]] <- "i"
obs.bin[obs.bin != "i"] <- 0
pi <- length(which(obs.bin == "i")) / length(obs)
ei <- length(which(fit.bin == "i")) / length(fit.bin)
fi <- pi / ei
return(fi)
}
#### Calculating Boyce index as in Hirzel et al. 2006
# fit: A vector or Raster-Layer containing the predicted suitability values
# obs: A vector containing the predicted suitability values or xy-coordinates (if fit is a Raster-Layer) of the validation points (presence records)
# nclass : number of classes or vector with classes threshold. If nclass=0, Boyce index is calculated with a moving window (see next parameters)
# windows.w : width of the moving window (by default 1/10 of the suitability range)
# res : resolution of the moving window (by default 100 focals)
# PEplot : if True, plot the predicted to expected ratio along the suitability class
ecospat.boyce <-
function(fit,
obs,
nclass = 0,
window.w = "default",
res = 100,
PEplot = TRUE) {
if (class(fit) == "RasterLayer") {
# if (class(obs) == "data.frame") {
if (class(obs) == "data.frame" | class(obs) == "matrix") {
obs <- raster::extract(fit, obs)
}
fit <- raster::getValues(fit)
fit <- fit[!is.na(fit)]
}
if (window.w == "default") {
window.w <- (max(fit) - min(fit)) / 10
}
interval <- c(min(fit), max(fit))
mini <- interval[1]
maxi <- interval[2]
if (nclass == 0) {
vec.mov <-
seq(
from = mini,
to = maxi - window.w,
by = (maxi - mini - window.w) / res
)
vec.mov[res + 1] <-
vec.mov[res + 1] + 1 #Trick to avoid error with closed interval in R
interval <- cbind(vec.mov, vec.mov + window.w)
} else if (length(nclass) > 1) {
vec.mov <- c(mini, nclass)
interval <- cbind(vec.mov, c(vec.mov[-1], maxi))
} else if (nclass > 0 & length(nclass) < 2) {
vec.mov <- seq(from = mini,
to = maxi,
by = (maxi - mini) / nclass)
}
f <- apply(interval, 1, boycei, obs, fit)
to.keep <- which(f != "NaN") # index to keep no NaN data
f <- f[to.keep]
if (length(f) < 2) {
b <- NA #at least two points are necessary to draw a correlation
} else {
r <-
c(1:length(f))[f != c(f[-1], FALSE)] #index to remove successive duplicates
b <-
stats::cor(f[r], vec.mov[to.keep][r], method = "spearman") # calculation of the spearman correlation (i.e. Boyce index) after removing successive duplicated values
}
HS <-
apply(interval, 1, sum) / 2 # mean habitat suitability in the moving window
HS[length(HS)] <-
HS[length(HS)] - 1 #Correction of the 'trick' to deal with closed interval
HS <- HS[to.keep] #exlude the NaN
if (PEplot == TRUE) {
plot(
HS,
f,
xlab = "Habitat suitability",
ylab = "Predicted/Expected ratio",
col = "grey",
cex = 0.75
)
points(HS[r], f[r], pch = 19, cex = 0.75)
}
results <- list(F.ratio = f,
Spearman.cor = round(b, 3),
HS = HS)
return(results)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.