#~~~~~~~~~~~~~~~~ 1 - IMPORTAÇÂO DOS DADOS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Definir diretório aonde encontra-se a planilha
setwd("C:/Trabalho_IVs_SR")
#Importar a planilha  e armazenar dentro do objeto dados
dados=read.table("planilha_ivs_COMPLETA.csv", header = T, sep=",")
#Remover dadps com problemas (nessa planilha, os ídices Ctr1 e LWCI estão comprometidos)
dados=subset(dados, select = -c(Ctr1, LWCI))
#Definir como fator de analise a coluna que contém a variavel resposta
dados$especie=factor(dados$especie)

#~~~~~~~~~~~~~~~~ 2 - PARTICIONAMENTO TREINO/TESTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Divisao aleatoria do conjunto de dados para treinamento (70%) e teste (30%)
# A sequencia de comandos abaixo realiza o sorteio dentro de cada classe,
# Ou seja, para cada espécie 21 amostras são sorteadas para treinamento e 9 para teste
# O sorteio foi pensado dessa forma para assegur que existam representantes de cada classe 
# durante o treinamento dos modelos
# A funcao "particionamento"  foi construida para realizar essa tarefa. O sorteio é feito
# dentro de cada nivel do fator 
# Essa funcao é generica e pode ser aplicada a qualqer base de dados, considerando 
# os seguintes argumentos:
# "dados": Base de dados que sera particionada
# "dados_fator" : Coluna da base de dados de armazena a variavel que constitui o fator de analise 
# (nesse caso a coluna com a identificacao das especies).
# "proporcao_treino" : valor decimal indicando a proporcao destinada ao conjunto de treinamento

particionamento=function(dados, dados_fator, proporcao_treino){
  
  fator=factor(dados_fator)
  niveis_fatores=levels(fator)
  
  f=function(niveis_fatores){
      for(i in 1:length(niveis_fatores)){
      a=subset(dados,dados_fator==niveis_fatores[i])
      sorteio = sample(1:nrow(a), proporcao_treino*nrow(a), replace = FALSE)
      treino= data.frame(); treino = a[sorteio,];teste = data.frame(); teste = a[-sorteio,]
      amostras=list(treino,teste)}
    return(amostras)}
  
  treino=c()
  teste=c()
  for(i in 1:length(niveis_fatores)){
    t=f(niveis_fatores[i])
    treino=rbind(treino,t[[1]])
    teste=rbind(teste,t[[2]])
    amostragem=list(treino,teste)}
  return(amostragem)}
particoes=particionamento(dados, dados$especie, 0.7)

# A funcao "particionamento" retorna um objeto do tipo "list", com duas listas internas. 
# A primeira lista, [[1]], armazena o subconjunto de treinamento, 
# enquanto a segunda, [[2]], os dados de teste.  
# Dessa forma, particoes[[1]] resgata os dados de treino e particoes[[2]], 
# resgata os dados de teste. 

#Parcela de dados para treinamento
dados_treino=data.frame(particoes[[1]])
length(dados_treino$especie) #210
## [1] 210
summary(dados_treino$especie) #treinamento 70% (21 repeticoes)
##   Acoita    Amora    Araca    Cedro Cinanomo     Inga Ipeamare  Iperoxo 
##       21       21       21       21       21       21       21       21 
## Pitangue  Platano 
##       21       21
#Parcela para teste/validacao
dados_teste=data.frame(particoes[[2]])
length(dados_teste$especie) #90
## [1] 90
summary(dados_teste$especie) #teste 30% (9 repeticoes)
##   Acoita    Amora    Araca    Cedro Cinanomo     Inga Ipeamare  Iperoxo 
##        9        9        9        9        9        9        9        9 
## Pitangue  Platano 
##        9        9
#~~~~~~~~~~~~~~~~ 3 - TREINAR E VALIDAR OS MODELOS COM TODOS OS INDICES~~~~~~~~~~~~~~~~~~~~~~~~~~~

