Escolher técnica de Machine Learning Regression e ordene por ano
Escolher uma base do ano de 2019 e praticar:
Utilize a função de regressão:
###### PACOTES E FUNÇÕES AUXILIARES ######
library("dplyr", warn.conflicts = F)
library("kableExtra", warn.conflicts = F)
library("data.table", warn.conflicts = F)
library("DT", warn.conflicts = F)
library("tidyverse", warn.conflicts = F)
library("formattable", warn.conflicts = F)
library("ggplot2",warn.conflicts = F)
library("GGally",warn.conflicts = F)
library("lattice",warn.conflicts = F)
library("PRROC",warn.conflicts = F)
library("caret",warn.conflicts = F)
library("tidyverse",warn.conflicts = F)
library("profvis",warn.conflicts = F)
library("gridExtra",warn.conflicts = F)
#função retirada do help(pairs)
panel.hist <- function(x, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(usr[1:2], 0, 1.5) )
h <- hist(x, plot = FALSE)
breaks <- h$breaks; nB <- length(breaks)
y <- h$counts; y <- y/max(y)
rect(breaks[-nB], 0, breaks[-1], y, col = "cyan", ...)
}
#função retirada do help(pairs)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
Link da base: Gas Turbine CO and NOx Emission Data Set Data Set
O conjunto de dados contém 36733 instâncias de 11 medidas de sensores agregadas ao longo de uma hora (por meio de média ou soma) de uma turbina a gás localizada na região noroeste da Turquia com o objetivo de estudar as emissões de gases de combustão, ou seja, CO e NOx (NO + NO2). Os dados vêm da mesma usina de energia que o conjunto de dados usado para prever o rendimento de energia líquido por hora. Em contrapartida, esses dados são coletados em outra faixa de dados (01.01.2011 - 31.12.2015), inclui parâmetros da turbina a gás (como temperatura de entrada da turbina e pressão de descarga do compressor) além das variáveis ambientais. Observe que as datas não são fornecidas nas instâncias, mas os dados são classificados em ordem cronológica.
Recomendações do site de onde foi extraída a base de dados: Consulte as informações do atributo e o papel relevante para obter detalhes. Siga o protocolo mencionado no artigo (usando os dados dos primeiros três anos para treinamento / validação cruzada e os dois últimos para teste) para reprodutibilidade e comparabilidade dos trabalhos.
O conjunto de dados vai usado para prever o rendimento de energia da turbina (TEY - variável dependente) usando variáveis ambientais como recursos (variáveis independentes).
As explicações sobre as medições do sensor. Abaixo os nomes das variáveis seguido de sua abreviação e unidade:
Abaixo o cabeçalho da base:
setwd("~/UPE/EST_COMPUTACIONAL/gas")
df2011 = fread("gt_2011.csv")
df2012 = fread("gt_2012.csv")
df2013 = fread("gt_2013.csv")
df2014 = fread("gt_2014.csv")
df2015 = fread("gt_2015.csv")
df_treino = rbind(df2011, df2012, df2013)
df_teste = rbind(df2014, df2015)
df_treino %>%
head %>%
kable("html", escape = F) %>%
kable_styling("striped", full_width = F)
| AT | AP | AH | AFDP | GTEP | TIT | TAT | TEY | CDP | CO | NOX |
|---|---|---|---|---|---|---|---|---|---|---|
| 4.5878 | 1018.7 | 83.675 | 3.5758 | 23.979 | 1086.2 | 549.83 | 134.67 | 11.898 | 0.32663 | 81.952 |
| 4.2932 | 1018.3 | 84.235 | 3.5709 | 23.951 | 1086.1 | 550.05 | 134.67 | 11.892 | 0.44784 | 82.377 |
| 3.9045 | 1018.4 | 84.858 | 3.5828 | 23.990 | 1086.5 | 550.19 | 135.10 | 12.042 | 0.45144 | 83.776 |
| 3.7436 | 1018.3 | 85.434 | 3.5808 | 23.911 | 1086.5 | 550.17 | 135.03 | 11.990 | 0.23107 | 82.505 |
| 3.7516 | 1017.8 | 85.182 | 3.5781 | 23.917 | 1085.9 | 550.00 | 134.67 | 11.910 | 0.26747 | 82.028 |
| 3.8858 | 1017.7 | 83.946 | 3.5824 | 23.903 | 1086.0 | 549.98 | 134.67 | 11.868 | 0.23473 | 81.748 |
Observando a natureza das variáveis e o preenchimento delas.
df_qt_cont <- df_treino %>%
select(AT:NOX) %>%
gather(var_continuas)
df_qt_cont %>%
group_by(var_continuas) %>%
summarise("Qtd" = n(),
"Missing" = sum(is.na(value)),
"Media" = mean(value),
"DP" = sd(value),
"Min" = min(value),
"Q1" = quantile(value, 0.25),
"Mediana" = quantile(value, 0.50),
"Q3" = quantile(value, 0.75),
"Max" = max(value)) %>%
mutate_each(funs(round(.,1)), -var_continuas) %>%
kable("html", escape = F) %>%
kable_styling("striped", full_width = F)
| var_continuas | Qtd | Missing | Media | DP | Min | Q1 | Mediana | Q3 | Max |
|---|---|---|---|---|---|---|---|---|---|
| AFDP | 22191 | 0 | 4.0 | 0.8 | 2.1 | 3.4 | 4.1 | 4.5 | 7.6 |
| AH | 22191 | 0 | 79.6 | 13.9 | 27.5 | 70.3 | 82.8 | 90.5 | 100.2 |
| AP | 22191 | 0 | 1012.8 | 6.4 | 985.9 | 1008.8 | 1012.4 | 1016.7 | 1034.2 |
| AT | 22191 | 0 | 17.7 | 7.4 | 0.3 | 11.7 | 17.7 | 23.7 | 34.9 |
| CDP | 22191 | 0 | 12.1 | 1.1 | 9.9 | 11.4 | 12.0 | 12.4 | 15.1 |
| CO | 22191 | 0 | 2.2 | 2.3 | 0.0 | 1.0 | 1.5 | 2.5 | 44.1 |
| GTEP | 22191 | 0 | 25.3 | 4.2 | 17.9 | 22.7 | 25.0 | 26.8 | 37.4 |
| NOX | 22191 | 0 | 68.8 | 11.0 | 27.8 | 61.5 | 67.1 | 74.6 | 119.9 |
| TAT | 22191 | 0 | 545.5 | 7.7 | 512.5 | 542.6 | 549.9 | 550.0 | 550.6 |
| TEY | 22191 | 0 | 133.5 | 16.0 | 100.2 | 124.3 | 133.8 | 138.6 | 174.6 |
| TIT | 22191 | 0 | 1083.1 | 16.8 | 1000.8 | 1074.6 | 1088.1 | 1095.3 | 1100.8 |
Uma breve análise de correlação será feita a partir da correlação de Pearson. Isto é possível pois todas as variáveis são de natureza quantitativa numérica.
A partir das análises de correlação, será decidido quais variáveis entrarão ou não no modelo.
Variáveis independentes que possuem alta correlação entre si, não entrarão as duas no modelo para evitar multicolinearidade (redundância). Assim como variáveis que possuem alta correlação com a variável dependente (TEY), também ficarão de fora do modelo de regressão.
(Valores de referência para correlação de Pearson, segundo Silvia E Shimakura 2006.)
Na ilustração abaixo, já podemos observar que as variáveis TAT, CDP, TIT e GTEP possuem correlação muito forte com a variável dependente TEY.
Também existem diversas variáveis independentes que possuem alta correlação entre elas.
ggcorr(df_treino, label=T)
Para melhor visualização, a base foi dividida em partes pelas variáveis independentes e a variável dependente (TEY).
Nessa primeira ilustração de gráficos de dispersão, observa-se que AT e AP são variáveis candidatas para o modelo, pois possuem fraca correlação com a variável dependente TEY e fraca correlação entre si.
treino_parte1 = df_treino %>% select("TEY", "AT", "AP")#, "AH", "AFDP", "GTEP")
#lattice::splom(treino_parte1)
panel.hist <- function(x, ...)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(treino_parte1, diag.panel = panel.hist, upper.panel = panel.cor)
Nessa segunda ilustração de gráficos de dispersão, observa-se que AFDP e AH são variáveis candidatas a entrar num modelo de regressão para explicar TEY devido a correlação moderada e fraca que eles possuem.
treino_parte2 = df_treino %>% select("TEY","AH","AFDP")#, "GTEP")
#lattice::splom(treino_parte2)
panel.hist <- function(x, ...)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(treino_parte2, diag.panel = panel.hist, upper.panel = panel.cor)
Nessa terceira ilustração de gráficos de dispersão, observa-se que GTEP, TIT não são variáveis candidatas a entrar num modelo de regressão para explicar TEY devido a correlação muito forte que elas possuem entre si e também com a variável dependente.
treino_parte3 = df_treino %>% select("TEY", "GTEP", "TIT")
#lattice::splom(treino_parte3)
panel.hist <- function(x, ...)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(treino_parte3, diag.panel = panel.hist, upper.panel = panel.cor)
Nessa quarta ilustração de gráficos de dispersão, observa-se que TAT, CDP não são variáveis candidatas a entrar num modelo de regressão para explicar TEY devido a correlação forte que elas possuem entre si e também com a variável dependente.
treino_parte4 = df_treino %>% select("TEY", "TAT", "CDP") #, "CO", "NOX")
#lattice::splom(treino_parte4)
panel.hist <- function(x, ...)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(treino_parte4, diag.panel = panel.hist, upper.panel = panel.cor)
Nessa quinta e última ilustração de gráficos de dispersão, observa-se que apenas NOX é uma variável candidata a entrar num modelo de regressão para explicar TEY devido a correlação fraca que ela possui com a variável dependente. A variável CO possui correlação moderada com a variável dependente, por isso poderá entrar no modelo de regressão.
treino_parte5 = df_treino %>% select("TEY", "CO", "NOX")
#lattice::splom(treino_parte5)
panel.hist <- function(x, ...)
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
usr <- par("usr"); on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste0(prefix, txt)
if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(treino_parte5, diag.panel = panel.hist, upper.panel = panel.cor)
No modelo de regressão foram usadas as variáveis AT , AP , AH, NOX, AFDP e CO para explicar TEY.
ajuste_lm <- lm(TEY ~ AT + AP + AH + NOX + AFDP + CO, data = df_treino)
Segue abaixo:
Chamada do modelo;
Medidas resumo dos resíduos;
Tabela de coeficientes, desvios padrão e testes T para hipótese nula de parâmetros iguais a zero;
Média dos quadrados do resíduo e os respectivos graus de liberdade, R^2 ajustado da regressão, Estatística F para qualidade do ajuste (comparação com o modelo com apenas o intercepto).
summary(ajuste_lm)
##
## Call:
## lm(formula = TEY ~ AT + AP + AH + NOX + AFDP + CO, data = df_treino)
##
## Residuals:
## Min 1Q Median 3Q Max
## -33.486 -7.202 0.223 5.478 96.989
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 92.534064 11.649460 7.943 2.06e-15 ***
## AT -0.832036 0.015110 -55.065 < 2e-16 ***
## AP 0.037934 0.011203 3.386 0.00071 ***
## AH -0.145979 0.006354 -22.973 < 2e-16 ***
## NOX -0.060375 0.008280 -7.292 3.16e-13 ***
## AFDP 9.683505 0.089481 108.219 < 2e-16 ***
## CO -2.715593 0.033386 -81.339 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 9.657 on 22184 degrees of freedom
## Multiple R-squared: 0.637, Adjusted R-squared: 0.6369
## F-statistic: 6489 on 6 and 22184 DF, p-value: < 2.2e-16
Observa-se que todas as variáveis do modelo foram signifcativas.
Unindo na mesma base a variável dependente e a predição, calcula-se o AUC.
predicao_treino = predict.lm(ajuste_lm, df_treino)
predicao_teste = predict.lm(ajuste_lm, df_teste)
predicao_treino = as.data.frame(predicao_treino)
predicao_teste = as.data.frame(predicao_teste)
df_teste_predict = cbind.data.frame(df_teste, predicao_teste)
df_treino_predict = cbind.data.frame(df_treino, predicao_treino)
Para ambas as bases, treinamento e teste, o AUC resultou em cerca de 50%.
# ROC Curve treino
roc_treino <- roc.curve(scores.class0 = df_treino_predict$TEY, scores.class1 = df_treino_predict$predicao_treino, curve = T)
plot(roc_treino)
# ROC Curve teste
roc_teste <- roc.curve(scores.class0 = df_teste_predict$TEY, scores.class1 = df_teste_predict$predicao_teste, curve = T)
plot(roc_teste)
Para melhorar o overfitting do modelo, talvez uma validação cruzada resolveria esse problema. Vejamos a seguir:
Ajustando e treinando o modelo com a validação cruzada, temos as seguintes saídas:
ajuste_lm2 <- train(TEY ~ AT + AP + AH + NOX + CO,
data = df_treino,
method = "knn",
preProcess = c("center", "scale"),
tuneLength = 10,
trControl = trainControl(method="cv", number=10))
ajuste_lm2
## k-Nearest Neighbors
##
## 22191 samples
## 5 predictor
##
## Pre-processing: centered (5), scaled (5)
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 19972, 19971, 19973, 19972, 19974, 19972, ...
## Resampling results across tuning parameters:
##
## k RMSE Rsquared MAE
## 5 6.271735 0.8469389 3.656946
## 7 6.298297 0.8456197 3.771124
## 9 6.367264 0.8423062 3.884542
## 11 6.421369 0.8397728 3.979463
## 13 6.478993 0.8370593 4.063056
## 15 6.537991 0.8342359 4.137740
## 17 6.584276 0.8320805 4.201025
## 19 6.638215 0.8294831 4.263267
## 21 6.684270 0.8272352 4.314847
## 23 6.724292 0.8253023 4.363731
##
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was k = 5.
Resultou em k = 5, o número de folds necessários.
# Realizando a predição para os dados de teste e treinamento
predictions_teste <- predict(ajuste_lm2, df_teste)
predictions_treino <- predict(ajuste_lm2, df_treino)
# ROC Curve treino
roc_treino_2 <- roc.curve(scores.class0 = df_treino$TEY, scores.class1 = predictions_treino, curve = T)
plot(roc_treino_2)
# ROC Curve teste
roc_teste_2 <- roc.curve(scores.class0 = df_teste_predict$TEY, scores.class1 = predictions_teste, curve = T)
plot(roc_teste_2)
Como sugerido, foram usados 2011, 2012 e 2013 para treinamento e 2014 e 2015 para teste.
Mesmo com a seleção de variáveis pela correlação de Pearson e utilizando validação cruzada, os resultados não foram satisfatórios devido a um provável compartamento diferente que a base de teste possui em relação a base de treino.
Para solucionar este problema, deve-se usar métodos como Regressão Stepwise para selecionar variáveis onde o modelo aprendesse melhor o comportamento de 2011, 2012 e 2013, afim de refletir uma boa predição para 2014 e 2015.
Visto que estamos falando de anos, o compartamento de treino pode sim ser bem diferente da de teste. Uma outra solução que eu aplicaria, seria juntar todas as bases de 2011 a 2015 e daí separar uma parte para treino e outra para teste. Como por exemplo, 75% da base para treinamento e 25% da base para teste, de forma que mantivessem o mesmo compartamentos gerais da variável dependente.