Krigagem do índice de sítio

O índice de sítio é um atributo que representa o potencial de produtividade de determinado local, sendo influenciado por fatores geológicos, topográficos, climáticos, edáficos e bióticos, apresentando de modo geral algum nível de dependência espacial, sendo portanto possível a realização de inferências espaciais sob seu comportamento.
Neste exemplo iremos interpolar o índice de sítio por meio de krigagem ordinária. A base teórica para os procedimentos abaixo descritos pode ser consultada nas teses de Mello (2004) e Pelissari (2015).

Iniciaremos com a importação de dados de unidades amostrais com índice de sítio estimado e respectivas coordenadas geográficas.

library(readxl)
library(geoR)
## Warning: package 'geoR' was built under R version 4.2.3
## --------------------------------------------------------------
##  Analysis of Geostatistical Data
##  For an Introduction to geoR go to http://www.leg.ufpr.br/geoR
##  geoR version 1.9-2 (built on 2022-08-09) is now loaded
## --------------------------------------------------------------
# Importar dados
dados <- read_excel('dados_interpolacao.xlsx')
dados
## # A tibble: 101 × 4
##    PARCELA      X       Y    IS
##      <dbl>  <dbl>   <dbl> <dbl>
##  1       1 440559 7801189  31.3
##  2       2 440846 7801282  32.0
##  3       3 440734 7801475  29.6
##  4       4 440923 7801657  29.4
##  5       5 440683 7800566  33.8
##  6       6 440709 7800769  36.9
##  7       7 440528 7800929  35.7
##  8       8 440783 7800975  31.0
##  9       9 440989 7800264  30.4
## 10      10 440872 7800395  33.9
## # ℹ 91 more rows
# Transformar dados em geodata
dados <- as.geodata(dados,coords.col = 2:3, data.col = 4)

Podemos avaliar visualmente a distribuição dos dados plotando um histograma de frequência. Esta avaliação é importante para averiguarmos a necessidade de transformação nos dados, caso estes possuam uma distribuição não normal.

# Plotar histograma
hist(dados$data,
     xlab = 'Índice de Sítio (m)', ylab = 'Frequência',
     main = 'Histograma - Índice de Sítio')

Por meio de uma análise visual, os valores de sítio parecem apresentar uma distribuição próxima da normal. Vamos confirmar se há aderência aplicando o teste de Kolmogorov-Smirnov.

# Teste de Kolmogorov-Smirnov 
ks = ks.test(dados$data, 'pnorm', mean = mean(dados$data), sd = sd(dados$data))
ks
## 
## 	Asymptotic one-sample Kolmogorov-Smirnov test
## 
## data:  dados$data
## D = 0.050885, p-value = 0.9562
## alternative hypothesis: two-sided

O elevado p-value aponta que não há diferença estatística entre a distribuição normal e a distribuição dos dados que estamos analisando, corroborando que poderemos proceder à krigagem sem transformação da variável de interesse.
A próxima etapa será plotar e analisar o semivariograma. Para tal, utilizaremos a função variog do geoR.
Dois argumentos são importantes neste procedimento. O primeiro max.dist se refere à distância máxima para construção do variograma. É importante que este valor seja grande o suficiente para que o variograma compreenda o alcance (range) que indica a zona de influência ou de dependência espacial entre as amostras.
O segundo argumento uvec indica o número de pontos de referência (lags) que serão distribuídos proporcionalmente até atingir a distância máxima definida para o variograma.
O procedimento para obtenção de valores para estes parâmetros é iterativo e será tema de um próximo post. Por hora, definiremos o valor de 1000 para max.dist e 10 para uvec (1000/10 = 100, que é a distância aproximada entre as unidades amostrais alocadas ).

# Plotar semivariograma
semivariograma <- variog(dados, max.dist = 1000, uvec = 10,messages=FALSE)
plot(semivariograma,
     ylab = 'Semivariância', xlab = 'Distância')

O semivariograma acima considera que a semivariância possui o mesmo comportamento em todas as direções. No entanto, é fundamental avaliar se esta premissa é verdadeira. Vamos averiguar se o fenômeno da anisotropia ocorre para este conjunto de dados utilizando a função variog4.

# Investigar anisotropia
plot(variog4(dados, max.dist = 1000, uvec = 10,messages=FALSE),
     ylab = 'Semivariância', xlab = 'Distância')

Verifica-se que as linhas que representam variogramas para diferentes direções se cruzam diversas vezes, sem haver clara distinção de tendências. Deste modo, consideramos verdadeira a premissa de isotropia. Do contrário, seria necessária uma transformação das coordenadas, de modo a estabelecer a isotropia. Agora podemos proceder ao ajuste de modelos de semivariância. Neste exemplo testaremos os modelos Esférico, Exponencial, Gaussiano e Cúbico.

# Definir modelos a serem ajustados
modelos <- c('spherical','exponential','gaussian','cubic')
# Criar lista para armazenar modelos ajustados
modelos_ajustados <- list()
# Ajustar modelos de semivariância
for(i in modelos){
modelos_ajustados[[i]] <- variofit(semivariograma, cov.model = i, messages = FALSE)
}
modelos_ajustados
## $spherical
## variofit: model parameters estimated by WLS (weighted least squares):
## covariance model is: spherical
## parameter estimates:
##    tausq  sigmasq      phi 
##   0.6878   2.4059 334.7681 
## Practical Range with cor=0.05 for asymptotic range: 334.7681
## 
## variofit: minimised weighted sum of squares = 182.0471
## 
## $exponential
## variofit: model parameters estimated by WLS (weighted least squares):
## covariance model is: exponential
## parameter estimates:
##    tausq  sigmasq      phi 
##   1.8991   1.7099 500.6367 
## Practical Range with cor=0.05 for asymptotic range: 1499.773
## 
## variofit: minimised weighted sum of squares = 130.6787
## 
## $gaussian
## variofit: model parameters estimated by WLS (weighted least squares):
## covariance model is: gaussian
## parameter estimates:
##    tausq  sigmasq      phi 
##   2.3775   1.0351 557.8393 
## Practical Range with cor=0.05 for asymptotic range: 965.5186
## 
## variofit: minimised weighted sum of squares = 136.2159
## 
## $cubic
## variofit: model parameters estimated by WLS (weighted least squares):
## covariance model is: cubic
## parameter estimates:
##     tausq   sigmasq       phi 
##    2.3595    1.0223 1282.4003 
## Practical Range with cor=0.05 for asymptotic range: 1282.4
## 
## variofit: minimised weighted sum of squares = 135.2704

