1. Introdução aos Problemas de Regressão
Problemas de regressão visam prever valores contínuos, como a resistência à compressão do concreto, temperatura ou preço de imóveis. Esta análise abrange quatro pilares: distinção entre modelos de regressão e classificação, métricas de avaliação essenciais, abordagens para regressão com múltiplas saídas, e o uso de intervalos de confiança via bootstrap.
2. Modelos de Regressão vs. Classificação
A diferença fundamental reside no objetivo: regressores preveem quantidades (ex.: "quanto"), enquanto classificadores determinam categorias (ex.: "qual"). Regressores utilizam variância para divisões, e classificadores usam medidas de pureza como o índice Gini. Modelos como LinearRegression e RandomForestRegressor são exemplos de regressores, enquanto LogisticRegression pertence à classificação, apesar do nome.
3. Métricas de Avaliação para Regressão
- Erro Absoluto Médio (MAE): Média dos erros absolutos, sendo robusto a outliers.
- Erro Quadrático Médio (MSE): Penaliza erros maiores, ampliando o impacto de valores atípicos.
- Raiz do Erro Quadrático Médio (RMSE): Mantém a mesma unidade dos dados originais, comum em artigos acadêmicos.
- Coeficiente de Determinação (R²): Varia de 0 a 1, onde valores próximos de 1 indicam melhor ajuste.
4. Regressão com Múltiplas Saídas
Para prever múltiplas variáveis contínuas simultaneamente, como temperatura e umidade, existem três estratégias principais: utilizar modelos com suporte nativo (ex.: redes neurais), aplicar wrappers como MultiOutputRegressor do scikit-learn, ou treinar modelos independentes para cada saída, perdendo possíveis correlações entre as variáveis alvo.
5. Intervalos de Confiança e Bootstrap
Intervalos de confiança fornecem uma faixa de valores prováveis para uma estiamtiva, em vez de um valor pontual. Por exemplo, um intervalo de 95% indica que, com 95% de probabilidade, o valor real está dentro daquela faixa. O bootstrap é uma técnica computacional que gera múltiplas amostras por reamostragem com reposição, permitindo a estimação desses intervalos sem suposições distributivas complexas.
6. Implementação Prática com Dados de Concreto
6.1 Preparação do Ambiente e Carregamento dos Dados
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
plt.rcParams['font.sans-serif'] = ['Arial']
plt.rcParams['axes.unicode_minus'] = False
sns.set(style="whitegrid")
# Carregar o dataset UCI Concrete Compressive Strength
url_concrete = "https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/concrete.csv"
try:
dataframe = pd.read_csv(url_concrete)
print("Dados carregados com sucesso.")
except Exception as erro:
print(f"Falha ao carregar dados: {erro}")
raise erro
# Renomear colunas para nomes descritivos em português
colunas_descritivas = [
'Cimento', 'Escória', 'CinzaVolante', 'Água',
'Superplastificante', 'AgregadoGrosso', 'AgregadoFino',
'Idade', 'Resistencia'
]
dataframe.columns = colunas_descritivas
print(f"Formato dos dados: {dataframe.shape}")
print(dataframe.head())
6.2 Separação dos Dados e Treinamento de Modelos
# Dividir em características (X) e alvo (y)
caracteristicas = dataframe.iloc[:, :-1]
alvo = dataframe.iloc[:, -1]
# Separar conjuntos de treino e teste
X_treino, X_teste, y_treino, y_teste = train_test_split(
caracteristicas, alvo, test_size=0.2, random_state=42
)
# Definir modelos de regressão para comparação
modelos_reg = {
"Regressão Linear": LinearRegression(),
"Árvore de Decisão": DecisionTreeRegressor(random_state=42),
"Floresta Aleatória": RandomForestRegressor(n_estimators=100, random_state=42),
"Gradient Boosting": GradientBoostingRegressor(n_estimators=100, random_state=42)
}
resultados_metricas = []
previsoes_armazenadas = {}
print("Iniciando treinamento e avaliação...")
for nome_modelo, modelo in modelos_reg.items():
modelo.fit(X_treino, y_treino)
previsoes = modelo.predict(X_teste)
previsoes_armazenadas[nome_modelo] = previsoes
r2_valor = r2_score(y_teste, previsoes)
rmse_valor = np.sqrt(mean_squared_error(y_teste, previsoes))
mae_valor = mean_absolute_error(y_teste, previsoes)
resultados_metricas.append({
"Modelo": nome_modelo,
"R²": round(r2_valor, 4),
"RMSE": round(rmse_valor, 4),
"MAE": round(mae_valor, 4)
})
print(f"Modelo: {nome_modelo} | R²: {r2_valor:.4f} | RMSE: {rmse_valor:.4f}")
tabela_resultados = pd.DataFrame(resultados_metricas).sort_values(by="R²", ascending=False)
print(tabela_resultados)
6.3 Visualização de Resultados e Intervalos de Confiança
figura, eixos = plt.subplots(2, 2, figsize=(16, 14))
eixos_planos = eixos.flatten()
paleta_cores = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728"]
# Definir limites comuns para os eixos
valor_min = min(y_teste.min(), np.min(list(previsoes_armazenadas.values()))) - 5
valor_max = max(y_teste.max(), np.max(list(previsoes_armazenadas.values()))) + 5
for idx, (nome, modelo) in enumerate(modelos_reg.items()):
eixo = eixos_planos[idx]
preds = previsoes_armazenadas[nome]
# Gráfico de dispersão com intervalo de confiança de 95%
sns.regplot(
x=y_teste, y=preds, ax=eixo,
color=paleta_cores[idx],
ci=95,
scatter_kws={'s': 25, 'alpha': 0.6},
line_kws={'color': 'black', 'linewidth': 2}
)
# Linha de previsão perfeita
eixo.plot([valor_min, valor_max], [valor_min, valor_max],
'r--', linewidth=2, label='Previsão Ideal')
r2_final = r2_score(y_teste, preds)
rmse_final = np.sqrt(mean_squared_error(y_teste, preds))
texto_metricas = f'R² = {r2_final:.3f}\nRMSE = {rmse_final:.3f}'
eixo.text(0.05, 0.95, texto_metricas, transform=eixo.transAxes,
fontsize=12, verticalalignment='top',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
eixo.set_title(nome, fontsize=14)
eixo.set_xlabel('Resistência Real')
eixo.set_ylabel('Resistência Prevista')
eixo.set_xlim(valor_min, valor_max)
eixo.set_ylim(valor_min, valor_max)
eixo.legend()
eixo.grid(True, linestyle='--', alpha=0.7)
plt.suptitle('Comparação de Modelos: Efeito Ajustado e Intervalos de Confiança', fontsize=18)
plt.tight_layout()
plt.subplots_adjust(top=0.93)
plt.show()