En esta sección haremos un ejercicio de modelación de riqueza de especies o modelo macroecológico (MEM en breve) en función de un conjunto de variables bioclimáticas y evaluaremos la capacidad predictiva del modelo con datos por fuera de la muestra y haremos algunas proyecciones a futuro usando escenarios de cambio climático.

Descargue los datos de aquí: https://www.dropbox.com/sh/9ks083qx3f0jm5m/AADOj-uvf3tUEGtHaBQ_1Kosa?dl=0

##rgdal, rgeos and maptools replaced by sf, stars and terra
library(raster)
## Loading required package: sp
library(sp)
library(sf)
## Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE
library(stars)
## Loading required package: abind
library(terra)
## terra 1.7.83
#library(maptools)
library(rgdal)
## Please note that rgdal will be retired during October 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
## See https://r-spatial.org/r/2023/05/15/evolution4.html and https://github.com/r-spatial/evolution
## rgdal: version: 1.6-7, (SVN revision 1203)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.0.4, released 2020/01/28
## Path to GDAL shared files: /usr/share/gdal
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
## Path to PROJ shared files: /usr/share/proj
## Linking to sp version:2.1-4
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
## 
## Attaching package: 'rgdal'
## The following object is masked from 'package:terra':
## 
##     project
library(dismo)
library(XML)
library(maps)
library(letsR)
library(plyr)
## 
## Attaching package: 'plyr'
## The following object is masked from 'package:maps':
## 
##     ozone
library(groupdata2)
#library(rgeos)
library(classInt)
library(Metrics)
library(RColorBrewer)
library(rcompanion)
## 
## Attaching package: 'rcompanion'
## The following object is masked from 'package:Metrics':
## 
##     accuracy
library(plotKML)
## plotKML version 0.8-3 (2022-06-05)
## URL: https://github.com/Envirometrix/plotKML/
library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following object is masked from 'package:terra':
## 
##     time<-
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(spdep)
## Loading required package: spData
## To access larger datasets in this package, install the spDataLarge
## package with: `install.packages('spDataLarge',
## repos='https://nowosad.github.io/drat/', type='source')`
library(lme4)
## Loading required package: Matrix
## 
## Attaching package: 'lme4'
## The following object is masked from 'package:raster':
## 
##     getData
library(reshape2)
library(usdm)

setwd("/home2/taller_R/")

Cargar shapefile con areas de distribución (extent of occurrence EOO) de todas las especies de ranas de la familia Centrolenidae (ranas de cristal).

