lidar:projetos:rcode_invconve
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Inventário Convencional na Fazenda Modelo ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Autor: Luiz Carlos Estraviz Rodriguez # Departamento de Ciências Florestais # ESALQ/USP - 16/Jan/2024 # # Inventário florestal da Fazenda Modelo # - download dos dados mantidos em um repositório github público # - shape files dos talhões florestais # - LiDAR multitemporal (2013 e 2014) # - sugestão de pasta para armazenamento local: # C:/LiDAR/PRJ_Modelo/ # # Linguagem de programação: # R (v 4.3) # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ rm(list=ls(all=TRUE)) # Limpa memória gc() # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 1. Leitura e organização de dados # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---- if(!require(tidyverse)) # Para melhor manipulação de dados e funções install.packages("tidyverse") library(tidyverse) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Download do shape da Fazenda Modelo (2 layers: talhoes e parcelas) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gitOnde <- "https://github.com/FlorestaR/dados/blob/main/5_LIDARF/Modelo/SHAPES" gitNome <- "fazmodelo.zip" gitArqv <- file.path(gitOnde, gitNome) %>% paste0("?raw=true") tmpd <- tempdir(check = TRUE) # diretório temporário zipf <- file.path(tmpd, "shapes.zip") # arquivo temporário options(timeout=1000) # Reset timeout oferecendo mais tempo de download if(!file.exists(zipf)) # garante download de dados binários (wb) download.file(gitArqv, mode="wb", destfile = zipf) unzip(zipf, exdir = tmpd) # shape é unziped no diretório temporário unlink(zipf) # deleta o arquivo zipado if(!require(sf)) # Para manipulação de shapes install.packages("sf") library(sf) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Lê atributos dos talhoes # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ shpArq <- paste0(tmpd, "/Modelo_talhoes.shp") # shape com talhões talhoesComGeo <- read_sf(shpArq) # completo com geom talhoesSemGeo <- tibble(sf::st_drop_geometry(talhoesComGeo)) # s/ geom # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Lê atributos das parcelas # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ shpArq <- paste0(tmpd, "/Modelo_parcelas.shp") # shape com parcelas parcelasComGeo <- read_sf(shpArq) # completo com geom parcelasSemGeo <- tibble(sf::st_drop_geometry(parcelasComGeo)) # s/ geom # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Cria coluna IDINV na tabela "talhões", extraída da tabela "parcelas" # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ talhoes <- parcelasSemGeo %>% group_by(SUBTALHAO) %>% summarise(IDINV = unique(IDINV)) %>% left_join(talhoesSemGeo) %>% select("SUBTALHAO", "IDINV", "AREA") %>% arrange(SUBTALHAO) %>% as.data.frame talhoesComGeo <- inner_join(talhoesComGeo, talhoes, by="SUBTALHAO") %>% select("OBJECTID", "SUBTALHAO", "IDINV", "geometry") # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Reorganiza colunas da tabela "parcelas" # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ parcelas <- parcelasSemGeo %>% select(SUBTALHAO, CHAVE2, DATAREALIZ, IDINV, AREAPARCEL, MHDOM, VTCC) %>% arrange(SUBTALHAO) %>% as.data.frame # Cria diretórios e pastas para onde alguns dados serão copiados # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ prjNome <- 'PRJ_Modelo' dirNome <- paste0('C:/LiDAR/', prjNome) dir.create(dirNome, showWarnings = F) # Salva e imprime dados reorganizados # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dirNome <- paste0(dirNome, '/DADOS/') dir.create(dirNome, showWarnings = F) # Leitura da mais atual versão rio para facilmente ler e salvar Excel # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (!require("remotes")){install.packages("remotes")} if (!require(rio)) {remotes::install_github("gesistsa/rio")} library(rio) # Salva dados em planilha Excel arqNome <- paste0(dirNome, prjNome, '.xlsx') export(list(talhoes = talhoes, parcelas = parcelas), file = arqNome) # Mostra tabelas no Viewer # Use o "Export" do Viewer para salvar em diferentes formatos # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if(!require(kableExtra)) install.packages("kableExtra") library(kableExtra) # Mostra talhões AreaTotal <- talhoes$AREA %>% sum NotaDeRodape <- paste0(": ", AreaTotal) talhoes %>% kbl(caption = "Talhões da Fazenda Modelo", align = "r") %>% kable_classic(full_width = F) %>% footnote(general = NotaDeRodape, general_title = "Área total", footnote_as_chunk = T) # Mostra parcelas parcelas %>% kbl(caption = "Parcelas da Fazenda Modelo", align = "r") %>% kable_classic(full_width = F) # Cria diretório para salvar mapas, figuras e gráficos # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dirNome <- paste0('C:/LiDAR/', prjNome) dir.create(dirNome, showWarnings = F) dirNome <- paste0(dirNome, '/GRAPH/') dir.create(dirNome, showWarnings = F) # Cria mapa dos talhões com localização das parcelas (EPSG: 31983) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arqNome <- paste0(dirNome, prjNome, '.png') png(arqNome, 30, 20, 'cm', res = 200) # abre "impressão" ggplot() + # plot dos talhões e parcelas (cor por idade) geom_sf(data = talhoesComGeo, colour = "black", fill="white") + geom_sf(data = parcelasComGeo, aes(fill = factor(IDINV))) + scale_fill_discrete(name = "Idade") + guides(fill = guide_legend(reverse=F)) + coord_sf(datum=st_crs(31983)) + # Especifica sistema de coord. scale_y_continuous(breaks = seq(from=7356500,to=7359000, by=200)) + scale_x_continuous(breaks = seq(from=206200, to=207600, by=200)) dev.off() # fecha "impressão" do aquivo # ---- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 2. Amostragem Casual Simples (ACS) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---- # Função para cálculo do Intervalo de Confiança calcCI = function(err, n, alpha=.05){ return( qt(1 - alpha/2, n-1) * err #/ sqrt(n) ) } # Função para cálculo dos parâmetros de estimação e inferência calcPars = function(df, N, alpha=.05){ means = apply(df, 2, mean) vars = apply(df, 2, function(y){ (var(y) / length(y)) * ((N - length(y)) / N) }) err = sqrt(vars) cis = calcCI(err, nrow(df), alpha) err_pc = 100*cis/means out = rbind(means, vars, err, cis, err_pc, nrow(df)) %>% as.data.frame row.names(out) = c('media', 'var', 'dp', 'ic', 'erro', 'n') names(out) = names(df) return(out) } # Cria lista com variáveis de interesse variaveisDeInteresse <- c("MHDOM", "VTCC") # Cria dataframe com valores observados das variáveis de interesse df <- parcelas %>% select(all_of(variaveisDeInteresse)) # Calcula o número máximo de unidades amostrais possíveis (N) parcelaAreaMedia <- mean(parcelas$AREAPARCEL) / 10000 # por ha N_ACS <- round(AreaTotal / parcelaAreaMedia , 0) # N # Resultados do inventário (estimação + inferência) # pelo método Amostragem Casual Simples (ACS) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ paramEstatisticosACS <- df %>% calcPars(N_ACS) # Função para cálculo da intensidade amostral recomendada # (ha por parcela) da ACS que garante ~10% de erro (altere se desejar) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ erro <- 10 tamanhoIdealACS = function(y, N, errDesired=erro/100, alpha=erro/100){ B = errDesired * mean(y) qt = qt(1 - alpha/2, length(y)-1) n = N*var(y)*qt^2 / (N * B^2 + qt^2 * var(y)) return(n) } # Intensidade amostral usada # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IAS <- paste0(" usada: 1 parc/", round(AreaTotal/paramEstatisticosACS$VTCC[6],0), " ha.") # Intensidade amostral que seria necessária para ACS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IA <- round(AreaTotal/tamanhoIdealACS(df$VTCC,N_ACS),0) erroTexto <- as.character(erro) IAI <- paste0("\n Necessárias p/ erro de ", erroTexto, "%: 1 parc/", IA, " ha.") # Mostra resultados da ACS no Viewer # Use o "Export" do Viewer para salvar em diferentes formatos # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NotaDeRodape <- paste0(IAS, IAI) paramEstatisticosACS %>% kbl(caption = "Amostragem Casual Simples (ACS)", align = "r") %>% kable_classic(full_width = F) %>% footnote(general = NotaDeRodape, general_title = "Intensidade amostral", footnote_as_chunk = T) # ---- # ********************************************************************* # 3. Amostragem Casual Estratificada (ACE) # **************************************************************** ---- # Escolhe variável de estratificação grupos = c("IDINV") # Box-plot da variável de interesse por nível de estratificação par(mfrow=c( length(grupos), length(variaveisDeInteresse) )) attach(parcelas) for(i in grupos){ for(j in variaveisDeInteresse){ plot( get(i) %>% factor , get(j), main = j, sub=i) } } detach(parcelas) # Estimativa da população para amostragem estratificada popFromStrata = function(factorStrataList){ popEstimates = foreach(i = factorStrataList, .combine = 'c') %do% { gpMeans = lapply(i, function(x) x[1,,drop=F]) %>% do.call(what = rbind) gpVars = lapply(i, function(x) x[2,,drop=F]) %>% do.call(what = rbind) cols = 1:(ncol(gpMeans)-4) popMean = apply(gpMeans[,cols], 2, function(x) sum(x*gpMeans$N) ) /N_ACS popVar = apply(gpVars[,cols], 2, function(x) sum( x * (gpVars$N/N_ACS)^2 ) ) popStdErr = sqrt(popVar) popCI = calcCI(popStdErr, sum(gpMeans$n)) popPars = data.frame( media = popMean, var = popVar, dp = popStdErr, ic = popCI, erro = 100 * popCI / popMean, n = sum( sapply(i, function(x) mean(x$n)) ) ) return(list(popPars)) } names(popEstimates) = names(factorStrataList) return(popEstimates) } if(!require(foreach)) # Para loops inteligentes install.packages("foreach") library(foreach) # Cria vetor de (True ou False) para marcar dados que estejam dentro # do intervalo de idades de interesse (entre 2 e 6) rightAges = talhoes$IDINV > 2 & talhoes$IDINV < 6 # Resultados do inventário (estimação + inferência) # pelo método Amostragem Casual Estratificada (ACE) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ paramEstatisticosACE = foreach( grp = grupos, .combine = 'rbind') %:% foreach( niv = parcelas[,grp] %>% unique %>% as.character %>% sort, .combine = 'rbind' ) %do% { inGroup = talhoes[,grp] == niv popSize = round( sum(talhoes[rightAges & !is.na(inGroup) & inGroup,]$AREA) / parcelaAreaMedia) inGroup = parcelas[,grp] == niv tempPars = parcelas[inGroup, variaveisDeInteresse, drop=F] inventory = calcPars(tempPars, popSize) inventory$grupo = grp inventory$nivel = niv inventory$n = nrow(tempPars) inventory$N = popSize return(inventory) } paramEstatisticosACE %<>% base::split(f=paramEstatisticosACE$grupo) %>% lapply(function(x) split(x, x$nivel)) globalparamEstatisticosACE = popFromStrata(paramEstatisticosACE) # Função para cálculo da intensidade amostral recomendada # (ha por parcela) da ACE que garante ~10% de erro (altere se desejar) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ erro <- 10 tamanhoIdealACE = function(y, g, Nh, errDesired=erro/100){ vars = by(y, g, stats::var) Wh = by(y, g, length) / length(y) Nh = Nh[ names(Nh) %in% g ] B = errDesired * mean(y) n = sum( Nh^2 * vars / Wh ) / ((B^2 * (sum(Nh)^2))/4 + sum(Nh * vars)) return(n) } # Calcula o número possível de unidades amostrais (N) por estrato # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ parcPorEstrato <- round( # Nh by(st_area(talhoesComGeo), talhoes$IDINV, sum) / (mean(parcelas$AREAPARCEL)), 0) IA <- round(AreaTotal/tamanhoIdealACE(y = parcelas$VTCC, g = parcelas$IDINV, Nh = parcPorEstrato), 0) # Intensidade amostral usada por estrato # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IAE <- round(by(st_area(talhoesComGeo)/10000, talhoes$IDINV, sum) / (parcelas %>% count(IDINV))[2])[1] IAS <- paste0(" usada: 1 parc / ", as.character(IAE) , " ha.") # Intensidade amostral que seria necessária para ACE # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ erroTexto <- as.character(erro) IAI <- paste0("\n Necessárias p/ erro de ", erroTexto, "%: 1 parc / ", IA, " ha.") NotaDeRodape <- paste0(IAS, IAI) globalparamEstatisticosACE[[grupos]] %>% t %>% # transpõe o data frame kbl(caption = paste0("Amostragem Casual Estratificada (ACE)"), align = "r") %>% kable_classic(full_width = F) %>% footnote(general = NotaDeRodape, general_title = "Intensidade amostral", footnote_as_chunk = T) # Gráfico de número de amostras necessárias por erro amostral aceitável # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ prjNome <- 'PRJ_Modelo' dirNome <- paste0('C:/LiDAR/', prjNome) dir.create(dirNome, showWarnings = F) dirNome <- paste0(dirNome, '/GRAPH/') dir.create(dirNome, showWarnings = F) arqNome <- paste0(dirNome, prjNome, '_IntAmostral_ACSvsACE.png') erro = 1:20 scsPlotn <- tamanhoIdealACS(parcelas$VTCC, N_ACS, errDesired = erro/100) cssPlotn <- tamanhoIdealACE(parcelas$VTCC, parcelas$IDINV, parcPorEstrato, errDesired = erro/100) # dsPlotn = dubleSamplePlotNumber(plotMetrics$PC_VOL_TOT, # plotMetrics$avgCrownHeight, # cropMetrics$avgCrownHeight, 300, erro/100) png( arqNome, 30, 20, 'cm', res = 200) # abre "impressão" PNG # jpeg(arqNome, 30, 20, 'cm', res = 200) # abre "impressão" JPG plot( scsPlotn ~ erro, type='l', col='red', lwd=2, ylim=c(0,200), ylab='Número de parcelas', xlab='Erro amostral (%)', axes=F) lines(erro, cssPlotn, col='green', lwd=2) # lines(erro, dsPlotn, col='blue', lwd=2) box() axis(1) axis(2, at = c(25, 50, 75, 100, 125, 150, 175, 200)) abline(v=10, col='black', lwd=2, lty=2) lines(c(0,15), rep(100, 2), col='black', lty=2, lwd=2) # lines(c(0,5), rep(dsPlotn[5], 2), col='blue', lty=2, lwd=2) # lines(c(0,5), rep(cssPlotn[5], 2), col='green', lty=2, lwd=2) legend('topright', col=rainbow(3), lwd=2, legend = c('ACS', 'ACE')) # legend = c('ACS', 'ACE', 'AD')) dev.off() # fecha "impressão" # Salva resultados em planilha Excel # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ prjNome <- 'PRJ_Modelo' dirNome <- paste0('C:/LiDAR/', prjNome) dir.create(dirNome, showWarnings = F) dirNome <- paste0(dirNome, '/RSLTS/') dir.create(dirNome, showWarnings = F) arqNome <- paste0(dirNome, prjNome, '_Results.xlsx') export(list(ACS = paramEstatisticosACS, ACE37 = paramEstatisticosACE$IDINV$'3.7', ACE52 = paramEstatisticosACE$IDINV$'5.2'), file = arqNome) # save.image(file='Modelo_inventario.RData') # faz backup dos dados # load('Modelo_inventario.RData') # recupera backup # ----
Referências sobre o pacote lidR para processamento de dados LiDAR:
e sobre os pacotes terra e sf para processamento de dados espaciais:
lidar/projetos/rcode_invconve.txt · Última modificação: 2024/03/23 20:17 por 127.0.0.1