# 3.1 - Random Forest - RF
library(randomForest)
## randomForest 4.7-1.1
## Type rfNews() to see new features/changes/bug fixes.
rf=randomForest(especie ~.,data=dados_treino, ntree=1000, mtry=10)
# ntree: Número de árvores aleatórias criadas durante no treinamento
# mtry: Número de variáveis sorteadas para compor cada árvore
# ref: https://www.rdocumentation.org/packages/randomForest/versions/4.7-1.1/topics/randomForest
table(predict(rf),dados_treino$especie)
##           
##            Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
##   Acoita       21     0     0     0        0    0        0       0        0
##   Amora         0    20     0     0        0    0        0       0        0
##   Araca         0     0    20     0        0    0        0       0        0
##   Cedro         0     0     0    21        0    0        0       0        0
##   Cinanomo      0     0     0     0       19    0        0       0        0
##   Inga          0     0     0     0        0   21        0       0        0
##   Ipeamare      0     0     1     0        0    0       21       0        0
##   Iperoxo       0     0     0     0        0    0        0      21        0
##   Pitangue      0     0     0     0        0    0        0       0       21
##   Platano       0     1     0     0        2    0        0       0        0
##           
##            Platano
##   Acoita         0
##   Amora          2
##   Araca          0
##   Cedro          2
##   Cinanomo       2
##   Inga           0
##   Ipeamare       0
##   Iperoxo        1
##   Pitangue       0
##   Platano       14
rf
## 
## Call:
##  randomForest(formula = especie ~ ., data = dados_treino, ntree = 1000,      mtry = 10) 
##                Type of random forest: classification
##                      Number of trees: 1000
## No. of variables tried at each split: 10
## 
##         OOB estimate of  error rate: 5.24%
## Confusion matrix:
##          Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
## Acoita       21     0     0     0        0    0        0       0        0
## Amora         0    20     0     0        0    0        0       0        0
## Araca         0     0    20     0        0    0        1       0        0
## Cedro         0     0     0    21        0    0        0       0        0
## Cinanomo      0     0     0     0       19    0        0       0        0
## Inga          0     0     0     0        0   21        0       0        0
## Ipeamare      0     0     0     0        0    0       21       0        0
## Iperoxo       0     0     0     0        0    0        0      21        0
## Pitangue      0     0     0     0        0    0        0       0       21
## Platano       0     2     0     2        2    0        0       1        0
##          Platano class.error
## Acoita         0  0.00000000
## Amora          1  0.04761905
## Araca          0  0.04761905
## Cedro          0  0.00000000
## Cinanomo       2  0.09523810
## Inga           0  0.00000000
## Ipeamare       0  0.00000000
## Iperoxo        0  0.00000000
## Pitangue       0  0.00000000
## Platano       14  0.33333333
#Avaliacao desempenho sobre os dados de teste do Random Forest
confusao_rf=table(predict(rf,dados_teste),dados_teste$especie)
confusao_rf
##           
##            Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
##   Acoita        9     0     0     0        0    0        0       0        0
##   Amora         0     8     0     0        0    0        0       0        0
##   Araca         0     0     8     0        0    0        0       0        0
##   Cedro         0     0     0     9        0    0        0       0        0
##   Cinanomo      0     0     0     0        9    2        0       0        0
##   Inga          0     0     0     0        0    7        0       0        0
##   Ipeamare      0     0     1     0        0    0        9       0        0
##   Iperoxo       0     0     0     0        0    0        0       9        0
##   Pitangue      0     0     0     0        0    0        0       0        9
##   Platano       0     1     0     0        0    0        0       0        0
##           
##            Platano
##   Acoita         0
##   Amora          0
##   Araca          0
##   Cedro          0
##   Cinanomo       0
##   Inga           0
##   Ipeamare       0
##   Iperoxo        1
##   Pitangue       0
##   Platano        8
acerto_rf=sum(diag(confusao_rf))/sum(confusao_rf)
acerto_rf
## [1] 0.9444444
# 3.2 - Support Vector Machine - SVM
#install.packages("e1071", dependencies=T)
library(e1071)
m_svm=svm(especie~.,dados_treino, kernel="polynomial", gamma=0.1, cost=10)
#Informações sobre os hiperparametros:
# https://www.rdocumentation.org/packages/e1071/versions/1.7-11/topics/svm

#Avaliacao desempenho sobre os dados de teste do SVM
confusao_svm=table(predict(m_svm,dados_teste),dados_teste$especie)
confusao_svm
##           
##            Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
##   Acoita        9     0     0     0        0    0        0       0        0
##   Amora         0     8     0     0        0    0        0       0        0
##   Araca         0     0     8     0        0    0        0       0        0
##   Cedro         0     0     0     9        0    0        0       0        0
##   Cinanomo      0     0     0     0        9    1        0       0        0
##   Inga          0     0     0     0        0    8        0       0        0
##   Ipeamare      0     0     1     0        0    0        9       2        0
##   Iperoxo       0     0     0     0        0    0        0       6        0
##   Pitangue      0     0     0     0        0    0        0       0        9
##   Platano       0     1     0     0        0    0        0       1        0
##           
##            Platano
##   Acoita         0
##   Amora          1
##   Araca          0
##   Cedro          0
##   Cinanomo       1
##   Inga           0
##   Ipeamare       0
##   Iperoxo        1
##   Pitangue       0
##   Platano        6
acerto_svm=sum(diag(confusao_svm))/sum(confusao_svm)
acerto_svm
## [1] 0.9
# 3.3 - Artificial Neural Network - ANN 
#install.packages("neuralnet", dependencies=T)
library(neuralnet)
#Ao rodar a rede neural perceptron do pacote neuralnet, melhores resultados são obtidos 
#com os dados normalizados
#Normalização dos dados
treino_nnet=data.frame(scale(dados_treino[,-236]),especie=dados_treino$especie)
teste_nnet=data.frame(scale(dados_teste[,-236]),especie=dados_teste$especie)