crs.geo <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84")  # geographical, datum WGS84
mapas <-st_read("./Shapefiles/Centrolenidae_IUCN.shp")
## Reading layer `Centrolenidae_IUCN' from data source 
##   `/home2/taller_R/Shapefiles/Centrolenidae_IUCN.shp' using driver `ESRI Shapefile'
## Simple feature collection with 158 features and 28 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -100.3641 ymin: -29.32361 xmax: -37.46495 ymax: 19.56507
## Geodetic CRS:  GCS_unknown
mapas
## Simple feature collection with 158 features and 28 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -100.3641 ymin: -29.32361 xmax: -37.46495 ymax: 19.56507
## Geodetic CRS:  GCS_unknown
## First 10 features:
##       id_no                      binomial presence origin seasonal    compiler
## 1     54917          Centrolene hesperium        1      1        1 Kelsey Neam
## 2     54959         Cochranella euhystrix        1      1        1 Kelsey Neam
## 3     54979             Nymphargus phenax        1      1        1 Kelsey Neam
## 4     54979             Nymphargus phenax        1      1        1  Steve Best
## 5     54931        Centrolene peristictum        1      1        1        IUCN
## 6  78457419             Centrolene sabini        1      1        1 Kelsey Neam
## 7     54933          Centrolene pipilatum        1      1        1        IUCN
## 8  78458868       Cochranella guayasamini        1      1        1 Kelsey Neam
## 9  78903218           Chimerella corleone        1      1        1 Kelsey Neam
## 10 78926514 Hyalinobatrachium anachoretus        1      1        1 Kelsey Neam
##    year_
## 1   2018
## 2   2017
## 3   2018
## 4   2018
## 5   2008
## 6   2017
## 7   2008
## 8   2017
## 9   2018
## 10  2018
##                                                                                            citation
## 1   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 2   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 3   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 4   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 5  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 6  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 7  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 8   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 9   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 10  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
##    source dist_comm island subspecies subpop            legend tax_comm
## 1    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 2    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 3    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 4    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 5    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 6    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 7    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 8    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 9    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 10   <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
##     kingdom   phylum    class order_        family             genus category
## 1  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       EN
## 2  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE       Cochranella       CR
## 3  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Nymphargus       EN
## 4  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Nymphargus       EN
## 5  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       VU
## 6  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       VU
## 7  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       EN
## 8  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE       Cochranella       LC
## 9  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Chimerella       DD
## 10 ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE Hyalinobatrachium       EN
##    marine terrestial freshwater  SHAPE_Leng   SHAPE_Area
## 1       f          t          t  0.25286444 0.0025440442
## 2       f          t          t  0.12643222 0.0012720221
## 3       f          t          t  0.09823846 0.0007679566
## 4       f          t          t  0.09823846 0.0007679566
## 5       f          t          t 16.27430080 0.9418965598
## 6       f          t          t  0.10123419 0.0008155085
## 7       f          t          t  0.73770207 0.0117393643
## 8       f          t          t  2.62224604 0.2668484008
## 9       f          t          t  0.10662779 0.0009047232
## 10      f          t          t  0.21783713 0.0018953110
##                          species                       geometry
## 1           Centrolene_hesperium MULTIPOLYGON (((-79.08572 -...
## 2          Cochranella_euhystrix MULTIPOLYGON (((-79.06595 -...
## 3              Nymphargus_phenax MULTIPOLYGON (((-73.59147 -...
## 4              Nymphargus_phenax MULTIPOLYGON (((-73.91681 -...
## 5         Centrolene_peristictum MULTIPOLYGON (((-76.19387 4...
## 6              Centrolene_sabini MULTIPOLYGON (((-71.6086 -1...
## 7           Centrolene_pipilatum MULTIPOLYGON (((-77.89176 -...
## 8        Cochranella_guayasamini MULTIPOLYGON (((-76.0394 -7...
## 9            Chimerella_corleone MULTIPOLYGON (((-76.2782 -6...
## 10 Hyalinobatrachium_anachoretus MULTIPOLYGON (((-77.64369 -...
plot(mapas)
## Warning: plotting the first 9 out of 28 attributes; use max.plot = 28 to plot
## all

st_transform(mapas,crs = crs.geo)
## Simple feature collection with 158 features and 28 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -100.3641 ymin: -29.32361 xmax: -37.46495 ymax: 19.56507
## Geodetic CRS:  GEOGCRS["unknown",
##     DATUM["World Geodetic System 1984",
##         ELLIPSOID["WGS 84",6378137,298.257223563,
##             LENGTHUNIT["metre",1]],
##         ID["EPSG",6326]],
##     PRIMEM["Greenwich",0,
##         ANGLEUNIT["degree",0.0174532925199433],
##         ID["EPSG",8901]],
##     CS[ellipsoidal,2],
##         AXIS["longitude",east,
##             ORDER[1],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]],
##         AXIS["latitude",north,
##             ORDER[2],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]]]
## First 10 features:
##       id_no                      binomial presence origin seasonal    compiler
## 1     54917          Centrolene hesperium        1      1        1 Kelsey Neam
## 2     54959         Cochranella euhystrix        1      1        1 Kelsey Neam
## 3     54979             Nymphargus phenax        1      1        1 Kelsey Neam
## 4     54979             Nymphargus phenax        1      1        1  Steve Best
## 5     54931        Centrolene peristictum        1      1        1        IUCN
## 6  78457419             Centrolene sabini        1      1        1 Kelsey Neam
## 7     54933          Centrolene pipilatum        1      1        1        IUCN
## 8  78458868       Cochranella guayasamini        1      1        1 Kelsey Neam
## 9  78903218           Chimerella corleone        1      1        1 Kelsey Neam
## 10 78926514 Hyalinobatrachium anachoretus        1      1        1 Kelsey Neam
##    year_
## 1   2018
## 2   2017
## 3   2018
## 4   2018
## 5   2008
## 6   2017
## 7   2008
## 8   2017
## 9   2018
## 10  2018
##                                                                                            citation
## 1   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 2   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 3   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 4   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 5  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 6  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 7  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe.
## 8   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 9   IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
## 10  IUCN (International Union for Conservation of Nature), Conservation International & NatureServe
##    source dist_comm island subspecies subpop            legend tax_comm
## 1    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 2    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 3    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 4    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 5    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 6    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 7    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 8    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 9    <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
## 10   <NA>      <NA>   <NA>       <NA>   <NA> Extant (resident)     <NA>
##     kingdom   phylum    class order_        family             genus category
## 1  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       EN
## 2  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE       Cochranella       CR
## 3  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Nymphargus       EN
## 4  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Nymphargus       EN
## 5  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       VU
## 6  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       VU
## 7  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Centrolene       EN
## 8  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE       Cochranella       LC
## 9  ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE        Chimerella       DD
## 10 ANIMALIA CHORDATA AMPHIBIA  ANURA CENTROLENIDAE Hyalinobatrachium       EN
##    marine terrestial freshwater  SHAPE_Leng   SHAPE_Area
## 1       f          t          t  0.25286444 0.0025440442
## 2       f          t          t  0.12643222 0.0012720221
## 3       f          t          t  0.09823846 0.0007679566
## 4       f          t          t  0.09823846 0.0007679566
## 5       f          t          t 16.27430080 0.9418965598
## 6       f          t          t  0.10123419 0.0008155085
## 7       f          t          t  0.73770207 0.0117393643
## 8       f          t          t  2.62224604 0.2668484008
## 9       f          t          t  0.10662779 0.0009047232
## 10      f          t          t  0.21783713 0.0018953110
##                          species                       geometry
## 1           Centrolene_hesperium MULTIPOLYGON (((-79.08572 -...
## 2          Cochranella_euhystrix MULTIPOLYGON (((-79.06595 -...
## 3              Nymphargus_phenax MULTIPOLYGON (((-73.59147 -...
## 4              Nymphargus_phenax MULTIPOLYGON (((-73.91681 -...
## 5         Centrolene_peristictum MULTIPOLYGON (((-76.19387 4...
## 6              Centrolene_sabini MULTIPOLYGON (((-71.6086 -1...
## 7           Centrolene_pipilatum MULTIPOLYGON (((-77.89176 -...
## 8        Cochranella_guayasamini MULTIPOLYGON (((-76.0394 -7...
## 9            Chimerella_corleone MULTIPOLYGON (((-76.2782 -6...
## 10 Hyalinobatrachium_anachoretus MULTIPOLYGON (((-77.64369 -...
st_crs(mapas)
## Coordinate Reference System:
##   User input: GCS_unknown 
##   wkt:
## GEOGCRS["GCS_unknown",
##     DATUM["World Geodetic System 1984",
##         ELLIPSOID["WGS 84",6378137,298.257223563,
##             LENGTHUNIT["metre",1]],
##         ID["EPSG",6326]],
##     PRIMEM["Greenwich",0,
##         ANGLEUNIT["Degree",0.0174532925199433]],
##     CS[ellipsoidal,2],
##         AXIS["longitude",east,
##             ORDER[1],
##             ANGLEUNIT["Degree",0.0174532925199433]],
##         AXIS["latitude",north,
##             ORDER[2],
##             ANGLEUNIT["Degree",0.0174532925199433]]]
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:plyr':
## 
##     arrange, count, desc, failwith, id, mutate, rename, summarise,
##     summarize
## The following objects are masked from 'package:terra':
## 
##     intersect, union
## The following objects are masked from 'package:raster':
## 
##     intersect, select, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
mapas2<-mapas %>% group_by(binomial) %>% summarise()

Generar un mapa de riqueza y una matriz de presencia-ausencia (PAM) usando los mapas individuales.

PAM_centro <-lets.presab(mapas2, xmn=-100.4, xmx=-37.5, ymn=-29.3, ymx=19.6, resol=1,
                         remove.cells=T, remove.sp=T, show.matrix=FALSE,
                         crs=CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"), cover=0, presence=NULL,
                         origin=NULL, seasonal=NULL, count=FALSE)
plot(PAM_centro,main="Riqueza de especies")

PAM_centro
## 
## Class: PresenceAbsence 
## Number of species: 148 
## Number of cells: 514
## Resolution: 1, 1 (x, y)
str(PAM_centro)
## List of 3
##  $ Presence_and_Absence_Matrix: num [1:514, 1:150] -96.9 -95.9 -94.9 -96.9 -95.9 -94.9 -93.9 -92.9 -91.9 -99.9 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : NULL
##   .. ..$ : chr [1:150] "Longitude(x)" "Latitude(y)" "Celsiella revocata" "Celsiella vozmedianoi" ...
##  $ Richness_Raster            :S4 class 'SpatRaster' [package "terra"]
##  $ Species_name               : chr [1:148] "Celsiella revocata" "Celsiella vozmedianoi" "Centrolene acanthidiocephalum" "Centrolene altitudinale" ...
##  - attr(*, "class")= chr "PresenceAbsence"

Extraer raster

rr <- PAM_centro$Richness_Raster

Cargar un mapa de países (shapefile)

am <-readOGR("./Shapefiles/america_completo.shp")
## Warning in readOGR("./Shapefiles/america_completo.shp"): OGR support is
## provided by the sf and terra packages among others
## Warning in ogrListLayers(dsn = dsn): OGR support is provided by the sf and
## terra packages among others
## Warning in ogrInfo(dsn = dsn, layer = layer, encoding = encoding, use_iconv =
## use_iconv, : OGR support is provided by the sf and terra packages among others
## Warning in ogrFIDs(dsn = dsn, layer = layer): OGR support is provided by the sf
## and terra packages among others
## Warning in OGRSpatialRef(dsn, layer, morphFromESRI = morphFromESRI, dumpSRS =
## dumpSRS, : OGR support is provided by the sf and terra packages among others
## Warning in ogrListLayers(dsn): OGR support is provided by the sf and terra
## packages among others
## Warning in ogrFIDs(dsn = dsn, layer = layer): OGR support is provided by the sf
## and terra packages among others
## OGR data source with driver: ESRI Shapefile 
## Source: "/home2/taller_R/Shapefiles/america_completo.shp", layer: "america_completo"
## with 5763 features
## It has 7 fields
projection(am)<-crs.geo
color<-hcl.colors(n=100,rev = T,palette="viridis")
color<-c("white",color)
plot(rr, main="Riqueza de especies",col=color)
plot(am, add=T)

Subir capas bioclimáticas actuales y futuras

bios.act <- stack(list.files(path="./Bioclimaticos/actual/", pattern = "tif", full.names = T))
bios.fut <- stack(list.files(path="./Bioclimaticos/rcp85_2070/bc85bi70/", pattern = "tif", full.names = T))

projection(bios.act)<-crs.geo
projection(bios.fut)<-crs.geo

Extraer datos de variables ambientales para cada celda con datos de riqueza

PAM_centro_bios <- lets.addvar(PAM_centro, bios.act, fun=mean,  onlyvar = TRUE)
PAM_centro_biosF <- lets.addvar(PAM_centro, bios.fut, fun=mean,  onlyvar = TRUE)

Preparar los conjuntos de datos de riqueza de especies y variables bioclimáticas

PAM_DF <- as.data.frame(PAM_centro$Presence_and_Absence_Matrix)
a <- rowSums(PAM_DF[,c(-1:-2)])
DF_SR <- PAM_DF[,c(1:2)]
DF_SR["Riqueza"] <- a

DF_SR_Bios <- round(cbind(DF_SR, PAM_centro_bios),1)
DF_SR_BiosFut <- round(cbind(DF_SR, PAM_centro_biosF),1)