Os quatro modelos ajustados possuem três parâmetros interpretáveis: tausq se refere ao efeito pepita (nugget), sigmasq é também conhecido como partial sill e consiste no valor do patamar menos o efeito pepita, e phi se refere ao alcance (range). Vamos plotar as curvas de semivariância geradas a partir dos modelos ajustados.

par(mfrow = c(2,2))
for(i in modelos){
  plot(semivariograma,
     ylab = 'Semivariância', xlab = 'Distância',
     main = i)
  lines.variomodel(modelos_ajustados[[i]])
}

Para avaliar a eficiência dos modelos ajustados na predição do índice de sítio em locais não amostrados, devemos proceder à validação cruzada, conforme o procedimento a seguir.

# Cria lista para armazenar resultado da validação cruzada
modelos_xvalid <- list()
# Validação cruzada para todos os modelos
for(i in modelos){
modelos_xvalid[[i]] <- xvalid(dados, model = modelos_ajustados[[i]], messages = FALSE)
}
# Formatação dos resultados
erro_padrao <- unlist(lapply(modelos_xvalid,summary))[c(11,25,39,53)]
names(erro_padrao) <- modelos
desvio_do_erro <- unlist(lapply(modelos_xvalid,summary))[c(14,28,42,56)]
names(desvio_do_erro) <- modelos
# Plotar
par(mfrow = c(1,2))
text(barplot(erro_padrao, ylim =c(-0.01,0.01), main = 'Erro padrão da validação cruzada'), y = erro_padrao+sign(erro_padrao)*0.001,labels = round(erro_padrao,5))
text(barplot(desvio_do_erro, ylim = c(0,2), main = 'Desvio padrão do erro'), y = desvio_do_erro+sign(desvio_do_erro)*0.1,labels = round(desvio_do_erro,3))

As estatísticas de validação cruzada são favoráveis ao uso do modelo cúbico, portanto, utilizaremos este para interpolar o índice de sítio para toda a área e interesse. Vamos importar os limites das áreas a serem interpoladas.

# Definir modelo a ser utilizado
modelo_selecionado <- modelos_ajustados$cubic
# Importar shape com os limites da área de interesse
library(rgdal)
## Carregando pacotes exigidos: sp
## Please note that rgdal will be retired during 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
## See https://r-spatial.org/r/2022/04/12/evolution.html and https://github.com/r-spatial/evolution
## rgdal: version: 1.6-4, (SVN revision 1196)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.5.2, released 2022/09/02
## Path to GDAL shared files: C:/Users/sergio.costa/AppData/Local/R/win-library/4.2/rgdal/gdal
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 8.2.1, January 1st, 2022, [PJ_VERSION: 821]
## Path to PROJ shared files: C:/Users/sergio.costa/AppData/Local/R/win-library/4.2/rgdal/proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.6-0
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
talhoes <- readOGR('.', 'talhoes', verbose = FALSE)
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
# Plotar talhões e pontos amostrais
points(plot(talhoes),
       x = dados[[1]][,1],y = dados[[1]][,2],
       pch='+', col='red')

Agora devemos gerar um grid de interpolação para toda a área de interesse e, por fim, aplicar o modelo cúbico ajustado.

# Gerar grid de interpolação
library(sp)
grid <- spsample(talhoes, type = 'regular', n = 10000)
plot(grid)

# Realizar a krigagem
krigagem_is <- krige.conv(dados, locations = as.data.frame(grid), krige = krige.control(obj.model = modelo_selecionado))
# Armazenar resultado em spatial data frame
krigagem_is <- coordinates(data.frame(x = data.frame(grid)[,1],
                                      y = data.frame(grid)[,2],
                                      IS = krigagem_is$predict))
# Converter em raster
library(raster)
krigagem_is <- rasterFromXYZ(krigagem_is)
# Definir projeção
projection(krigagem_is) <- CRS("+init=epsg:31982")
image(krigagem_is, asp=1,xlab='Longitude',ylab = 'Latitude')

# Plotar resultado com bordas e pontos amostrais
image(krigagem_is, asp=1,xlab='Longitude',ylab = 'Latitude')
plot(talhoes, add = TRUE)
points(x = dados[[1]][,1],y = dados[[1]][,2],
       pch='+', col='black')

Agora que visualizamos o resultado da krigagem, podemos exportar um arquivo em formato .tif, que permitirá a visualização em qualquer outro software de SIG.

# Salvar arquivo .tif
writeRaster(krigagem_is,'krigagem_is.tif', overwrite = TRUE)
Avatar
Sérgio Costa
MSc. Engenheiro Florestal

Mestre em Engenharia Florestal pela Universidade Federal do Paraná, atualmente trabalha como Especialista em Modelagem de Dados na Arauco Forest Brasil.

comments powered by Disqus
Próximo
Anterior

Relacionados