Del ejercicio pasado, tenemos que importar los objetos nuevamente
# datos
#1_ todos los datos
#datos = st_read("tricahue.gpkg")
#2_ datos del norte
datos = st_read("tricahueNorte.gpkg")
## Reading layer `tricahueNorte' from data source
## `C:\Users\lenovo\Documents\1.ICON\7. SEPTIMO SEMESTRE ICON\ECOLOGIA DE PAISAJES\ACTIVIDADES\practicoModelos\tricahueNorte.gpkg'
## using driver `GPKG'
## Simple feature collection with 859 features and 3 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -71.63031 ymin: -31.00513 xmax: -70.37606 ymax: -28.73471
## Geodetic CRS: WGS 84
#3_datos del sur
#datos = st_read("tricahueSur.gpkg")
# raster con (todo) Bioclim para el área
Bioclim = rast("Bioclim_raster.tif")
#rasterVariablesAmbientales
#1_ todos los datos
#Var_ambientales = read.csv("Var_ambientalesTODO.csv",row.names = 1)
#2_ datos del SUR
Var_ambientalesS = read.csv("Var_ambientalesSUR.csv",row.names = 1)
#3_datos del NORTE
Var_ambientalesN = read.csv("Var_ambientalesNORTE.csv",row.names = 1)
Necesitamos generar datos de pseudo-ausencias para evaluar sitios donde no se ha encontrado tricahue. Para eso generaremos puntos aleatorios en la misma cantidad de ocurrencias descargadas de GBIF.
Luego, combinamos con los datos de variables climáticas obtenidas para generar un objeto con todas las variables climáticaspara los sitios de presencias y de preudo-ausencias.
#NORTEEEE------------------
p_load(dismo)
# setting random seed to always create the same
# random set of points for this example
set.seed(69)
backgrN <- dismo::randomPoints(raster::stack(Bioclim), nrow(Var_ambientalesN)/2)
## Warning in dismo::randomPoints(raster::stack(Bioclim),
## nrow(Var_ambientalesN)/2): generated random points = 0.388824214202561 times
## requested number
pseudo_ausenciasN <- extract(Bioclim[[names(Var_ambientalesN)]], backgrN) # restringimos extraccion a capas bioclimaticas de interes
#presenciasN <- c(rep(1, nrow(pseudo_ausenciasN)), rep(0, nrow(Var_ambientalesN)))
#mde_dataN <- data.frame(cbind(presenciasN, rbind(Var_ambientalesN,pseudo_ausenciasN)))
presenciasN <- c(rep(1, nrow(Var_ambientalesN)),rep(0, nrow(pseudo_ausenciasN)))
mde_dataN <- data.frame(cbind(presenciasN, rbind(Var_ambientalesN,pseudo_ausenciasN)))
#SUUUURR-----------------
p_load(dismo)
# setting random seed to always create the same
# random set of points for this example
set.seed(69)
backgrS <- dismo::randomPoints(raster::stack(Bioclim), nrow(Var_ambientalesS)/2)
pseudo_ausenciasS <- extract(Bioclim[[names(Var_ambientalesS)]], backgrS) # restringimos extraccion a capas bioclimaticas de interes
#presenciasS <- c(rep(1, nrow(pseudo_ausenciasS)), rep(0, nrow(Var_ambientalesS)))
#mde_dataS <- data.frame(cbind(presenciasS, rbind(Var_ambientalesS,pseudo_ausenciasS)))
presenciasS <- c(rep(1, nrow(Var_ambientalesS)),rep(0, nrow(pseudo_ausenciasS)))
vc <- rbind(Var_ambientalesS,pseudo_ausenciasS)
# mde_dataS <- data.frame(cbind(presenciasS, rbind(Var_ambientalesS,pseudo_ausenciasS)))
mde_dataS <- data.frame(cbind(presenciasS, vc))
Ahora que tenemos datos climáticos para nuestros puntos de presencia
y pseudoausencia en el objeto mde_data
, vamos a construir
nuestro modelo utilizando sólo una parte de nuestros datos, y
utilizaremos los datos de testeo para evaluar después el
rendimiento del modelo con el set de validación.
Separamos entonces nuestros datos en un conjunto de entrenamiento, o testeo (i.e. datos utilizados para construir el modelo) y un conjunto de prueba, o validación (i.e. los datos utilizados para evaluar el modelo).
Vamos a reservar el 20% de los datos para las pruebas, por lo que
utilizaremos la función folds()
del paquete
predicts
para asignar uniformemente cada punto a un grupo
aleatorio. Para asegurarnos de que tenemos una muestra más o menos
representativa tanto de puntos de presencia como de pseudoausencia,
utilizamos la columna presencias
para indicar a
R
que nuestros datos tienen estos dos subgrupos.
#NORTEEEEE-----
p_load(predicts)
foldN <- folds(x = mde_dataN,
k = 5,
by = mde_dataN$presenciasN)
# tabla de frecuencia en cada grupo
table(foldN)
## foldN
## 1 2 3 4 5
## 205 206 204 206 205
#SUUUUUUR------
p_load(predicts)
foldS <- folds(x = mde_dataS,
k = 5,
by = mde_dataS$presenciasS)
# tabla de frecuencia en cada grupo
table(foldS)
## foldS
## 1 2 3 4 5
## 415 416 415 416 415
Dejaremos los puntos en el grupo 1 para validación y los otros grupos (i.e. 2, 3, 4 y 5) para entrenar el modelo
#NORTEEEE-----
testingN <- mde_dataN[foldN == 1, ]
trainingN <- mde_dataN[foldN != 1, ]
#SUR----
testingS <- mde_dataS[foldS == 1, ]
trainingS <- mde_dataS[foldS != 1, ]
#NORTEEEE-----
modelo_glmN <- step(glm(presenciasN ~ ., data=trainingN, family = binomial()),trace=0)
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(modelo_glmN)
##
## Call:
## glm(formula = presenciasN ~ bio14 + bio3 + bio2 + bio15, family = binomial(),
## data = trainingN)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.40976 0.00032 0.00198 0.01636 1.58534
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 55.41562 15.33328 3.614 0.000301 ***
## bio14 -7.98066 2.11850 -3.767 0.000165 ***
## bio3 -0.48936 0.20658 -2.369 0.017840 *
## bio2 -2.28741 0.63968 -3.576 0.000349 ***
## bio15 0.07345 0.02830 2.595 0.009456 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 728.484 on 814 degrees of freedom
## Residual deviance: 18.309 on 810 degrees of freedom
## (6 observations deleted due to missingness)
## AIC: 28.309
##
## Number of Fisher Scoring iterations: 17
#SUR----
modelo_glmS <- step(glm(presenciasS ~ ., data=trainingS, family = binomial()),trace=0)
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(modelo_glmS)
##
## Call:
## glm(formula = presenciasS ~ bio4 + bio6 + bio15 + bio8, family = binomial(),
## data = trainingS)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -4.1920 -0.0003 0.0614 0.1819 1.8106
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -39.773314 4.140240 -9.607 < 2e-16 ***
## bio4 0.063141 0.006507 9.704 < 2e-16 ***
## bio6 1.114972 0.137439 8.113 4.96e-16 ***
## bio15 0.212606 0.019668 10.810 < 2e-16 ***
## bio8 -1.039943 0.149996 -6.933 4.12e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2115.8 on 1661 degrees of freedom
## Residual deviance: 273.1 on 1657 degrees of freedom
## AIC: 283.1
##
## Number of Fisher Scoring iterations: 10
Con la función pa_evaluate()
, pasamos datos que
“sabemos” cuál debería ser la respuesta correcta para estos cálculos de
probabilidad. Es decir, el modelo m1
debería predecir
valores cercanos a 1 para aquellas filas que pasemos al argumento
p
(porque sabemos que los tricahues se dan en esos lugares)
y debería predecir valores cercanos a 0 para aquellas filas que pasemos
al argumento a
. Utilizamos esta información sobre el
rendimiento del modelo para determinar el valor de probabilidad que se
utilizará como límite para decir si una ubicación concreta es adecuada o
inadecuada para los tricahues.
#NORTEEEE-----
# Use testing data for model evaluation
glm_evalN <- pa_evaluate(p = testingN[testingN$presenciasN == 1, ],
a = testingN[testingN$presenciasN == 0, ],
model = modelo_glmN,
type = "response")
#SUR----
# Use testing data for model evaluation
glm_evalS <- pa_evaluate(p = testingS[testingS$presenciasS == 1, ],
a = testingS[testingS$presenciasS == 0, ],
model = modelo_glmS,
type = "response")
Con el modelo podemos generar
#NORTEEEE-----
predictionsN <- predict(Bioclim[[names(Var_ambientalesN)]], modelo_glmN, type = "response")
##
|---------|---------|---------|---------|
=========================================
plot(predictionsN, colNA='black', main ="Norte")
writeRaster(predictionsN, "PrediccionConDatosDelNorte.tif", overwrite=TRUE)
#SUR----
predictionsS <- predict(Bioclim[[names(Var_ambientalesS)]], modelo_glmS, type = "response")
##
|---------|---------|---------|---------|
=========================================
plot(predictionsS, colNA='black',main ="Sur")
writeRaster(predictionsS, "PrediccionConDatosDelSur.tif", overwrite=TRUE)
Podemos mirar el Area Bajo la Curva
#NORTEEEE-----
presence_dataN = filter(mde_dataN, presenciasN == 1)
absence_dataN = filter(mde_dataN, presenciasN == 0)
evaluationN <- evaluate(presence_dataN, absence_dataN, modelo_glmN)
tr <- dismo::threshold(evaluationN, 'spec_sens')
plot(evaluationN, 'ROC')
#SUR----
presence_dataS = filter(mde_dataS, presenciasS == 1)
absence_dataS = filter(mde_dataS, presenciasS == 0)
evaluationS <- evaluate(presence_dataS, absence_dataS, modelo_glmS)
tr <- dismo::threshold(evaluationS, 'spec_sens')
plot(evaluationS, 'ROC')
### Umbrales de distribución
Artículos relevantes: - Fieldings et al (1997) - Liu et al. (2011)
El estadístico de evaluación más común es el AUC: el área bajo la curva receiver-operating characteristic (ROC). Las curvas ROC se generan calculando la sensibilidad (tasa de verdaderos positivos) y la especificidad (tasa de verdaderos negativos) para muchos umbrales a lo largo de toda la gama de probabilidades previstas. Como veremos en el gráfico mas abajo, (1-especificidad) se traza en el eje de abscisas frente a la sensibilidad en el eje de ordenadas. El área bajo esta curva se denomina AUC. Cuanto más se desvíe la curva generada de la línea 1:1 hacia la esquina superior izquierda, mejor predice el modelo la presencia/ausencia de una especie. Si tomamos una presencia aleatoria y una ausencia aleatoria de nuestras observaciones y hacemos predicciones, el AUC puede interpretarse como la probabilidad de asignar una probabilidad de ocurrencia predicha más alta al punto de presencia que al de ausencia. Normalmente, consideramos que un AUC > 0,7 indica que las predicciones son correctas (Araujo et al. 2005).
El objeto glm_eval
, nos muestra la calidad de la
evaluación. Sin embargo, el modelo que generamos nos entrega valores
continuos como predictores (i.e. la probabilidad de ocurrencia). Por eso
necesitamos encontrar un umbral para decidir donde ocurre realmente la
especie.
# Use testing data for model evaluation
#glm_eval <- pa_evaluate(p = testing[testing$presencias == 1, ],
# a = testing[testing$presencias == 0, ],
# model = modelo_glm,
# type = "response")
Entonces, con la función pa_evaluate()
, le pasamos datos
que “sabemos” cuál debería ser la respuesta correcta para estos cálculos
de probabilidad. Es decir, el modelo modelo_glm
debería
predecir valores cercanos a 1
para aquellas filas que
pasemos al argumento p
(porque sabemos que los tricahues se
dan en esos lugares) y debería predecir valores cercanos a 0 para
aquellas filas que pasemos al argumento a
. Utilizamos esta
información sobre el rendimiento del modelo para determinar el valor de
probabilidad que se utilizará como límite para decir si una ubicación
concreta es adecuada o inadecuada para los tricahues.
El elemento thresholds de glm_eval
guarda la información
que nos permite determinar el umbral de corte. Aquí elegimos
max_spec_sens
, que establece “el umbral en el que la
suma de la sensibilidad (tasa de verdaderos positivos) y la
especificidad (tasa de verdaderos negativos) es más alta”. Para más
información, consulte la documentación de la función
pa_evaluate()
.
Una vez defiinido ese umbral, podemos mirar el AUC, o área bajo la
curva. Como sabemos, un AUC=0.5
, nos dice que el modelo se
comporta igual que si hubieramos elegido variables por simple azar,
cuando AUC=1.0
, la predicción es perfecta (y poco creible,
probablemente sobre-ajustada).
plot(glm_evalN, 'ROC')
veamos la evaluación en la proxima sección
Podemos usar distintos umbrales para definir presencias.
Se define:
#NORTEEEE-----
glm_thresholdN <- glm_evalN@thresholds$max_spec_sens
plot(predictionsN > glm_thresholdN)
#SUR----
glm_thresholdS <- glm_evalS@thresholds$max_spec_sens
plot(predictionsS > glm_thresholdS)
para comparar mapas raster usando la libreía terra
.
st = predictionsN - predictionsS
plot(st,col = terrain.colors(3))
Con estos ejercicios iremos haciendo un reporte, que será entregado el 24 de junio 2024.
Indica cual es la predicción para la distribución de C. patagus
Discute tus resultados desde las siguientes perspectivas: