Os dados utilizados no exemplo são referentes a incêndios em florestas na região Nordeste de Portugal. A tarefa é prever os tamanhos das áreas incendiadas (em hectares). Os dados podem ser encontrados neste link
O dataset é composto de 517 observações com 12 variáveis preditoras e uma variável resposta.
Informações sobre atributos:
* X - coordenada espacial no eixo x
* Y - coordenada espacial no eixo y
* month - mês do ano
* day - dia da semana
* Índices do sistema FWI:
+ FFMC
+ DMC
+ DC
+ ISI
* temp - temperatura em graus celsius
* RH - humidade relativa
* wind - velocidade do vento em km/h
* rain - nível de chuva (em milímetro) por área (em metros quadrados)
* area - área incendiada na floresta (em hectares)
A seguir temos um breve sumário dos dados:
forestfires <- read.csv("~/Documents/ad2/problema3-regressao/forestfire-exemploCaret/forestfires.csv")
summary(forestfires)
## X Y month day FFMC
## Min. :1.000 Min. :2.0 aug :184 fri:85 Min. :18.70
## 1st Qu.:3.000 1st Qu.:4.0 sep :172 mon:74 1st Qu.:90.20
## Median :4.000 Median :4.0 mar : 54 sat:84 Median :91.60
## Mean :4.669 Mean :4.3 jul : 32 sun:95 Mean :90.64
## 3rd Qu.:7.000 3rd Qu.:5.0 feb : 20 thu:61 3rd Qu.:92.90
## Max. :9.000 Max. :9.0 jun : 17 tue:64 Max. :96.20
## (Other): 38 wed:54
## DMC DC ISI temp
## Min. : 1.1 Min. : 7.9 Min. : 0.000 Min. : 2.20
## 1st Qu.: 68.6 1st Qu.:437.7 1st Qu.: 6.500 1st Qu.:15.50
## Median :108.3 Median :664.2 Median : 8.400 Median :19.30
## Mean :110.9 Mean :547.9 Mean : 9.022 Mean :18.89
## 3rd Qu.:142.4 3rd Qu.:713.9 3rd Qu.:10.800 3rd Qu.:22.80
## Max. :291.3 Max. :860.6 Max. :56.100 Max. :33.30
##
## RH wind rain area
## Min. : 15.00 Min. :0.400 Min. :0.00000 Min. : 0.00
## 1st Qu.: 33.00 1st Qu.:2.700 1st Qu.:0.00000 1st Qu.: 0.00
## Median : 42.00 Median :4.000 Median :0.00000 Median : 0.52
## Mean : 44.29 Mean :4.018 Mean :0.02166 Mean : 12.85
## 3rd Qu.: 53.00 3rd Qu.:4.900 3rd Qu.:0.00000 3rd Qu.: 6.57
## Max. :100.00 Max. :9.400 Max. :6.40000 Max. :1090.84
##
Com a função str, podemos ver o tipo das variáveis:
str(forestfires)
## 'data.frame': 517 obs. of 13 variables:
## $ X : int 7 7 7 8 8 8 8 8 8 7 ...
## $ Y : int 5 4 4 6 6 6 6 6 6 5 ...
## $ month: Factor w/ 12 levels "apr","aug","dec",..: 8 11 11 8 8 2 2 2 12 12 ...
## $ day : Factor w/ 7 levels "fri","mon","sat",..: 1 6 3 1 4 4 2 2 6 3 ...
## $ FFMC : num 86.2 90.6 90.6 91.7 89.3 92.3 92.3 91.5 91 92.5 ...
## $ DMC : num 26.2 35.4 43.7 33.3 51.3 ...
## $ DC : num 94.3 669.1 686.9 77.5 102.2 ...
## $ ISI : num 5.1 6.7 6.7 9 9.6 14.7 8.5 10.7 7 7.1 ...
## $ temp : num 8.2 18 14.6 8.3 11.4 22.2 24.1 8 13.1 22.8 ...
## $ RH : int 51 33 33 97 99 29 27 86 63 40 ...
## $ wind : num 6.7 0.9 1.3 4 1.8 5.4 3.1 2.2 5.4 4 ...
## $ rain : num 0 0 0 0.2 0 0 0 0 0 0 ...
## $ area : num 0 0 0 0 0 0 0 0 0 0 ...
Como podemos ver, existem duas variáveis categóricas (month e day). Iremos removê-las para facilitar nossa vida.
require(dplyr)
forestfires <- forestfires %>% select(-day, -month)
require(reshape2)
require(ggplot2)
df <- melt(forestfires)
ggplot(df,aes(x = value)) +
facet_wrap(~variable, scales = "free_x") +
geom_histogram()
Ao analisar os histogramas, é interessante observar em quais gráficos existem muita assimetria. Recomenda-se realizar um ajuste nessas variáveis aplicando alguma função que gere dados mais próximos de uma distribuição normal.
forestfires$log.Y <- log(forestfires$Y)
forestfires$log.DC <- log(forestfires$DC + 1)
forestfires$log.RH <- log(forestfires$RH)
forestfires$log.wind <- log(forestfires$wind)
forestfires$log.area <- log(forestfires$area + 1)
df <- melt(forestfires)
ggplot(df,aes(x = value)) +
facet_wrap(~variable, scales = "free_x") +
geom_histogram()
require(caret)
trainIndex <- createDataPartition(forestfires$log.area, p = .75, list = FALSE)
train <- forestfires[trainIndex,]
test <- forestfires[-trainIndex,]
Para realizar o treinamento, deve-se assumir as seguintes proposições:
- A relação entre preditores e variável resposta é aproximadamente linear.
- Um bom preditor está consideravelmente bem correlacionado com a variável resposta.
- Preditores com alta colinearidade geram instabilidade no modelo.
- Um preditor não deve ser derivado da combinação linear dos demais.
- Há um número igual ou maior de observações do que preditores (isso tenta evitar a maldição da dimensionalidade).
correlationMatrix <- cor(forestfires)
print(correlationMatrix)
## X Y FFMC DMC DC
## X 1.000000000 0.539548171 -0.02103927 -0.048384178 -0.08591612
## Y 0.539548171 1.000000000 -0.04630755 0.007781561 -0.10117777
## FFMC -0.021039272 -0.046307546 1.00000000 0.382618800 0.33051180
## DMC -0.048384178 0.007781561 0.38261880 1.000000000 0.68219161
## DC -0.085916123 -0.101177767 0.33051180 0.682191612 1.00000000
## ISI 0.006209941 -0.024487992 0.53180493 0.305127835 0.22915417
## temp -0.051258262 -0.024103084 0.43153226 0.469593844 0.49620805
## RH 0.085223194 0.062220731 -0.30099542 0.073794941 -0.03919165
## wind 0.018797818 -0.020340852 -0.02848481 -0.105342253 -0.20346569
## rain 0.065387168 0.033234103 0.05670153 0.074789982 0.03586086
## area 0.063385299 0.044873225 0.04012200 0.072994296 0.04938323
## log.Y 0.531494601 0.973352433 -0.05172036 -0.000110987 -0.09158812
## log.DC -0.063975630 -0.070535390 0.34530923 0.653334918 0.94651532
## log.RH 0.080301614 0.055065326 -0.25946727 0.084086452 -0.01430512
## log.wind 0.033862600 0.003378939 0.01494708 -0.069256421 -0.15982208
## log.area 0.061994908 0.038838213 0.04679856 0.067152740 0.06635976
## ISI temp RH wind rain
## X 0.006209941 -0.05125826 0.08522319 0.018797818 0.065387168
## Y -0.024487992 -0.02410308 0.06222073 -0.020340852 0.033234103
## FFMC 0.531804931 0.43153226 -0.30099542 -0.028484809 0.056701533
## DMC 0.305127835 0.46959384 0.07379494 -0.105342253 0.074789982
## DC 0.229154169 0.49620805 -0.03919165 -0.203465691 0.035860862
## ISI 1.000000000 0.39428710 -0.13251718 0.106825888 0.067668190
## temp 0.394287104 1.00000000 -0.52739034 -0.227116220 0.069490547
## RH -0.132517177 -0.52739034 1.00000000 0.069410067 0.099751223
## wind 0.106825888 -0.22711622 0.06941007 1.000000000 0.061118880
## rain 0.067668190 0.06949055 0.09975122 0.061118880 1.000000000
## area 0.008257688 0.09784411 -0.07551856 0.012317277 -0.007365729
## log.Y -0.026017226 -0.03807040 0.06945431 -0.007171111 0.037843476
## log.DC 0.286186198 0.53133294 -0.06596066 -0.171909763 0.033787859
## log.RH -0.128587013 -0.50179002 0.97586364 0.044159611 0.094891378
## log.wind 0.116384763 -0.15355750 0.04786933 0.949644419 0.059946913
## log.area -0.010346879 0.05348655 -0.05366216 0.066973489 0.023311313
## area log.Y log.DC log.RH log.wind
## X 0.063385299 0.531494601 -0.06397563 0.08030161 0.033862600
## Y 0.044873225 0.973352433 -0.07053539 0.05506533 0.003378939
## FFMC 0.040122004 -0.051720356 0.34530923 -0.25946727 0.014947084
## DMC 0.072994296 -0.000110987 0.65333492 0.08408645 -0.069256421
## DC 0.049383225 -0.091588119 0.94651532 -0.01430512 -0.159822076
## ISI 0.008257688 -0.026017226 0.28618620 -0.12858701 0.116384763
## temp 0.097844107 -0.038070402 0.53133294 -0.50179002 -0.153557500
## RH -0.075518563 0.069454306 -0.06596066 0.97586364 0.047869333
## wind 0.012317277 -0.007171111 -0.17190976 0.04415961 0.949644419
## rain -0.007365729 0.037843476 0.03378786 0.09489138 0.059946913
## area 1.000000000 0.035214168 0.05203853 -0.07895492 0.027440629
## log.Y 0.035214168 1.000000000 -0.06798841 0.06262184 0.013881816
## log.DC 0.052038530 -0.067988410 1.00000000 -0.04187272 -0.131526348
## log.RH -0.078954922 0.062621841 -0.04187272 1.00000000 0.033396499
## log.wind 0.027440629 0.013881816 -0.13152635 0.03339650 1.000000000
## log.area 0.524134036 0.047660541 0.06900635 -0.04964497 0.066917694
## log.area
## X 0.06199491
## Y 0.03883821
## FFMC 0.04679856
## DMC 0.06715274
## DC 0.06635976
## ISI -0.01034688
## temp 0.05348655
## RH -0.05366216
## wind 0.06697349
## rain 0.02331131
## area 0.52413404
## log.Y 0.04766054
## log.DC 0.06900635
## log.RH -0.04964497
## log.wind 0.06691769
## log.area 1.00000000
library(corrplot)
corrplot(correlationMatrix, method="circle", type="lower", order="hclust")
Observe este gráfico atentamente. Variáveis correlacionadas com seus respectivos logs estão altamente relacionadas. Seria algo redundante utilizar ambas para gerar no modelo. Variáveis bem correlacionadas com a variável resposta produzirão modelos com resultados mais expressivos.
É possível perceber que as variáveis preditoras estão fracamente correlacionadas com a variável resposta log.area. Isso não é um bom sinal.
#parâmetro de ajuste
fitControl <- trainControl(## 10-fold CV
method = "cv",
number = 10)
lm <- lm(log.area ~ FFMC + temp + DMC + log.DC + log.wind + X + log.Y + RH ,
data = forestfires)
lm
##
## Call:
## lm(formula = log.area ~ FFMC + temp + DMC + log.DC + log.wind +
## X + log.Y + RH, data = forestfires)
##
## Coefficients:
## (Intercept) FFMC temp DMC log.DC
## 0.472996 -0.001689 -0.007535 0.001324 0.084991
## log.wind X log.Y RH
## 0.212060 0.035626 0.106713 -0.007121
summary(lm)
##
## Call:
## lm(formula = log.area ~ FFMC + temp + DMC + log.DC + log.wind +
## X + log.Y + RH, data = forestfires)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.5929 -1.0951 -0.5969 0.9130 5.6667
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.472996 1.309338 0.361 0.7181
## FFMC -0.001689 0.013070 -0.129 0.8972
## temp -0.007535 0.016585 -0.454 0.6498
## DMC 0.001324 0.001415 0.935 0.3501
## log.DC 0.084991 0.091025 0.934 0.3509
## log.wind 0.212060 0.125435 1.691 0.0915 .
## X 0.035626 0.031521 1.130 0.2589
## log.Y 0.106713 0.236857 0.451 0.6525
## RH -0.007121 0.005073 -1.404 0.1611
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.395 on 508 degrees of freedom
## Multiple R-squared: 0.0204, Adjusted R-squared: 0.004971
## F-statistic: 1.322 on 8 and 508 DF, p-value: 0.2297
Residuals: fornecem o valor mínimo, primeiro quartil, mediana
terceiro quartil e valor máximo dos resíduos da regressão
A distribuição dos resíduos, tal como estimada com esses números,
deve ser simétrica, a mediana deveria ser perto de 0,
Os valores de 1Q e 3Q deveriam ter valor absoluto semelhantes.
Coefficients: fornecem os valores estimados de beta_0 hat e beta_1 hat
(Estimate), o desvio padrão dos valores (Std. Error),
o valor t (t value) e o p-valor associado Pr(>|t|)
O desvio padrão fornece uma estimativa da incerteza associada aos
coeficientes do modelo.
A estatística t é igual ao coeficiente dividido pelo desvio padrão.
Neste caso, com p-valor muito baixo, os dois coeficientes são estatisticamente significativos, isto é, diferentes de zero.
Residual standard error: valor estimado do desvio padrão dos resíduos.
R-squared: a fração da variância em log.psa explicada por log.vol
Adjusted R-squared: igual a R-squared com ajuste pela complexidade
do modelo (o número de parâmetros).
Não tem importância para um modelo tão simples com 1 preditor.
F-statistic: a razão entre a variância explicada pelo modelo e a variância residual ou não explicada.
Se este valor for alto (com p-valor baixo), significa que o modelo explica
mais variância do que a não explicada.
prediction <- predict(lm, select(test,FFMC,temp ,DMC ,log.DC,log.wind,X,log.Y,RH))
exp.prediction <- exp(prediction) - 1 #transformando o vetor de predição para a unidade original do problema (em ha).
lm_prediction <- data.frame(pred = exp.prediction, obs = test$area)
ggplot(lm_prediction, aes(x = pred, y = obs)) + geom_point(alpha = 0.5, position = position_jitter(width=0.2)) + geom_abline(colour = "blue") + ggtitle("Previsão x Observado (validação)")
round(defaultSummary(lm_prediction), digits = 3)
## RMSE Rsquared
## 21.949 0.002
O RMSE alto indica que o erro na predição foi alto. O que acontece é que, por conta dos outliers, o modelo se ajusta bem a boa parte dos dados tendo como consequência grandes erros na previsão alguns valores. Dependendo do caso, isso pode indicar que a regressão não seria a melhor técnica para resolver o problema.
ggplot(lm_prediction, aes(y = obs - pred, x = pred)) +
geom_point(alpha = 0.5, position = position_jitter(width=0.1)) +
geom_abline(slope = 0, intercept = 0, colour = "darkred")
fitControl <- trainControl(method='cv', number = 10)
lasso.fit <- train(log.area ~ ., data=select(train, FFMC,ISI,temp,DMC,log.DC,log.wind,X,log.Y ,RH, log.area),
method='lasso',
metric="RMSE",
tuneLength = 10,
trControl=fitControl)
plot(lasso.fit)
lasso.fit
## The lasso
##
## 389 samples
## 9 predictor
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 350, 350, 349, 350, 351, 350, ...
## Resampling results across tuning parameters:
##
## fraction RMSE Rsquared RMSE SD Rsquared SD
## 0.1000000 1.424426 0.02738409 0.1749171 0.02680433
## 0.1888889 1.424673 0.02084919 0.1752045 0.01790298
## 0.2777778 1.425126 0.02005852 0.1755858 0.02333097
## 0.3666667 1.425356 0.02027669 0.1763439 0.02804242
## 0.4555556 1.424778 0.02211763 0.1776085 0.03179565
## 0.5444444 1.423886 0.02457893 0.1793339 0.03484948
## 0.6333333 1.422838 0.02667298 0.1805959 0.03694805
## 0.7222222 1.421879 0.02840167 0.1810235 0.03822739
## 0.8111111 1.421340 0.02984201 0.1815390 0.03938656
## 0.9000000 1.421776 0.02963991 0.1824419 0.03808917
##
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.8111111.
A função train tentou 10 valores para fraction e achou valor ótimo (RMSE mais baixo).
plot(varImp(lasso.fit))
lasso_prediction <- predict(lasso.fit, select(test, FFMC,ISI,temp,DMC,log.DC,log.wind,X,log.Y ,RH))
exp.lasso_prediction <- exp(lasso_prediction) - 1 #transformando o vetor de predição para a unidade original do problema (em ha).
lasso_prediction <- data.frame(pred = exp.lasso_prediction, obs = test$area)
round(defaultSummary(lasso_prediction), digits = 3)
## RMSE Rsquared
## 21.954 0.004
compare <- lm_prediction
compare$model <- "RL"
lasso_prediction$model <- "LASSO"
compare <- rbind(compare, lasso_prediction)
ggplot(compare, aes(x = pred, y = obs)) +
geom_point(alpha = 0.5, position = position_jitter(width=0.2)) +
facet_grid(. ~ model) +
geom_abline() +
ggtitle("Observado x Previsão (validação)")
round(defaultSummary(lasso_prediction), digits = 3)
## RMSE Rsquared
## 21.954 0.004
round(defaultSummary(lm_prediction), digits = 3)
## RMSE Rsquared
## 21.949 0.002
O melhor modelo será aquele que possuir o RMSE mais baixo. Como podemos ver, ambos os modelos produziram um RMSE alto, sugerindo que a regressão linear talvez não seja uma boa solução para este problema.
Contudo, analisando os gráficos, podemos observar que a regressão se ajustou bem aos valores observados e parece encontrar resultados bem aproximados. Sendo assim, o que causa o alto valor do RMSE?
Podemos culpar os outliers. O RMSE é calculado através da raiz quadrada da média dos erros quadrados. Com isso, quanto maior os erros, maior o RMSE. Como os outliers possuem valores altíssimos (houve um incêndio em 1200 ha, por exemplo), isso faz com que a métrica aumente consideravelmente.
Dependendo do problema, indica-se remover os outliers, pois estes são considerados comportamentos atípicos nos dados. Neste problema em específico, entendo que o objetivo seja prever os outliers, que seriam catástrofes de grandes áreas incendiadas. Com isso, o indicado seria buscar um modelo alternativo a regressão linear.