Este tutorial está basado en el documento elaborado por T. Hengl para el instituto ISRIC - World Soil Information. En este documento se aplican algunos algoritmos de aprendizaje de máquina (ML en inglés) que pueden ser útiles para proyectos de cartografía de suelos. En particular, se usan algoritmos de alto desempeño tales como bosques aleatorios (random forests), máquinas de soporte vectorial (svm) y redes neuronales artificiales de múltiples capas (deep learning).
Tenga en cuenta que este tutorial no revisa los conceptos teóricos asociados a estos algoritmos y que ellos deben ser estudiados usando otras referencias.
La siguiente función, escrita por Juan Antonio Caro, permite descargar las librerías requeridas de una manera “automágica”:
InstalledPackage <- function(package)
{
available <- suppressMessages(suppressWarnings(sapply(package, require, quietly = TRUE, character.only = TRUE, warn.conflicts = FALSE)))
missing <- package[!available]
if (length(missing) > 0) return(FALSE)
return(TRUE)
}
CRANChoosen <- function()
{
return(getOption("repos")["CRAN"] != "@CRAN@")
}
UsePackage <- function(package, defaultCRANmirror = "http://cran.at.r-project.org")
{
if(!InstalledPackage(package))
{
if(!CRANChoosen())
{
chooseCRANmirror()
if(!CRANChoosen())
{
options(repos = c(CRAN = defaultCRANmirror))
}
}
suppressMessages(suppressWarnings(install.packages(package)))
if(!InstalledPackage(package)) return(FALSE)
}
return(TRUE)
}
Ahora usemos el script mágico para usar nuestras librerías:
libraries <- c("plotKML", "sp", "randomForest", "nnet", "e1071", "GSIF",
"plyr","raster", "caret","Cubist", "GSIF", "xgboost")
for(library in libraries)
{
if(!UsePackage(library))
{
stop("Error!", library)
}
}
Ebergötzen es una zona de 10 km x 10 km que está muy cerca de Göttingen (Alemania). Esta área ha sido estudiada desde hace muchos años, especialmente para el desarrollo de técnicas de cartografía digital del suelo (Gehrt and Böhner, 2001).
La variable eberg contiene 3670 observations (obtenidas con barreno) de textura del suelo a cinco profundidades (0-10, 10-30, 30-50, 50-70, and 70-90), y registros de clases de suelo de acuerdo con el sistema de clasificación de suelos de Alemania.
La variable eberg_grid contiene datos raster con resolución de 100 m que pueden ser usados como covariables para realizar la predicción de variables del suelo.
La variable eberg_grid25 contiene datos raster con resolución de 25 m.
La variable eberg_zones contiene datos vectoriales de tipo poligonal que representan la distribución de material parental en la zona de estudio (Silt and sand, Sandy material, Clayey derivats, Clay and loess).
La variable eberg_contours contine curvas de nivel derivadas del modelo de elevación digital (DEM) con resolución de 25 m, usando un intervalo entre curvas igual a 10 m.
Enseguida vamos a cargar en la sesión en R el conjunto de datos de Ebergotzen descrito anteriormente:
data(eberg)
data(eberg_grid)
coordinates(eberg) <- ~X+Y
proj4string(eberg) <- CRS("+init=epsg:31467")
gridded(eberg_grid) <- ~x+y
proj4string(eberg_grid) <- CRS("+init=epsg:31467")
Las covariables (variables predictoras) originales se pueden sintetizar en nuevas covariables usando la transformación de componentes principales:
eberg_spc <- spc(eberg_grid, ~ PRMGEO6+DEMSRT6+TWISRT6+TIRAST6)
## Converting PRMGEO6 to indicators...
## Warning: In prcomp.default(formula = formulaString, x) :
## extra argument 'formula' will be disregarded
## Converting covariates to principal components...
eberg_grid@data <- cbind(eberg_grid@data, eberg_spc@predicted@data)
Todos los análisis que siguen, usan una matriz de regresión (obtenida por medio de una operación espacial de superposición entre los puntos de muestreo y los datos raster) que contiene los valores de la variable de interés lo mismo que los valores de todas las covariables en todos los puntos de entrenamiento:
ov <- over(eberg, eberg_grid)
m <- cbind(ov, eberg@data)
dim(m)
## [1] 3670 44
El resultado anterior nos indica que la matriz de regresión consiste de 3670 filas (es decir, observaciones) y 44 columnas (valores de variables conocidos en cada observación).
En el primer ejemplo nos vamos a enfocar en obtener una clasificación de suelos usando los datos muestreados con barreno. En primer lugar, nos vamos a enfocar solamente en aquellas clases que ocurren con alta frecuencia y que, por ello, permiten realizar un modelamiento estadístico. Una regla aproximada para realizar esa selección es considerar aquellas clases que tengan por lo menos 5 observaciones:
xg = summary(m$TAXGRSC, maxsum=length(levels(m$TAXGRSC)))
str(xg)
## Named int [1:13] 790 704 487 376 252 215 186 86 71 23 ...
## - attr(*, "names")= chr [1:13] "Braunerde" "Parabraunerde" "Pseudogley" "Regosol" ...
selg.levs = attr(xg, "names")[xg > 5]
m$soiltype <- m$TAXGRSC
m$soiltype[which(!m$TAXGRSC %in% selg.levs)] <- NA
m$soiltype <- droplevels(m$soiltype)
str(summary(m$soiltype, maxsum=length(levels(m$soiltype))))
## Named int [1:11] 790 704 487 376 252 215 186 86 71 43 ...
## - attr(*, "names")= chr [1:11] "Braunerde" "Parabraunerde" "Pseudogley" "Regosol" ...
Como puede verse, existen 2 clases que tienen menos de 5 observaciones y ellas se han removido para realizar el análisis. Igualmente, también es conveniente remover aquellos puntos que contienen valores nulos (o que no tienen valores) para alguna combinación entre las covariables y la variable de interés:
m <- m[complete.cases(m[,1:(ncol(eberg_grid)+2)]),]
m$soiltype <- as.factor(m$soiltype)
Ahora podemos ajustar un modelo predictivo usando la técnica de bosques aleatorios, usando cuatro covariables (material parental, elevación, índice de humedad topográfica -TWI- y banda termal Aster):
s <- sample.int(nrow(m), 500)
TAXGRSC.rf <- randomForest(x=m[-s,paste0("PC",1:10)], y=m$soiltype[-s], xtest=m[s,paste0("PC",1:10)], ytest=m$soiltype[s])
TAXGRSC.rf
##
## Call:
## randomForest(x = m[-s, paste0("PC", 1:10)], y = m$soiltype[-s], xtest = m[s, paste0("PC", 1:10)], ytest = m$soiltype[s])
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 3
##
## OOB estimate of error rate: 59.5%
## Confusion matrix:
## Auenboden Braunerde Gley Kolluvisol Parabraunerde
## Auenboden 11 2 6 3 10
## Braunerde 2 290 6 13 59
## Gley 6 7 15 4 13
## Kolluvisol 4 20 5 22 37
## Parabraunerde 6 79 7 23 209
## Pararendzina 0 32 0 1 3
## Pelosol 0 32 0 3 3
## Pseudogley 5 64 5 7 83
## Ranker 0 6 0 0 4
## Regosol 0 66 2 3 42
## Rendzina 0 0 0 0 0
## Pararendzina Pelosol Pseudogley Ranker Regosol Rendzina
## Auenboden 0 2 3 0 0 0
## Braunerde 27 28 58 4 47 4
## Gley 0 0 8 0 4 0
## Kolluvisol 2 2 13 0 3 0
## Parabraunerde 5 5 61 2 27 0
## Pararendzina 61 35 5 2 2 1
## Pelosol 36 45 14 0 3 1
## Pseudogley 7 10 102 0 44 1
## Ranker 1 1 1 0 2 0
## Regosol 6 4 53 2 67 1
## Rendzina 3 7 0 0 1 9
## class.error
## Auenboden 0.7027027
## Braunerde 0.4609665
## Gley 0.7368421
## Kolluvisol 0.7962963
## Parabraunerde 0.5070755
## Pararendzina 0.5704225
## Pelosol 0.6715328
## Pseudogley 0.6890244
## Ranker 1.0000000
## Regosol 0.7276423
## Rendzina 0.5500000
## Test set error rate: 63.2%
## Confusion matrix:
## Auenboden Braunerde Gley Kolluvisol Parabraunerde
## Auenboden 3 1 3 1 2
## Braunerde 0 67 2 1 24
## Gley 0 2 3 0 2
## Kolluvisol 1 5 2 7 11
## Parabraunerde 2 9 4 6 40
## Pararendzina 0 7 0 0 0
## Pelosol 0 6 0 0 1
## Pseudogley 0 27 1 3 19
## Ranker 0 2 0 0 0
## Regosol 0 19 0 2 19
## Rendzina 0 1 0 0 0
## Pararendzina Pelosol Pseudogley Ranker Regosol Rendzina
## Auenboden 0 0 1 0 0 0
## Braunerde 6 4 10 0 17 0
## Gley 0 0 3 0 1 0
## Kolluvisol 0 0 4 0 0 0
## Parabraunerde 2 1 17 0 8 0
## Pararendzina 15 10 1 0 1 0
## Pelosol 11 19 1 1 1 0
## Pseudogley 0 2 19 0 12 0
## Ranker 0 0 0 0 0 0
## Regosol 0 6 10 0 11 0
## Rendzina 1 0 0 0 0 0
## class.error
## Auenboden 0.7272727
## Braunerde 0.4885496
## Gley 0.7272727
## Kolluvisol 0.7666667
## Parabraunerde 0.5505618
## Pararendzina 0.5588235
## Pelosol 0.5250000
## Pseudogley 0.7710843
## Ranker 1.0000000
## Regosol 0.8358209
## Rendzina 1.0000000
TAXGRSC.rf$test$confusion[,"class.error"]
## Auenboden Braunerde Gley Kolluvisol Parabraunerde
## 0.7272727 0.4885496 0.7272727 0.7666667 0.5505618
## Pararendzina Pelosol Pseudogley Ranker Regosol
## 0.5588235 0.5250000 0.7710843 1.0000000 0.8358209
## Rendzina
## 1.0000000
Las variables xtest y ytest contienen una selección de los datos excluyendo 500 puntos. Esas variables permitem ajustar el modelo usando una técnica de validación cruzada. Los resultados muestran un error de predicción relativamente alto (60%). Es decir que la exactitud de clasificación es apenas del 40%.
Adicionalmente, podemos evaluar otros algoritmos ML tales como multinom (librería nnet) y máquinas de soporte vectorial (support vector machines) (librería e1071):
TAXGRSC.rf <- randomForest(x=m[,paste0("PC",1:10)], y=m$soiltype)
fm = as.formula(paste("soiltype~", paste(paste0("PC",1:10), collapse="+")))
fm
## soiltype ~ PC1 + PC2 + PC3 + PC4 + PC5 + PC6 + PC7 + PC8 + PC9 +
## PC10
TAXGRSC.mn <- multinom(fm, m)
## # weights: 132 (110 variable)
## initial value 6119.428736
## iter 10 value 4161.338634
## iter 20 value 4118.296050
## iter 30 value 4054.454486
## iter 40 value 4020.653949
## iter 50 value 3995.113270
## iter 60 value 3980.172669
## iter 70 value 3975.188371
## iter 80 value 3973.743572
## iter 90 value 3973.073564
## iter 100 value 3973.064186
## final value 3973.064186
## stopped after 100 iterations
TAXGRSC.mn
## Call:
## multinom(formula = fm, data = m)
##
## Coefficients:
## (Intercept) PC1 PC2 PC3 PC4
## Braunerde 5.45385949 -1.5523725 -1.1414899 3.8709194 1.4091389
## Gley 0.81237203 -0.8441025 -0.9312981 -0.8226797 -1.3941956
## Kolluvisol 2.07610351 -0.5182167 -0.8295361 0.5692995 0.1252458
## Parabraunerde 4.79697987 -0.7988520 -0.9690134 2.8326057 1.2534355
## Pararendzina 0.02502688 -3.9859766 4.3969612 5.3946981 1.0568509
## Pelosol 1.74206393 -4.6008224 -2.6307442 4.5101860 2.3914096
## Pseudogley 5.54640062 -1.6876641 -0.8466514 2.8029280 1.6803954
## Ranker -0.96272445 -4.2793437 -3.6187842 4.3917782 1.4555614
## Regosol 4.75933466 -1.8791610 -1.4315041 3.3350548 1.4528831
## Rendzina -3.79009984 -7.1819850 2.7137859 2.4190389 5.3561776
## PC5 PC6 PC7 PC8 PC9
## Braunerde 1.8267474 -0.53585896 -1.0202426 0.4130277 -2.1117407
## Gley 3.2509685 0.95970334 0.1373794 -1.3089189 -1.1892245
## Kolluvisol 0.1753722 -1.11878357 -3.0079465 -0.2429255 -0.8361207
## Parabraunerde 1.8110834 -0.23800375 -0.3752836 0.3904447 -1.5288602
## Pararendzina 2.1783580 -0.16180762 0.6286308 1.3313932 -1.8354678
## Pelosol -0.5658518 0.55226113 1.1437075 -0.3310972 -4.6781098
## Pseudogley 1.9471449 -0.02731435 -0.1180446 0.4029453 -2.0395526
## Ranker -0.4347812 -0.61573963 -2.3780706 -0.8746946 -6.1753129
## Regosol 2.0765431 -0.49133114 -1.4234241 -0.1413113 -2.2472025
## Rendzina 1.0357045 0.87248537 1.3751377 0.3783946 -5.4131087
## PC10
## Braunerde 4.0354695
## Gley 3.1921390
## Kolluvisol 2.3187566
## Parabraunerde 3.4629867
## Pararendzina 1.5015180
## Pelosol 2.4189837
## Pseudogley 5.5537219
## Ranker -0.6739856
## Regosol 4.2216540
## Rendzina 4.2512969
##
## Residual Deviance: 7946.128
## AIC: 8126.128
TAXGRSC.svm <- svm(fm, m, probability=TRUE, cross=5)
TAXGRSC.svm
##
## Call:
## svm(formula = fm, data = m, probability = TRUE, cross = 5)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 1
## gamma: 0.1
##
## Number of Support Vectors: 2375
TAXGRSC.svm$tot.accuracy
## [1] 40.90909
Los resultados anteriores muestran que los tres métodos utilizados (random forest, multinom y svm) producen niveles de exactitud similares. Por ello, podemos “fusionar” las predicciones usando un promedio simple (otra alternativa sería usar el paquete caretEnsemble que permite optimizar la integración de varios modelos):
probs1 <- predict(TAXGRSC.mn, eberg_grid@data, type="probs", na.action = na.pass)
probs2 <- predict(TAXGRSC.rf, eberg_grid@data, type="prob", na.action = na.pass)
probs3 <- attr(predict(TAXGRSC.svm, eberg_grid@data, probability=TRUE, na.action = na.pass), "probabilities")
Ahora, procedemos a la obtención del promedio:
leg <- levels(m$soiltype)
lt <- list(probs1[,leg], probs2[,leg], probs3[,leg])
probs <- Reduce("+", lt) / length(lt)
eberg_soiltype = eberg_grid
eberg_soiltype@data <- data.frame(probs)
Es buena idea verificar que la suma de todas las predicciones es igual al 100%:
ch <- rowSums(eberg_soiltype@data)
summary(ch)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1 1 1 1 1 1
Podemos plotear el resultado usando el paquete raster:
plot(raster::stack(eberg_soiltype), col=SAGA_pal[[1]], zlim=c(0,1))
La figura de arriba muestra la clasificación de suelos que se ha obtenido para la zona de Ebergotzen usando los tres modelos.
También es posible obtener un índice de confusión, que representa la incertidumbre de la clasificación, y establecer si es posible agregar algunas clases. También se puede generar una clasificación “cualitativa” si se selecciona para cada pixel aquella clase que tenga la mayor probabilidad:
eberg_soiltype$class <- NULL
summary(eberg_soiltype@data)
## Auenboden Braunerde Gley
## Min. :0.001126 Min. :0.02568 Min. :0.001163
## 1st Qu.:0.003243 1st Qu.:0.13300 1st Qu.:0.008016
## Median :0.006650 Median :0.17772 Median :0.014450
## Mean :0.022304 Mean :0.22935 Mean :0.034343
## 3rd Qu.:0.022081 3rd Qu.:0.27390 3rd Qu.:0.035207
## Max. :0.461989 Max. :0.69116 Max. :0.710280
## Kolluvisol Parabraunerde Pararendzina
## Min. :0.002873 Min. :0.004612 Min. :0.001165
## 1st Qu.:0.023987 1st Qu.:0.083156 1st Qu.:0.002385
## Median :0.035491 Median :0.122953 Median :0.011258
## Mean :0.050266 Mean :0.184962 Mean :0.064523
## 3rd Qu.:0.051241 3rd Qu.:0.286666 3rd Qu.:0.040572
## Max. :0.450358 Max. :0.625822 Max. :0.662323
## Pelosol Pseudogley Ranker
## Min. :0.002002 Min. :0.01782 Min. :0.001376
## 1st Qu.:0.006346 1st Qu.:0.07926 1st Qu.:0.002947
## Median :0.013109 Median :0.12427 Median :0.004253
## Mean :0.059944 Mean :0.15993 Mean :0.006627
## 3rd Qu.:0.033575 3rd Qu.:0.18642 3rd Qu.:0.007135
## Max. :0.537763 Max. :0.61842 Max. :0.234746
## Regosol Rendzina
## Min. :0.008785 Min. :0.0003582
## 1st Qu.:0.034156 1st Qu.:0.0006643
## Median :0.073967 Median :0.0010215
## Mean :0.101642 Mean :0.0861144
## 3rd Qu.:0.147030 3rd Qu.:0.1496042
## Max. :0.572929 Max. :0.4378668
DF <- eberg_soiltype@data
eberg_soiltype$class <- colnames(DF)[max.col(DF, ties.method = 'first')]
unique(eberg_soiltype$class)
## [1] "Pararendzina" "Pelosol" "Rendzina" "Braunerde"
## [5] "Parabraunerde" "Regosol" "Auenboden" "Kolluvisol"
## [9] "Pseudogley" "Gley"
colors <- heat.colors(10)
plot(raster(eberg_soiltype[12]), col=colors, zlim=c(1,10))
El algoritmo de bosques aleatorios (random forest) es útil para resolver problemas de clasificación y de regresión. Por ello, se puede aplicar en el modelamiento de propiedades del suelo (es decir, para generar predicciones de valores cuantitativos). El paquete randomForest de R puede no ser la mejor alternativa cuando se usan datos “muy pesados”. Una opción más interesante es la utilización del paquete h2o (Richter et al. 2015). h2o es una implementación basada en Java y todos los cálculos se realizan fuera de R, es decir dentro de JVM (Java Virtual Machine).
La parte más complicada es la instalación de h2o. Una guía para realizar ese proceso se encuentra en este link: http://h2o-release.s3.amazonaws.com/h2o/master/1247/docs-website/Ruser/R_studio.html
En el ejemplo que sigue vamos a cartografiar el contentido de arena para el horizonte superior. Empecemos por inicializar h2o:
#install.packages("h2o")
library(h2o)
##
## ----------------------------------------------------------------------
##
## Your next step is to start H2O:
## > h2o.init()
##
## For H2O package documentation, ask for help:
## > ??h2o
##
## After starting H2O, you can use the Web UI at http://localhost:54321
## For more information visit http://docs.h2o.ai
##
## ----------------------------------------------------------------------
##
## Attaching package: 'h2o'
## The following objects are masked from 'package:raster':
##
## %in%, as.factor, is.factor
## The following objects are masked from 'package:stats':
##
## cor, sd, var
## The following objects are masked from 'package:base':
##
## %*%, %in%, &&, ||, apply, as.factor, as.numeric, colnames,
## colnames<-, ifelse, is.character, is.factor, is.numeric, log,
## log10, log1p, log2, round, signif, trunc
localH2O = h2o.init()
## Connection successful!
##
## R is connected to the H2O cluster:
## H2O cluster uptime: 17 hours 42 minutes
## H2O cluster version: 3.10.3.6
## H2O cluster version age: 3 days
## H2O cluster name: H2O_started_from_R_Ivan_ldv605
## H2O cluster total nodes: 1
## H2O cluster total memory: 3.43 GB
## H2O cluster total cores: 8
## H2O cluster allowed cores: 2
## H2O cluster healthy: TRUE
## H2O Connection ip: localhost
## H2O Connection port: 54321
## H2O Connection proxy: NA
## R Version: R version 3.3.2 (2016-10-31)
#h2o.shutdown()
#h2o.init(nthreads = -1)
Enseguida, vamos a preparar la matriz de regresión y los sitios de las predicciones usando la función as.h2o de manera que sean visibles a la librería h2o:
eberg.hex = as.h2o(m, destination_frame = "eberg.hex")
##
|
| | 0%
|
|=================================================================| 100%
eberg.grid = as.h2o(eberg_grid@data, destination_frame = "eberg.grid")
##
|
| | 0%
|
|=================================================================| 100%
Ahora podemos ajustar un modelo random forest:
RF.m = h2o.randomForest(y = which(names(m)=="SNDMHT_A"), x = which(names(m) %in% paste0("PC",1:10)), training_frame = eberg.hex, ntree = 50)
##
|
| | 0%
|
|==== | 6%
|
|============================================ | 68%
|
|=================================================================| 100%
RF.m
## Model Details:
## ==============
##
## H2ORegressionModel: drf
## Model ID: DRF_model_R_1487981499883_28
## Model Summary:
## number_of_trees number_of_internal_trees model_size_in_bytes min_depth
## 1 50 50 640844 20
## max_depth mean_depth min_leaves max_leaves mean_leaves
## 1 20 20.00000 923 1063 1016.36000
##
##
## H2ORegressionMetrics: drf
## ** Reported on training data. **
## ** Metrics reported on Out-Of-Bag training samples **
##
## MSE: 220.5606
## RMSE: 14.85128
## MAE: 10.05702
## RMSLE: 0.4263087
## Mean Residual Deviance : 220.5606
Los resultados muestran que el valor R2 del modelo ajustado es cercano al 50%. Ello también se puede observar en un gráfico de valores observados vs valores obtenidos en la predicción:
plot(m$SNDMHT_A, as.data.frame(h2o.predict(RF.m, eberg.hex, na.action=na.pass))$predict, asp=1, xlab="measured", ylab="predicted")
##
|
| | 0%
|
|=================================================================| 100%
Para obtener un mapa de contenido de arena basado en las predicciones se puede usar:
eberg_grid$RFx <- as.data.frame(h2o.predict(RF.m, eberg.grid, na.action=na.pass))$predict
##
|
| | 0%
|
|=================================================================| 100%
plot(raster(eberg_grid["RFx"]), col=SAGA_pal[[1]], zlim=c(10,90))
points(eberg, pch="+")
La librería h2o tiene otro algoritmo ML de interés que se conoce como “deep learning” y que no es otra cosa que es una red neuronal artificial de múltiples capas. El ajuste del modelo es similar al uso random forest:
DL.m <- h2o.deeplearning(y = which(names(m)=="SNDMHT_A"), x = which(names(m) %in% paste0("PC",1:10)), training_frame = eberg.hex)
##
|
| | 0%
|
|====== | 10%
|
|==================== | 30%
|
|============================================== | 70%
|
|=================================================================| 100%
DL.m
## Model Details:
## ==============
##
## H2ORegressionModel: deeplearning
## Model ID: DeepLearning_model_R_1487981499883_29
## Status of Neuron Layers: predicting SNDMHT_A, regression, gaussian distribution, Quadratic loss, 42.601 weights/biases, 508,2 KB, 25.520 training samples, mini-batch size 1
## layer units type dropout l1 l2 mean_rate rate_rms
## 1 1 10 Input 0.00 %
## 2 2 200 Rectifier 0.00 % 0.000000 0.000000 0.016178 0.011101
## 3 3 200 Rectifier 0.00 % 0.000000 0.000000 0.161467 0.193774
## 4 4 1 Linear 0.000000 0.000000 0.001413 0.001068
## momentum mean_weight weight_rms mean_bias bias_rms
## 1
## 2 0.000000 0.000157 0.102569 0.334967 0.069185
## 3 0.000000 -0.018338 0.071091 0.952872 0.020253
## 4 0.000000 -0.002110 0.042361 0.062960 0.000000
##
##
## H2ORegressionMetrics: deeplearning
## ** Reported on training data. **
## ** Metrics reported on full training frame **
##
## MSE: 230.3774
## RMSE: 15.17819
## MAE: 10.99303
## RMSLE: 0.4484678
## Mean Residual Deviance : 230.3774
Los resultados obtenidos mediante deep learning son comparables a los obtenidos mediante random forest. Sin embargo, los resultados de las predicciones (map) lucen diferente de las predicciones obtenidas mediante random forest:
eberg_grid$DLx <- as.data.frame(h2o.predict(DL.m, eberg.grid, na.action=na.pass))$predict
##
|
| | 0%
|
|=================================================================| 100%
plot(raster(eberg_grid["DLx"]), col=SAGA_pal[[1]], zlim=c(10,90))
points(eberg, pch="+")
La pregunta obvia es cuál de los dos métodos deberíamos usar? Teniendo en cuenta que los dos tienen un desempeño similar, la opción lógica es fusionar (emsamblar) las predicciones, de manera que cada método sea utilizado de acuerdo con algún sistema de ponderación. En este ejemplo, se puede usar el valor R2 para realizar esa ponderación:
rf.R2 = RF.m@model$training_metrics@metrics$r2
dl.R2 = DL.m@model$training_metrics@metrics$r2
eberg_grid$SNDMHT_A <- rowSums(cbind(eberg_grid$RFx*rf.R2, eberg_grid$DLx*dl.R2), na.rm=TRUE)/(rf.R2+dl.R2)
plot(raster(eberg_grid["SNDMHT_A"]), col=SAGA_pal[[1]], zlim=c(10,90))
points(eberg, pch="+")
La figura de arriba muestra la predicción del contenido de arena basada en los modelos integrados. De hecho, los resultados muestran patrones asociados a los métodos individuales pero tienen una mejor exactitud que cualquiera de ellos.
Este documento ha ilustrado el uso de algunos algoritmos de aprendizaje de máquina (ML) aplicado a la cartografía de suelos, tanto de propiedades cualitativas como de propiedades cuantitativas. Los algoritmos ML son muy atractivos en cuanto permiten representar de una manera relaciones que son eminentemente locales, como ocurre a menudo con las propiedades de suelos. Los algoritmos ML no dependen en supuestos estadísticos ideales sino que explotan las características particulares de los datos disponibles. Sin embargo, un problema con estos algoritmos es que requieren una gran capacidad computacional y que los modelos obtenidos son eminentemente empíricos y, por consiguiente, únicamente válidos en las zonas geográficas específicas en que han sido estudiados.
Referencias
Hengl, T. (n.d.) Machine Learning Algorithms for Soil Mapping. Available at http://gsif.isric.org/doku.php?id=wiki:soilmapping_using_mla