Reputation: 1
I'm working on an R script to build a correlation matrix based on values extracted from WorldClim bioclimatic layers at specific geographic coordinates (WGS84).
I have a dataset (db) with 842 obs. of 45 variables for just one specie, where each row have metadata and important spatial data in the following columns:
decimalLatitude
decimalLongitude
scientificName
Process Overview
Load the dataset
Load WorldClim raster layers (biosTotal)
Extract raster values at the point locations
Compute a correlation matrix
Run the process in parallel to improve performance The code I’m using for extraction and correlation calculation is below:
#1.- Carga de paquetes y definiciones previas:####
rm(list=ls())
list.of.packages <- c("tictoc","tidyverse","data.table","sp","raster","rgdal","parallel","devtools","snow", "doParallel")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages);lapply(list.of.packages, library, character.only=T)
if(!require(kuenm)){devtools::install_github("marlonecobos/kuenm")}
library(kuenm)
tic.clearlog()
tic("1.- Carga de paquetes y definiciones previas", log=T)
#ruta de la carpeta general, donde se encuentra toda la información y donde aparecerá la carpeta de resultados.
wd<- "C:/modelosREPTILES"
#Esta carpeta debe contener, antes de correr el script, los siguientes elementos:
##01_Bios_presente: carpeta con las 19 bios presentes
##02_Bios_futuro: carpeta con subcarpetas para cada escenario-laboratorio con las bios futuro en su carpeta correspondiente
##03_todasM_shp: carpeta con el shapefile de la M (coordenadas geográficas WGS84 -GCS_WGS84-)
##bbdd.csv: archivo csv con la base de datos en formato DwC (el nombre puede cambiarse, siempre que se especifique en la variable csv)
##maxent.jar: programa MaxENT (archivo jar)
results<- "04_Resultados_pruebaScript"#Nombre de la carpeta que se va a crear con los resultados
csv<-"Cor_hortulana0rep.csv"#Nombre del archivo con la bbdd en formato DwC
test<-0.3 # % de test
kept_JK<-FALSE #TRUE guardar modelos candidatos de modelado para JackKnife
kept_MF<- FALSE #TRUE guardar modelos candidatos de modelado final, FALSE los borra
# y guarda solo el/los finales
tiempos<- "tiempos_pruebaScript"#nombre archivo tiempos
setwd(wd) #directorio de trabajo
db<-fread(paste0(getwd(),"/", csv), sep=",", encoding="UTF-8") #lectura bd
db$family= rep("C", dim(db)[1])
db#Se extrae vector con sp a modelar segun criterio:
#Si queremos modelar todas las especies le asignamos nulo spMod<-NULL
##En este caso se filtan las de mas de 4 observaciones
## CORRE SIEMPRE DESDE AQUI CUANDO CAMBIES LA SP
spMod<-db %>% group_by(scientificName) %>% count() %>% filter(n>5)%>%
dplyr::select(scientificName) %>% pull()
##se eligen al azar 5 especies para probar
#spMod<-spMod[sample(1:length(spMod),5)] #Desbloquear esta línea para las corridas de 5 especies aleatorias, como prueba
spMod<-spMod [1:1] ## ESTA REALIZADO HASTA LA SP 4,esta en 5
### cambias los numeros que estan aun lado de los puntos por ejemplo si queires la 3 pones 3:3
write.csv(spMod, "spModeladas_pruebaScript.csv")
toc(log=T)
#2.- Carga funciones: ####
tic("2.- Carga de funciones", log=T)
numCores <- detectCores() #detecta los nucleos de CPU
carpetas<- function (db, results){ # Crea carpetas por especie
dir.create(results)
for(i in unique(db$scientificName)){
y<-paste0(substring(i,1,3),"_",
substring(i,(str_locate(i," ")[1,1]+1))) #Acronimo de la especie
dir.create(paste0(results,"/",y))
}
}
presencias<-function (db, test, results){ #Crea por especie los Training/test puntos de acuerdo a la conf. previa
for (i in unique(db$scientificName)){
y<-paste0(substring(i,1,3),"_",
substring(i,(str_locate(i," ")[1,1]+1))) #Acronimo
db_cols<- db %>% dplyr::select(scientificName,
decimalLatitude, decimalLongitude) %>% droplevels()
x<- db_cols %>% dplyr::filter(scientificName==i) %>%
rename(LATITUDE=decimalLatitude,
LONGITUDE=decimalLongitude) %>%
mutate (Clavesp=y)%>%
dplyr::select(Clavesp, LONGITUDE, LATITUDE) # seleccion columnas para MaxENT
write.csv(x,paste0(results,"/",y,"/Sp_joint.csv"), row.names = F) # Archivo joint
train<-1-test
Sp_test<-x[sample(1:nrow(x), nrow(x)*test), ]
Sp_train<-x[sample(1:nrow(x), nrow(x)*train), ]
write.csv(Sp_test, paste0(results,"/",y,"/Sp_test.csv"), row.names = F)
write.csv(Sp_train, paste0(results,"/",y,"/Sp_train.csv"), row.names = F)
}
} #funcion que permite a partir de df en DwC, %test y carpeta donde colocar resultados,
#genera una carpeta por especie y en cada una de ellas un csv con todos los registros, train y test con el formato para MaxENT
#Seleccionar las BIOS a partir de la matriz de correlacion
F_SVal<-function(i,matrizCorr,JK){
vec=matrizCorr[i,]
p=which(abs(vec)>0.85) #Porcentaje aceptado de umbral en el valor de correlación
vm=data.frame(valores=JK[p],pos=p)
vm$pos[which(vm$valores==max(vm$valores))]
}
colocarMaxEnt<- function (from= "maxent.jar", to=results){ #Copia Maxent en cada una de las carpetas de las especies
for (i in sp){
file.copy(from= "maxent.jar", to= paste0(results, "/", i))
}
} #Coloca maxEnt
organizarM<-function (allM=input, sp=sp){ #Busca la M con el nombre la especie codificada como 3letrasGénero_especie "Ade_adiastola.shp", la copia y la pega en la carpeta de la especie
for (i in sp){
l<-list.files(input,
pattern=i, full.names = T, recursive=T)
dir.create(paste0(results, "/",i, "/M_shapefile"))
file.copy(from= l,
to=paste0(results, "/",i, "/M_shapefile"))
file.rename(from=list.files(paste0(results, "/",i, "/M_shapefile"),full.names = T),
to=str_replace(list.files(paste0(results, "/",i, "/M_shapefile"),full.names = T), pattern="([.])", "_M."))
}} #organiza M en cada carpeta de sp
#MatCorrPAR2 Función para la matriz de correlación
MatCorrPAR2<- function (sp=sp, biosTotal=biosTotal , results=results) {
list.of.packages<-c("sp","raster","rgdal")#Paquetes requeridos para script
lapply(list.of.packages, library,character.only=T)
file<- read.csv(paste0(results, "/", sp ,"/Sp_joint.csv"))
shp<-SpatialPointsDataFrame(coords=file[,c(2,3)],
data=file,
proj4string=crs(biosTotal))
writeOGR(obj = shp,layer = sp,
dsn =paste0(results,"/",sp, "/Ptos_shapefile"),driver = "ESRI Shapefile", overwrite_layer = T)
M<- readOGR(paste0(results,"/",sp,"/","M_shapefile"), layer=paste0(sp,"_M"))
crop<-raster::crop(x=biosTotal, y=M)
biosM<-raster::mask(crop, M)
dir.create(paste0(results, "/", sp, "/M_var/TodasBios"), recursive=T)
lapply(names(biosM), function(x){
writeRaster (biosM[[x]], paste0(results, "/",sp, "/M_var/TodasBios/", x,".asc"))})
pointsExtract<-data.frame(raster::extract(biosM, shp))
Corr<-cor(na.omit(pointsExtract), use="complete.obs")
dir.create(paste0(results, "/", sp, "/SelecVars"), recursive=T)
write.csv(Corr, paste0(results,"/",sp,"/SelecVars/", "Corr_bios.csv"), row.names = F)
pdf(paste0(results,"/",sp,"/","M_shapefile","/","plot",sp,".pdf"))
plot(M, main=sp, lwd=3)
plot(shp, col="red",lwd=2, add=T)
dev.off()
}
preparacionG<-function(allBiosFuturo="02_Bios_futuro",results=results, G_varSet="G_var/BiosSelec", sp=sp){
for (i in sp){
listBiosSelec<-list.files(paste0(results,"/",i,"/M_var/BiosModelo/BiosSelec"),
pattern="*.asc$")
for (j in list.files(allBiosFuturo)){
dir.create(paste0(results,"/",i,"/",G_varSet,"/",j), recursive=T)
file.copy(from=paste0(allBiosFuturo,"/", j,"/", listBiosSelec),
to=paste0(results,"/",i,"/",G_varSet,"/",j))
}
}
}
#Revisar la funcion preparacionG para paralelo con foreach y %dopar%
#https://nceas.github.io/oss-lessons/parallel-computing-in-r/parallel-computing-in-r.html
toc(log=T)
#3.- Comprobaciones previas para modelamiento: ####
tic("3.- Comprobaciones previas para modelamiento", log=T)
#3.1 existe bd con campos correctos
if(nrow(db) == 0 | is.null(nrow(db))) print("No se encuentra tabla de datos")
if(nrow(db) != 0 | !is.null(nrow(db))){
if(sum(!(c("scientificName", "decimalLatitude", "decimalLongitude") %in% names(db)))!=0){
print("Revisar campos de nombre cientifico y coordenadas")
}
}
#3.2 existe carpeta bios presentes
dirs.wd<-list.files(getwd())
if(!("01_Bios_presente" %in% dirs.wd))print("Falta carpeta bios presente")
#3.3 existe carpeta bios futuro
dirs.wd<-list.files(getwd())
if(!("02_Bios_futuro" %in% dirs.wd))print("Falta carpeta bios futuro")
#3.4 existen M para las sp a modelar?
if (is.null(spMod)){especiesModelar<- unique(db$scientificName)}else {especiesModelar<-spMod}
especiesModelar_nomResum<-paste0(str_sub(especiesModelar, 1,3),"_",
str_sub(especiesModelar, str_locate(especiesModelar, " ")[,1]+1))
v<-NULL
for (i in especiesModelar_nomResum){
v1<-length(list.files("03_todasM_shp", pattern=i))<3
if(v1){print(paste0("La especie ", i, " no tiene una M correcta"))}
v<-c(v,v1)
if(sum(v)==0)cat("Todas las sp a modelar tienen M correcta")
}
toc(log=T)
#4.- Preparacion carpetas sp y archivos de presencias a partir de bbdd ####
tic("4.-Preparacion carpetas sp y archivos de presencias a partir de bbdd", log=T)
#Genero una columna (Si/No) con las sp a modelar
if(!is.null(spMod)){db<- db %>% mutate(Modelar=ifelse(scientificName %in% spMod,"Si", "No"))
}else{db<- db %>% mutate(Modelar="Si")}
db_filtro<- db %>% filter(Modelar=="Si") %>%
droplevels()#Filtro sp validadas no modeladas
carpetas(db_filtro, results)
presencias(db_filtro, test, results)
#Se coloca cada M en su carpeta correspondiente
sp<-list.dirs(results, full.names = F, recursive = F)
input<- "03_todasM_shp"
organizarM(input, sp)
#Colocacion maxENt en cada sp
colocarMaxEnt(from= "maxent.jar", to=results)
toc(log=T)
#5.- Matriz correlacion: carga de bios como stack. cortar M, extraccion valores bios y mat correlacion####
tic("5.- Matriz correlacion", log=T)
pathBios<- list.files(paste0("01_Bios_presente","/"),
pattern= "*.asc$", full.names=T, recursive=T)[c(-8,-9,-18,-19)] #Recomendacion de quitar estas variables
biosTotal<- raster::stack(pathBios)
crs(biosTotal)<-CRS("+proj=longlat +ellps=WGS84")
cl<-makeCluster(numCores)
clusterApply(cl,sp, MatCorrPAR2, biosTotal=biosTotal, results=results)
stopCluster(cl)
toc(log=T)
time1<-as.data.frame(unlist(tic.log()))
timeOK1<-separate(time1,
col="unlist(tic.log())",
c("operacion", "tiempo_seg", "2"), sep=" sec |//: ") %>%
dplyr::select(-"2") %>% mutate(tiempo_seg = as.numeric(tiempo_seg),
tiempo_min=ifelse(!is.na(tiempo_seg), tiempo_seg/60,NAS),
tiempo_h=ifelse(!is.na(tiempo_min), tiempo_min/60, NA))
write.csv(timeOK1, paste0(results, "/tiempos.csv"))
When running this code, I get the following error:
Error in checkForRemoteErrors(val) :
one node produced an error: Argumento NA/NaN
I’ve already tried the following without success:
Checked for NA values in the coordinates (decimalLatitude, decimalLongitude) and removed them.
Verified that all points fall within the raster extent (xmin, xmax, ymin, ymax).
Checked if extract(biosTotal, coords) returns NA values and filtered records with complete.cases().
Ran the function without parallelization, and in some cases, it works, suggesting that the issue may be specific to certain records or species.
Question
What could be causing this error? How can I better handle this issue when running the process in parallel?
Rversion: 4.2.2
Any help is greatly appreciated!
Upvotes: 0
Views: 18
Reputation: 47481
I have a dataset (db) with 842 obs. of 45 variables
Can you use this example data set to illustrate your problem?
set.seed(221)
db <- matrix(runif(842*45), ncol=45)
Run the process in parallel to improve performance
Why, if this takes no time at all?
system.time(x <- cor(db))
# user system elapsed
# 0 0 0
Upvotes: 0