#Criacao do modelo com a rede neural perceptron do pacote neuralnet
nnet=neuralnet(especie~., treino_nnet, hidden = c(59,39,26,17,7), linear.output = F,
               threshold = 0.01,
               stepmax = 1e+05, rep = 1, startweights = NULL,
               learningrate.limit = NULL, learningrate.factor = list(minus = 0.5, plus = 1.2))
# hidden = c(59,39,26,17,7) - Numero de neuronios em cada camada da rede. Como recomendação 
# usa-se a regra dos 2/3 (A primeira camada tem 2/3 do numero de amostras. 
# A segunda camada de neuronios possui 2/3 da primeira e assim sucessivamente)
# Sobre os demais hiperparametros:
# https://www.rdocumentation.org/packages/neuralnet/versions/1.44.2/topics/neuralnet

pred_treino=as.data.frame(nnet$net.result)
names(pred_treino)=levels(treino_nnet$especie)
pred_treino$class=colnames(pred_treino[,1:10])[max.col(pred_treino[,1:10], ties.method = 'first')]
confusao_treino=table(pred_treino$class,treino_nnet$especie)
confusao_treino
##           
##            Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
##   Acoita       21     0     0     0        0    0        0       0        0
##   Amora         0    21     0     0        0    0        0       0        0
##   Araca         0     0    21     0        0    0        0       0        0
##   Cedro         0     0     0    21        0    0        0       0        0
##   Cinanomo      0     0     0     0       21    0        0       0        0
##   Inga          0     0     0     0        0   21        0       0        0
##   Ipeamare      0     0     0     0        0    0       21       0        0
##   Iperoxo       0     0     0     0        0    0        0      21        0
##   Pitangue      0     0     0     0        0    0        0       0       21
##   Platano       0     0     0     0        0    0        0       0        0
##           
##            Platano
##   Acoita         0
##   Amora          0
##   Araca          0
##   Cedro          0
##   Cinanomo       0
##   Inga           0
##   Ipeamare       0
##   Iperoxo        0
##   Pitangue       0
##   Platano       21
#Avaliacao desempenho sobre os dados de teste da ANN

ypred = neuralnet::compute(nnet, teste_nnet)
ypred = as.data.frame(ypred$net.result)
names(ypred)=levels(teste_nnet$especie)
ypred$class = colnames(ypred[,1:10])[max.col(ypred[,1:10], ties.method = 'first')]
confusao_nnet = table(ypred$class,teste_nnet$especie)
confusao_nnet
##           
##            Acoita Amora Araca Cedro Cinanomo Inga Ipeamare Iperoxo Pitangue
##   Acoita        9     0     0     0        0    1        0       0        0
##   Amora         0     6     0     1        0    0        1       0        0
##   Araca         0     0     8     0        0    1        1       0        0
##   Cedro         0     0     0     8        0    0        0       0        0
##   Cinanomo      0     0     0     0        9    3        0       0        0
##   Inga          0     0     1     0        0    3        0       0        0
##   Ipeamare      0     0     0     0        0    0        7       0        0
##   Iperoxo       0     0     0     0        0    0        0       9        0
##   Pitangue      0     2     0     0        0    0        0       0        9
##   Platano       0     1     0     0        0    1        0       0        0
##           
##            Platano
##   Acoita         1
##   Amora          2
##   Araca          0
##   Cedro          1
##   Cinanomo       1
##   Inga           0
##   Ipeamare       0
##   Iperoxo        2
##   Pitangue       0
##   Platano        2
acerto_nnet=sum(diag(confusao_nnet))/sum(confusao_nnet)
acerto_nnet
## [1] 0.7777778
 #~~~~~~~~~~~~~~~~ 4 - TREINAR E VALIDAR OS MODELOS COM OS INDICES SELECIONADOS~~~~~~~~~~~~~~~~~~~~~

#4.1 Ranking de importancia Random Forest
# Resgata os scores das variaveis preditoras junto ao modelo RF treinado 
importancia=importance(rf)
ranking=data.frame(importancia)
ranking=data.frame(rownames(ranking),ranking$MeanDecreaseGini)
names(ranking)
## [1] "rownames.ranking."        "ranking.MeanDecreaseGini"
ranking=ranking[order(ranking[,2],decreasing = T),]

