Lab03 - Aprendizado Supervisionado - Regressão
Objetivos¶
- Apresentar o conceito de Regressão
- Apresentar e utilizar algoritmo de Regressão linear
- Apresentar e utilizar Regressão Polinomial
- Apresentar e discutir a matriz de correlação
- Apresentar uma intuição sobre métricas de avaliação (MSE, RMSE e $ R² $ )
Começando¶
Sabemos que dentro de aprendizado supervisionado vamos trabalhar com dois tipos de problemas:
- [x] Classificação - (Já conhecemos o KNN)
- [ ] Regressão - (Objetivo de hoje)
Uma intuição sobre problemas que envolvem cada um deles:¶
Classificação --> Resultados discretos (categóricos).
Regressão --> Resultados numéricos e contínuos.
Regressão linear¶
É uma técnica que consiste em representar um conjunto de dados por meio de uma reta.
Na matemática aprendemos que a equação de uma reta é:
$$
Y = A + BX \\
$$A e B são constantes que determinam a posição e inclinação da reta. Para cada valor de X temos um Y associado.
Em machine learning aprendemos que uma Regressão linear é:
$$
Y_{predito} = \beta_o + \beta_1X \\
$$$ \beta_o $ e $ \beta_1 $ são parâmetros que determinam o peso e bias da rede. Para cada entrada $ X $ temos um $ Y_{predito} $ aproximado predito.
Essa ideia se estende para mais de um parâmetro independente, mas nesse caso não estamos associando a uma reta e sim a um plano ou hiperplano:
$$ Y_{predito} = \beta_o + \beta_1X_1 + \beta_2X_2 + ... + \beta_nX_n\\ $$
Em outras palavras, modelos de regressão linear são intuitivos, fáceis de interpretar e se ajustam aos dados razoavelmente bem em muitos problemas.
Bora lá!!¶
Vamos juntos realizar um projeto, do começo ao fim, usando regressão.
Definição do problema¶
Vamos trabalhar com um dataset com informações coletadas U.S Census Service (tipo IBGE americano) sobre habitação na área de Boston Mass.
ref: https://www.cs.toronto.edu/~delve/data/boston/bostonDetail.html
informação importante sobre o significado de cada um dos atributos
Attribute Information:
- CRIM per capita crime rate by town
- ZN proportion of residential land zoned for lots over 25,000 sq.ft.
- INDUS proportion of non-retail business acres per town
- CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
- NOX nitric oxides concentration (parts per 10 million)
- RM average number of rooms per dwelling
- AGE proportion of owner-occupied units built prior to 1940
- DIS weighted distances to five Boston employment centres
- RAD index of accessibility to radial highways
- TAX full-value property-tax rate per $10,000
- PTRATIO pupil-teacher ratio by town
- B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
- LSTAT % lower status of the population
- MEDV Median value of owner-occupied homes in $1000's
Queremos desenvolver um modelo capaz de predizer o valor de um imovel em Boston.
Desafio 1¶
Do ponto de vista de machine learning, que problema é esse:
Aprendizado supervisionado, não-supervisionado ou aprendizado por reforço?
R:
Classificação, regressão ou clusterização?
R:
# Inicializção das bibliotecas
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
O scikit-learn possui diversos dataset em seu banco de dados, um deles é o dataset que vamos utilizar hoje.
faça o import direto usando sklearn.datasets
caso queira, você pode fazer o downlod do dataset direto do site e importar em seu projeto.
from sklearn.datasets import load_boston
boston_dataset = load_boston()
#para conhecer o que foi importado do dataset
boston_dataset.keys()
dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])
# vamos carregar no pandas apenas data com os dados e "feature_names" com os nomes dos atributos
df = pd.DataFrame(boston_dataset.data, columns=boston_dataset.feature_names)
df.head()
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 |
#vamos adicionar mais uma coluna ao nosso dataframe com o target (alvo que vamos fazer a predição)
df['MEDV'] = boston_dataset.target
df.head()
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
Desafio 2¶
Use os metodos info() e describe() para exibir as informações do dataframe e responda:
Existe dados faltantes?
Qual o tamanho do dataset, quantas linhas e quantas colunas?
# Mostra informações sobre o dataframe em si
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 506 entries, 0 to 505 Data columns (total 14 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 CRIM 506 non-null float64 1 ZN 506 non-null float64 2 INDUS 506 non-null float64 3 CHAS 506 non-null float64 4 NOX 506 non-null float64 5 RM 506 non-null float64 6 AGE 506 non-null float64 7 DIS 506 non-null float64 8 RAD 506 non-null float64 9 TAX 506 non-null float64 10 PTRATIO 506 non-null float64 11 B 506 non-null float64 12 LSTAT 506 non-null float64 13 MEDV 506 non-null float64 dtypes: float64(14) memory usage: 55.5 KB
df.describe()
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 |
mean | 3.613524 | 11.363636 | 11.136779 | 0.069170 | 0.554695 | 6.284634 | 68.574901 | 3.795043 | 9.549407 | 408.237154 | 18.455534 | 356.674032 | 12.653063 | 22.532806 |
std | 8.601545 | 23.322453 | 6.860353 | 0.253994 | 0.115878 | 0.702617 | 28.148861 | 2.105710 | 8.707259 | 168.537116 | 2.164946 | 91.294864 | 7.141062 | 9.197104 |
min | 0.006320 | 0.000000 | 0.460000 | 0.000000 | 0.385000 | 3.561000 | 2.900000 | 1.129600 | 1.000000 | 187.000000 | 12.600000 | 0.320000 | 1.730000 | 5.000000 |
25% | 0.082045 | 0.000000 | 5.190000 | 0.000000 | 0.449000 | 5.885500 | 45.025000 | 2.100175 | 4.000000 | 279.000000 | 17.400000 | 375.377500 | 6.950000 | 17.025000 |
50% | 0.256510 | 0.000000 | 9.690000 | 0.000000 | 0.538000 | 6.208500 | 77.500000 | 3.207450 | 5.000000 | 330.000000 | 19.050000 | 391.440000 | 11.360000 | 21.200000 |
75% | 3.677083 | 12.500000 | 18.100000 | 0.000000 | 0.624000 | 6.623500 | 94.075000 | 5.188425 | 24.000000 | 666.000000 | 20.200000 | 396.225000 | 16.955000 | 25.000000 |
max | 88.976200 | 100.000000 | 27.740000 | 1.000000 | 0.871000 | 8.780000 | 100.000000 | 12.126500 | 24.000000 | 711.000000 | 22.000000 | 396.900000 | 37.970000 | 50.000000 |
Desafio 3¶
Aplique os métodos que achar conveniente (vimos algumas opções na última aula) para visualizar os dados de forma gráfica.
## Sua resposta e seus gráficos para análisar..
#Vamos explorar um pouco uma matrix de correlação
import seaborn as sns
correlation_matrix = df.corr().round(2)
fig, ax = plt.subplots(figsize=(10,10))
sns.heatmap(data=correlation_matrix, annot=True, linewidths=.5, ax=ax)
<AxesSubplot:>
Desafio 4¶
Analisando a matriz de correlação acima responda:
Qual feature possue a maior correlação positiva com o target?
Qual feature possue a maior correlação negativa com o target?
df.plot.scatter('RM', 'MEDV')
<AxesSubplot:xlabel='RM', ylabel='MEDV'>
df.plot.scatter('LSTAT', 'MEDV')
<AxesSubplot:xlabel='LSTAT', ylabel='MEDV'>
PARE!!!¶
A análise feita no desafio 2 e 3 é uma das etapas mais importantes. Caso você tenha pulado essa etapa, volte e faça suas análises.
Com essa etapa concluída, vamos criar um sub-dataset com os atributos que serão utilizados.
# Vamos treinar nosso modelo com 2 dois atributos independentes
# para predizer o valor de saida
#X = df[['LSTAT', 'RM']]
X = df[['RM']]
Y = df['MEDV']
print(f"Formato das tabelas de dados {X.shape} e saidas {Y.shape}")
Formato das tabelas de dados (506, 1) e saidas (506,)
Dividindo os dados em conjunto de treinamento e de testes¶
Dividir nosso dataset em dois conjuntos de dados.
Treinamento - Representa 80% das amostras do conjunto de dados original,
Teste - com 20% das amostras
Vamos escolher aleatoriamente algumas amostras do conjunto original. Isto pode ser feito com Scikit-Learn usando a função train_test_split()
scikit-learn: pip3 install scikit-learn
# Separamos 20% para o teste
from sklearn.model_selection import train_test_split
X_treino, X_teste, Y_treino, Y_teste = train_test_split(X, Y, test_size=0.2)
print(X_treino.shape)
print(X_teste.shape)
print(Y_treino.shape)
print(Y_teste.shape)
(404, 1) (102, 1) (404,) (102,)
#Primeiras linhas do dataframe
X_treino.head()
RM | |
---|---|
460 | 6.701 |
59 | 5.927 |
146 | 5.628 |
304 | 7.236 |
101 | 6.781 |
Y_treino.head()
460 16.4 59 19.6 146 15.6 304 36.1 101 26.5 Name: MEDV, dtype: float64
Chegou a hora de aplicar o modelo preditivo¶
Treinar um modelo no python é simples se usar o Scikit-Learn. Treinar um modelo no Scikit-Learn é simples: basta criar o regressor, e chamar o método fit().
Uma observação sobre a sintaxe dos classificadores do scikit-learn
- O método
fit(X,Y)
recebe uma matriz ou dataframe X onde cada linha é uma amostra de aprendizado, e um array Y contendo as saídas esperadas do classificador, seja na forma de texto ou de inteiros - O método
predict(X)
recebe uma matriz ou dataframe X onde cada linha é uma amostra de teste, retornando um array de classes
# Importa a biblioteca
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# Cria o modelo de regressão
lin_model = LinearRegression()
# Cria o modelo de machine learning
lin_model.fit(X_treino, Y_treino)
LinearRegression()
Pronto!! bora testar se esta funcionando....
# Para obter as previsões, basta chamar o método predict()
y_teste_predito = lin_model.predict(X_teste)
print("Predição usando regressão, retorna valores continuos: {}".format(y_teste_predito))
Predição usando regressão, retorna valores continuos: [20.06354871 18.8064744 28.75454442 34.80477973 6.53417348 21.97176941 25.16419552 20.38912191 19.20439721 19.47570821 21.02218091 21.07644311 27.00006662 35.17557143 23.32832441 25.52594352 18.87882401 24.28695661 24.54922391 21.81802651 28.52845192 18.8426492 24.59444241 17.3323513 20.09972351 29.03489912 18.98734841 25.67064272 20.00928651 10.61288219 18.3181146 19.32196531 24.40452471 28.68219482 22.81283351 21.83611391 19.00543581 23.58154801 40.70127214 18.90595511 26.10474032 22.95753271 20.46147151 10.99271759 30.64467772 26.50266312 18.1462843 18.91499881 17.4951379 21.81802651 24.02468931 13.3440796 25.85151672 23.77146571 24.03373301 21.09453051 30.19249272 18.5713382 33.39396253 16.4279813 19.46666451 13.3892981 15.5869172 18.88786771 18.7431685 27.00006662 18.91499881 22.22499301 35.22078993 23.48206731 28.04009212 16.0300585 25.86960412 18.7702996 23.82572791 19.48475191 23.69911611 23.04796971 16.9434722 21.03122461 16.2832821 18.426639 31.15112493 29.93926912 22.65909061 40.35761154 17.7302741 27.39798942 27.10859102 25.05567112 14.628285 29.76743882 25.62542422 26.61118752 32.76994723 30.44571632 25.73394862 27.46129532 21.23018601 19.34909641 20.05450501 21.23018601]
# vamos avaliar os parametros do nosso modelo
print('(A) Intercepto: ', lin_model.intercept_)
print('(B) Inclinação: ', lin_model.coef_)
if len(lin_model.coef_)>1:
print('Nossa equação é: Y_pred = {} + {} * X_LSTAT + {} * X_RM'.format(lin_model.intercept_.round(2),lin_model.coef_[0].round(2),lin_model.coef_[1].round(2)) )
else:
print('Nossa equação é: Y_pred = {} + {} * X_LSTAT'.format(lin_model.intercept_.round(2),lin_model.coef_[0].round(2)))
(A) Intercepto: -34.33430688384365 (B) Inclinação: [9.04370002] Nossa equação é: Y_pred = -34.33 + 9.04 * X_LSTAT
plt.scatter(Y_teste,y_teste_predito)
plt.xlabel('Valor Real')
plt.ylabel('Valor Predito')
Text(0, 0.5, 'Valor Predito')
Avaliando o modelo treinado¶
Vamos colocar alguns valores e ver a predição do classificador.
from sklearn.metrics import r2_score, mean_squared_error,mean_absolute_error
import numpy as np
print("Soma dos Erros ao Quadrado (SSE): %2.f " % np.sum((y_teste_predito - Y_teste)**2))
print("Erro Quadrático Médio (MSE): %.2f" % mean_squared_error(Y_teste, y_teste_predito))
print("Erro Médio Absoluto (MAE): %.2f" % mean_absolute_error(Y_teste, y_teste_predito))
print ("Raiz do Erro Quadrático Médio (RMSE): %.2f " % np.sqrt(mean_squared_error(Y_teste, y_teste_predito)))
print("R2-score: %.2f" % r2_score(y_teste_predito , Y_teste) )
Soma dos Erros ao Quadrado (SSE): 5105 Erro Quadrático Médio (MSE): 50.05 Erro Médio Absoluto (MAE): 4.32 Raiz do Erro Quadrático Médio (RMSE): 7.07 R2-score: -0.46
Desafio 5¶
Refaça o notebook substituindo o algoritmo de regressão linear por outro algoritmo de regressão.
Sugestão::
Random forest
Decision Tree
## implemente sua sua solução....
Regressão Polinomial¶
$$ Y = A + BX + C X² \\ $$A, B e C são constantes que determinam a posição e inclinação da curva, o 2 indica o grau do polinômio. Para cada valor de X temos um Y associado.
Em machine learning aprendemos que uma Regressão Polinomial é:
$$
Y_{predito} = \beta_o + \beta_1X + \beta_2X² \\
$$$ \beta_o $ , $ \beta_1 $ e $ \beta_2 $ são parâmetros que determinam o peso da rede. Para cada entrada $ X $ temos um $ Y_{predito} $ aproximado predito.
Essa ideia se estende para polinômio de graus maiores:
$$ Y_{predito} = \beta_o + \beta_1X + \beta_2X² + ... + \beta_nX^n\\ $$import operator
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# importa feature polinomial
from sklearn.preprocessing import PolynomialFeatures
#gera numeros aleatorios, apenas para exemplo
np.random.seed(0)
x = 2 - 3 * np.random.normal(0, 1, 20)
y = x - 2 * (x ** 2) + 0.5 * (x ** 3) + np.random.normal(-3, 3, 20)
# ajuste nos dados, pois estamos trabalhando com a numpy
x = x[:, np.newaxis]
y = y[:, np.newaxis]
#----É aqui que o seu código muda
# Chama a função definindo o grau do polinomio e aplica o modelo
polynomial_features= PolynomialFeatures(degree=2)
x_poly = polynomial_features.fit_transform(x)
#----Pronto agora é tudo como era antes, com regressão linear
model = LinearRegression()
model.fit(x_poly, y)
y_poly_pred = model.predict(x_poly)
# Métrica de avaliação do modelo
print("Soma dos Erros ao Quadrado (SSE): %2.f " % np.sum((y_poly_pred - y)**2))
print("Erro Quadrático Médio (MSE): %.2f" % mean_squared_error(y,y_poly_pred))
print("Erro Médio Absoluto (MAE): %.2f" % mean_absolute_error(y, y_poly_pred))
print ("Raiz do Erro Quadrático Médio (RMSE): %.2f " % np.sqrt(mean_squared_error(y, y_poly_pred)))
print("R2-score: %.2f" % r2_score(y,y_poly_pred) )
plt.scatter(x, y, s=10)
# ordena os valores de x antes de plotar
sort_axis = operator.itemgetter(0)
sorted_zip = sorted(zip(x,y_poly_pred), key=sort_axis)
x, y_poly_pred = zip(*sorted_zip)
plt.plot(x, y_poly_pred, color='m')
plt.show()
Soma dos Erros ao Quadrado (SSE): 2048 Erro Quadrático Médio (MSE): 102.42 Erro Médio Absoluto (MAE): 8.34 Raiz do Erro Quadrático Médio (RMSE): 10.12 R2-score: 0.85
Desafio 6¶
Faça uma função que calcula a regressão polinomial (basicamente colocar o codigo acima em uma função), agora faça um código que chama essa função alterando o grau do polinomio de 2 até 10, basicamente um loop for que chama a função criada.
Análise os resultados obtidos e determine qual o melhor grau polinomio do seu modelo.
## Implemente sua solução