Simon
Simon

Reputation: 1

x@presence error for Species Distribution modeling

Does anybody know how to solve this problem? I'm trying to build a species Distribution model using bioclimatic variables

sdm package by Naimi, 2016 R version 4.4.1

ERROR:

model <- sdm(Species ~ ., data = sdm_data, 
    methods = c('glm', 'gam', 'gbm', 'rf', 'svm', 'mars'))

Error in x@presence : no applicable method for @ applied to an object of class "NULL"

Part of code:

bioclim_files <- list.files(pattern = "*.tif$", full.names = TRUE)
Study_Area <- st_read("shp/3Province.shp")
DEM <- rast ("shp/DEM.tif")          
DEM_crop <- crop (DEM, Study_Area)
DEM_mask <- mask (DEM_crop, Study_Area) 
Bio <- rast(bioclim_files)
Bio <- crop (Bio, Study_Area)
Bio <- mask (Bio, Study_Area)
ext(Bio)
ext(DEM)
Bio_crop <- crop(Bio, ext(DEM))
Bio_resample <- resample(Bio_crop, DEM) #Bio1_2_4_8_15_18
occurance_data <- import("p_i.xlsx")
sdm_data <- sdmData(Species ~ . + coords(Lon + Lat), 
                    train = occurance_data, 
                    predictors = Bio_resample)
print(sdm_data)
summary(sdm_data)
model <- sdm(Species ~ ., data = sdm_data,
             methods = c('glm', 'gam', 'gbm', 'rf', 'svm', 'mars'))
str(sdm_data)

occurance_data more details:

> names(occurance_data)
[1] "OBJECTID" "Species"  "Lon"      "Lat"

> str(occurance_data)

'data.frame':   78 obs. of  4 variables:
 $ OBJECTID: num  1 2 3 4 5 6 7 8 9 10 ...
 $ Species : chr  "p_i" "p_i" "p_i" "p_i" ...
 $ Lon     : num  50.8 50.8 50.9 51.3 51.3 ...
 $ Lat     : num  36.7 36.7 36.7 36.4 36.7 ...

> summary(occurance_data)
    OBJECTID       Species               Lon             Lat       
 Min.   : 1.00   Length:78          Min.   :49.01   Min.   :36.12  
 1st Qu.:20.25   Class :character   1st Qu.:50.86   1st Qu.:36.29  
 Median :39.50   Mode  :character   Median :52.36   Median :36.42  
 Mean   :39.50                      Mean   :51.97   Mean   :36.56  
 3rd Qu.:58.75                      3rd Qu.:53.09   3rd Qu.:36.76  
 Max.   :78.00                      Max.   :55.59   Max.   :37.39 

I've tried capital letters like 'Species' or 'species', even added more occurrence data but none of them worked.

Upvotes: 0

Views: 77

Answers (1)

Ben Bolker
Ben Bolker

Reputation: 226741

Based on the output of str(occurance_data), it looks like you have a data set where the Species variable is a character vector describing which species was observed at a particular location. If we look at the help file for sdmData it strongly suggests that data containing multi-species records are supposed to be provided in wide format, i.e. a 0/1 column for each species:

sdmData creates a data object, for single or multiple species. It can automatically detect the variables containing species data (if a data.frame is provided in ‘train’), but it is recommended to use formula through which all species (in the left hand side, e.g., sp1+sp2+sp3 ~ .)

This is confirmed by looking at the data used for example 3 in ?sdmData:

file <- system.file("external/multi_pa_df.csv", package="sdm")
df <- read.csv(file)
str(df)
'data.frame':   150 obs. of  16 variables:
 $ b15       : num  26 54.5 27 32.8 42.8 ...
 $ NDVI      : num  195 110 108 93 179 ...
 $ categoric1: chr  "A" "B" "B" "E" ...
 $ categoric2: chr  "ff" "cc" "bb" "cc" ...
 $ x         : int  494375 214375 364375 564375 94375 634375 444375 624375 64375 224375 ...
 $ y         : int  4774936 4244936 4674936 4344936 4744936 4474936 4354936 4314936 4714936 4664936 ...
 $ sp1       : int  1 0 1 1 1 1 1 1 1 1 ...
 $ sp2       : int  0 0 0 0 0 0 0 0 0 1 ...
 $ sp3       : int  0 0 0 0 1 1 1 0 1 1 ...
 $ sp4       : int  0 0 0 0 1 0 1 0 1 1 ...
 $ sp5       : int  1 1 1 1 0 1 0 1 0 0 ...
 $ sp6       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ sp7       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ sp8       : int  0 1 0 0 1 0 0 0 1 0 ...
 $ sp9       : int  1 1 1 1 0 1 1 1 0 1 ...
 $ sp10      : int  0 0 1 1 1 1 0 1 1 0 ...

You would probably have to tell us more about the structure of your data before we can help. Is it a presence-only data set, i.e. you have recorded which species did occur at a particular location (and you can infer that all species in your species list not in the data set were not recorded at that location)? It should be possible to transform your data set from long to wide, but it could be a little bit tricky. In particular, suppose that at location x1, y1, you recorded species 1, 2, and 3 (but not 4, 5, 6). Would your data set for that location be recorded as

Species xloc yloc <other covariates>
p1      x1   y1   ...
p2      x1   y1   [identical]
p3      x1   y1   [identical]

?

I think the way I would do this, roughly, is

  • make one data set with species, x, y and another with x, y, covariates
  • convert the species, x, y, data set to a x + y + presence-absence data set (e.g. see here or here)
  • use merge() (base R) or full_join (tidyverse) to combine the presence-absence data set with unique(covariate_dataset)

Upvotes: 1

Related Questions