Construir el modelo de regresión. Esta parte es muy importante porque es necesario tener una buena calibración y que el modelo tenga buena capacidad de predicción de la riqueza por fuera de la muestra. Primero vamos a generar una partición aleatoria de los datos. Hay otro tipo de particiones estructuradas que se pueden usar (e.g., stratified, block, checkerboard, véase el siguiente enlace: http://cran.nexr.com/web/packages/ENMeval/vignettes/ENMeval-vignette.html#partition).

partitions <- partition(DF_SR_Bios, p=0.7)
train <- partitions[[1]]
test <- partitions[[2]]
trainDF <- as.data.frame(train)
testDF <- as.data.frame(test)

Ajustar el modelo. Usaremos una regresión lineal con el método de mínimos cuadrados ordinarios (OLS en inglés). Este método hace una estimación de los parámetros minimizando la suma de residuales al cuadrado. Es el método más sencillo.

m.ols <- lm(Riqueza~., data=trainDF[,c(-1,-2)])
summary(m.ols)
## 
## Call:
## lm(formula = Riqueza ~ ., data = trainDF[, c(-1, -2)])
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -6.9783 -1.4688 -0.1985  1.1361 12.5116 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -27.941536  10.248717  -2.726 0.006737 ** 
## bio_01_mean  -0.194774   0.207610  -0.938 0.348824    
## bio_02_mean  -0.484414   0.127040  -3.813 0.000163 ***
## bio_03_mean   0.627975   0.139426   4.504 9.19e-06 ***
## bio_04_mean  -0.016301   0.008534  -1.910 0.056947 .  
## bio_05_mean  -0.576730   2.824328  -0.204 0.838319    
## bio_06_mean   0.816060   2.823255   0.289 0.772720    
## bio_07_mean   1.043996   2.819702   0.370 0.711427    
## bio_08_mean  -0.039085   0.064273  -0.608 0.543522    
## bio_09_mean   0.079438   0.059622   1.332 0.183636    
## bio_10_mean   0.478318   0.290410   1.647 0.100476    
## bio_11_mean  -0.629217   0.394685  -1.594 0.111817    
## bio_12_mean   0.003765   0.001708   2.204 0.028179 *  
## bio_13_mean   0.066231   0.013043   5.078 6.31e-07 ***
## bio_14_mean   0.013822   0.035888   0.385 0.700363    
## bio_15_mean   0.005197   0.017303   0.300 0.764070    
## bio_16_mean  -0.036208   0.005173  -7.000 1.38e-11 ***
## bio_17_mean  -0.026636   0.013277  -2.006 0.045628 *  
## bio_18_mean   0.017046   0.002283   7.466 7.03e-13 ***
## bio_19_mean   0.005097   0.001507   3.381 0.000806 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.582 on 339 degrees of freedom
## Multiple R-squared:  0.5728, Adjusted R-squared:  0.5489 
## F-statistic: 23.93 on 19 and 339 DF,  p-value: < 2.2e-16

Generamos la predicción usando el conjunto de datos que se dejaron por fuera (fuera de la muestra).

pred.ols <- predict(m.ols, testDF)

# Comparación entre observaciones y predicciones.
par(mfrow=c(1,1))
hist(testDF$Riqueza, main="Observaciones")

hist(pred.ols, main="Predicciones (fuera de la muestra)")

nsim <- 100
mfit_ols <- list() # guarda cada modelo ajustado
rsq_ols <- list() # guarda cada R2 calculado
rmse_ols <- list() # guarda la raíz del error cuadrático medio RMSE
pred_ols <- list() # valores predichos fuera de la muestra

for (i in 1:nsim){
#
partitions <- partition(DF_SR_Bios, p=0.7)
train <- partitions[[1]]
test <- partitions[[2]]
trainDF <- as.data.frame(train)
testDF <- as.data.frame(test)

# model fit
m.ols <- lm(Riqueza~., data=trainDF[,c(-1:-2)])
mfit_ols[[i]] <- m.ols

# predictions
pred.ols <- predict(m.ols, testDF[,c(-1:-2)])
pred_ols[[i]] <- pred.ols

# metrics
rss <- sum((pred.ols - testDF$Riqueza) ^ 2)  ## suma de cuadrados residuales
tss <- sum((testDF$Riqueza - mean(testDF$Riqueza)) ^ 2)  ## suma total de cuadrados
rsq_ols[[i]] <- 1 - rss/tss # R2
rmse_ols[[i]] <- rmse(testDF$Riqueza, pred.ols) #  raíz del error cuadrático medio RMSE
}

Hacemos un histograma de los 100 valores de R2 y RMSE

bb <- cbind(as.numeric(rsq_ols), as.numeric(rmse_ols))
colnames(bb) <- c("R2", "RMSE")
v.ols <- as.data.frame(bb)

par(mfrow=c(1,2))
hist(v.ols$R2, main="R2")
hist(v.ols$RMSE, main="RMSE")

Ahora vamos a ajustar un modelo linear generalizado. Es más flexible que el OLS y permite acomodar mejorar la variación de los datos porque la variable de respuesta puede tener un tipo de distribución diferente a la Gaussiana (no normal).

# GLM
nsim <- 100
# to run models across a sample of 100 spatial folds
mfit_glm <- list() # model fitted
rsq_glm <- list() # R squared
rmse_glm <- list() # Root Mean Squared Error
pred_glm <- list() # predicciones fuera de la muestra

for (i in 1:nsim){
#
partitions <- partition(DF_SR_Bios, p=0.7)
train <- partitions[[1]]
test <- partitions[[2]]
trainDF <- as.data.frame(train)
testDF <- as.data.frame(test)

# model fit
m.glm <- glm(Riqueza~., data = trainDF[,c(-1:-2)], family=poisson())
mfit_glm[[i]] <- m.glm

# predictions
pred.glm <- predict(m.glm, newdata=testDF[,c(-1:-2)], type="response", se.fit=FALSE)
pred_glm[[i]] <- pred.glm

# metrics
rss <- sum((pred.glm - testDF$Riqueza) ^ 2)  ## suma de cuadrados residuales
tss <- sum((testDF$Riqueza - mean(testDF$Riqueza)) ^ 2)  ## suma total de cuadrados
rsq_glm[[i]] <- 1 - rss/tss # R2
rmse_glm[[i]] <- rmse(testDF$Riqueza, pred.glm) #  raíz del error cuadrático medio RMSE
}

Hacemos el histograma de los 100 valores de R2 y RMSE y comparamos el GLM con el OLS

bb <- cbind(as.numeric(rsq_glm), as.numeric(rmse_glm))
colnames(bb) <- c("R2", "RMSE")
v.glm <- as.data.frame(bb)


par(mfrow=c(1,2))
hist(v.ols$R2, main="R2 OLS")
hist(v.ols$RMSE, main="RMSE OLS")

par(mfrow=c(1,2))
hist(v.glm$R2, main="R2 GLM")
hist(v.glm$RMSE, main="RMSE GLM")

Vamos a generar unos escenarios futuros de riqueza de especies. Recuerde las diferencias entre pronóstico, predicción y proyección. Cuando hablamos de cambio climático el término adecuado es proyección o escenario futuro.

#  Proyectar a futuro
options(scipen=999) # quitamos la notación científica


m.ols <- lm(Riqueza~., data=DF_SR_Bios[,c(-1:-2)])
m.glm <- glm(Riqueza~., data=DF_SR_Bios[,c(-1:-2)], family=poisson())

pred.ols.act <- round(predict(m.ols, newdata=DF_SR_Bios[,c(-1:-2)], type="response", se.fit=FALSE),1)
pred.glm.act <- round(predict(m.glm, newdata=DF_SR_Bios[,c(-1:-2)], type="response", se.fit=FALSE),1)

pred.ols.fut <- round(predict(m.ols, newdata=DF_SR_BiosFut[,c(-1:-2)], type="response", se.fit=FALSE),1)
pred.glm.fut <- round(predict(m.glm, newdata=DF_SR_BiosFut[,c(-1:-2)], type="response", se.fit=FALSE),1)

Comparamos las ganancias y pérdidas potenciales de especies a futuro usando el modelo OLS y el GLM

pp.ols <- pred.ols.fut - pred.ols.act # negativo = pérdidas, positivo = ganancias
pp.glm <- pred.glm.fut - pred.glm.act # negativo = pérdidas, positivo = ganancias

Hacemos un dataframe con las predicciones futuras

DF_SR_Bios["pred_ols_act"] <- pred.ols.act
DF_SR_Bios["pred_ols_fut"] <- pred.ols.fut

DF_SR_Bios["pred_glm_act"] <- pred.glm.act
DF_SR_Bios["pred_glm_fut"] <- pred.glm.fut

Convertimos las predicción en formato raster

DF_SR_Bios_sp <- DF_SR_Bios
DF_SR_Bios_sp <- plyr::rename(DF_SR_Bios_sp, replace=c("Longitude(x)"="x", "Latitude(y)"="y"))
coordinates(DF_SR_Bios_sp)<- ~ x + y

class(DF_SR_Bios_sp)
## [1] "SpatialPointsDataFrame"
## attr(,"package")
## [1] "sp"
obs.r <- vect2rast(DF_SR_Bios_sp, fname = "Riqueza", cell.size=1)
obs.r  <- raster(obs.r)
projection(obs.r)<-crs.geo

ols.act.r <- vect2rast(DF_SR_Bios_sp, fname = "pred_ols_act", cell.size=1)
ols.act.r  <- raster(ols.act.r)
projection(ols.act.r)<-crs.geo

ols.fut.r <- vect2rast(DF_SR_Bios_sp, fname = "pred_ols_fut", cell.size=1)
ols.fut.r  <- raster(ols.fut.r)
projection(ols.fut.r)<-crs.geo

glm.act.r <- vect2rast(DF_SR_Bios_sp, fname = "pred_glm_act", cell.size=1)
glm.act.r  <- raster(glm.act.r)
projection(glm.act.r)<-crs.geo

glm.fut.r <- vect2rast(DF_SR_Bios_sp, fname = "pred_glm_fut", cell.size=1)
glm.fut.r  <- raster(glm.fut.r)
projection(glm.fut.r)<-crs.geo

Calculamos las diferencias entre lo actual y lo futuro

dif.ols <- ols.fut.r - ols.act.r # negativo = pérdidas, positivo = ganancias
plot(dif.ols,col=color)
plot(am, add=T)

dif.glm <- glm.fut.r - glm.act.r # negativo = pérdidas, positivo = ganancias
plot(dif.glm,col=color)
plot(am,add=T)

perd.riq.ols <- reclassify(dif.ols, c(0, Inf, 0))
perd.riq.glm <- reclassify(dif.glm, c(0, Inf, 0))

gan.riq.ols <- reclassify(dif.ols, c(-Inf, 0, 0))
gan.riq.glm <- reclassify(dif.glm, c(-Inf, 0, 0))

Hacemos unos mapas bonitos

library(viridis)
## Loading required package: viridisLite
## 
## Attaching package: 'viridis'
## The following object is masked from 'package:maps':
## 
##     unemp
par(mfrow=c(2,3))
plot(ols.act.r, main="OLS predicción", col=viridis(30))
plot(am, add=T, lwd=0.5)

plot(perd.riq.ols, main="OLS pérdidas", col=viridis(30))
plot(am, add=T, lwd=0.5)

plot(gan.riq.ols, main="OLS ganancias", col=viridis(30))
plot(am, add=T, lwd=0.5)

plot(glm.act.r, main="GLM predicción", col=viridis(30))
plot(am, add=T, lwd=0.5)

plot(perd.riq.glm, main="GLM pérdidas", col=viridis(30))
plot(am, add=T, lwd=0.5)

plot(gan.riq.glm, main="GLM ganancias", col=viridis(30))
plot(am, add=T, lwd=0.5)

Estos modelos son muy básicos porque solo incorporan variables bioclimáticas y la riqueza de especies está influenciada por otros factores. Aquí una literatura adicional recomendada al respecto en la que hemos trabajado con varios colegas para entender que determina la riqueza de especies en diferentes escalas y con diferentes grupos taxonómicos.

García-Rodríguez, A., Martínez, P.A., Oliveira, B.F., Velasco, J.A., Pyron, A & Costa, G.C. 2021. Amphibian speciation rates support a general role of mountains as biodiversity pumps. The American Naturalist. 198: E68-E79. https://doi.org/10.1086/715500

García-Rodriguez, A., Velasco, J.A, Villalobos, F & Parra, G. 2021. Effects of evolutionary time, speciation rates and local abiotic conditions on the origin and maintenance of amphibian montane diversity. Global Ecology and Biogeography 30: 674-684. https://doi.org/10.1111/geb.13249

Ochoa-Ochoa, L.,Mejía-Domínguez, N.R., Velasco, J.A., Dimitrov, D & Marske, K.A. 2020. Dimensions of Amphibian alpha diversity in the New World. Journal of Biogeography 47: 2293-2302.

Ochoa-Ochoa, L. M., Mejía-Domínguez, N.R.,Velasco, J.A, Marskea, K.A. & Rahbek, C. 2019. Amphibian functional diversity is related to precipitation stability in the New World. Global Ecology and Biogeography. 28: 1219-1229.

Velasco, J.A., Villalobos, F., Diniz-Filho, JAF., Algar, A.C., Flores-Villela, O., Kohler, G., Poe, S., Martínez-Meyer, E. 2018. Climatic and evolutionary factors shaping geographical gradients of species richness in Anolis lizards. Biological Journal of the Linnean Society 123: 615-627.

Eso es todo por ahora!