#Plotar gráfico com o índice de GINI para avaliar o "ponto de corte" no número de preditores
plot(ranking$ranking.MeanDecreaseGini, xlab= "Número de preditores", ylab= " Mean Decrease GINI") 

#Quanto maior o índice de GINI mais relevante é a variável
head(ranking,20) #Mostrar as 20 primeiras linhas do objeto ranking
##     rownames.ranking. ranking.MeanDecreaseGini
## 180            SB1420                 4.646938
## 50                MVI                 3.822940
## 178            SB1200                 3.761037
## 181            SB1450                 3.430822
## 167        SR833_1649                 3.164739
## 53          MCARI1510                 3.067699
## 2            AFRI1600                 2.925117
## 177            SB1120                 2.903208
## 179            SB1400                 2.828553
## 185            SB1540                 2.792149
## 182            SB1490                 2.732887
## 183            SB1510                 2.701665
## 218             SB910                 2.640938
## 91               NDMI                 2.542725
## 220             SB990                 2.509670
## 219             SB930                 2.317181
## 122               MSI                 1.963154
## 155            DSWI_1                 1.954123
## 7           AR750_850                 1.944875
## 228               WET                 1.845721
# Grafico opcional para visualizar as variáveis mais importantes
varImpPlot(rf)

#Filtrar (Por exemplo) as 10 variaveis mais importantes
var=as.character(ranking[1:10,1])

#Aplicar a selecao de variaveis sobre o conjunto de dados treino
selecao_treino=dados_treino[,var[]]
selecao_treino =data.frame(selecao_treino,especie=dados_treino$especie)
head(selecao_treino)
##       SB1420       MVI    SB1200    SB1450 SR833_1649   MCARI1510   AFRI1600
## 20 0.2328185 0.6783276 0.5490159 0.2056960   1.513549 -0.05955238 -0.4350953
## 21 0.2174971 0.6596526 0.5304922 0.1963648   1.513406 -0.05213464 -0.4514931
## 4  0.2468327 0.6974400 0.5549001 0.2250736   1.462303 -0.07071857 -0.4323397
## 9  0.2436155 0.7112731 0.5194206 0.2056841   1.386189 -0.06778746 -0.4681777
## 15 0.2249213 0.6400222 0.5360963 0.2032251   1.551487 -0.05717062 -0.4385034
## 23 0.2351394 0.6781678 0.5537630 0.2129303   1.473557 -0.05868277 -0.4430847
##       SB1120    SB1400    SB1540 especie
## 20 0.5873234 0.3202901 0.3086413  Acoita
## 21 0.5583793 0.3100394 0.2823689  Acoita
## 4  0.5827512 0.3337514 0.3191585  Acoita
## 9  0.5452921 0.3293867 0.3000632  Acoita
## 15 0.5761419 0.3133014 0.2803870  Acoita
## 23 0.5682686 0.3198699 0.3049400  Acoita
#Aplicar a selecao de variaveis sobre o conjunto de dados teste
selecao_teste=dados_teste[,var[]]
selecao_teste =data.frame(selecao_teste,especie=dados_teste$especie)
head(selecao_teste)
##       SB1420       MVI    SB1200    SB1450 SR833_1649   MCARI1510   AFRI1600
## 5  0.2404670 0.6935337 0.5433676 0.2251143   1.480904 -0.07146529 -0.4317878
## 8  0.2456984 0.6936780 0.5127410 0.2100551   1.491303 -0.06028026 -0.4635366
## 11 0.2436912 0.6775980 0.5499068 0.2108449   1.466020 -0.06068689 -0.4347588
## 16 0.2397257 0.6680299 0.5455996 0.2102325   1.481646 -0.05760962 -0.4401471
## 19 0.2297520 0.6554117 0.5365095 0.2047166   1.587894 -0.05025108 -0.4364687
## 22 0.2231307 0.6556364 0.5431486 0.2041344   1.544419 -0.05252724 -0.4392763
##       SB1120    SB1400    SB1540 especie
## 5  0.5848209 0.3395051 0.3248342  Acoita
## 8  0.5439228 0.3275356 0.3054879  Acoita
## 11 0.5732949 0.3280475 0.3050638  Acoita
## 16 0.5678229 0.3284755 0.2925872  Acoita
## 19 0.5806264 0.3113537 0.2918864  Acoita
## 22 0.5878295 0.3204495 0.2809013  Acoita
##############################################################################
#4.2 Rodar novamente os modelos, agora com o banco de dados reduzido

# Construir novamente os modelos, aplicando agora os subconjuntos selecao_treino e selecao_teste