Análise exploratória do Dataset "House Prices - Advanced Regression Techniques"¶

1 Introdução¶

Neste projeto, procurarei realizar uma Análise Exploratória mais detalhada do dataset "House Prices - Advanced Regression Techniques", obtido no link "https://www.kaggle.com/c/house-prices-advanced-regression-techniques".

Este conjunto se constitui em 79 features, que é considerado um número razoavelmente alto, de onde podem se obter informações diversas.

Procuraremos realizar uma análise voltada a entender cada tipo de variável, bem como analisar graficamente cada uma.

Ao final, analisaremos ainda, algumas das principais características dos outliers.

2 Coleta de Dados¶

In [ ]:
# Importando as bibliotecas necessárias


#Para cálculos e dataframe
import pandas as pd
import numpy as np

#Para criação de gráficos
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
In [ ]:
# Algumas configurações iniciais

pd.set_option('display.max_columns',81)

3 Aquisição de dados¶

In [ ]:
# Carregando os dados de treino

train = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/Projetos/Advanced Houses/train.csv')

# Exibindo o dataset

train
Out[ ]:
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Condition1 Condition2 BldgType HouseStyle OverallQual OverallCond YearBuilt YearRemodAdd RoofStyle RoofMatl Exterior1st Exterior2nd MasVnrType MasVnrArea ExterQual ExterCond Foundation BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinSF1 BsmtFinType2 BsmtFinSF2 BsmtUnfSF TotalBsmtSF Heating HeatingQC CentralAir Electrical 1stFlrSF 2ndFlrSF LowQualFinSF GrLivArea BsmtFullBath BsmtHalfBath FullBath HalfBath BedroomAbvGr KitchenAbvGr KitchenQual TotRmsAbvGrd Functional Fireplaces FireplaceQu GarageType GarageYrBlt GarageFinish GarageCars GarageArea GarageQual GarageCond PavedDrive WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch ScreenPorch PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub Inside Gtl CollgCr Norm Norm 1Fam 2Story 7 5 2003 2003 Gable CompShg VinylSd VinylSd BrkFace 196.0 Gd TA PConc Gd TA No GLQ 706 Unf 0 150 856 GasA Ex Y SBrkr 856 854 0 1710 1 0 2 1 3 1 Gd 8 Typ 0 NaN Attchd 2003.0 RFn 2 548 TA TA Y 0 61 0 0 0 0 NaN NaN NaN 0 2 2008 WD Normal 208500
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub FR2 Gtl Veenker Feedr Norm 1Fam 1Story 6 8 1976 1976 Gable CompShg MetalSd MetalSd None 0.0 TA TA CBlock Gd TA Gd ALQ 978 Unf 0 284 1262 GasA Ex Y SBrkr 1262 0 0 1262 0 1 2 0 3 1 TA 6 Typ 1 TA Attchd 1976.0 RFn 2 460 TA TA Y 298 0 0 0 0 0 NaN NaN NaN 0 5 2007 WD Normal 181500
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub Inside Gtl CollgCr Norm Norm 1Fam 2Story 7 5 2001 2002 Gable CompShg VinylSd VinylSd BrkFace 162.0 Gd TA PConc Gd TA Mn GLQ 486 Unf 0 434 920 GasA Ex Y SBrkr 920 866 0 1786 1 0 2 1 3 1 Gd 6 Typ 1 TA Attchd 2001.0 RFn 2 608 TA TA Y 0 42 0 0 0 0 NaN NaN NaN 0 9 2008 WD Normal 223500
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub Corner Gtl Crawfor Norm Norm 1Fam 2Story 7 5 1915 1970 Gable CompShg Wd Sdng Wd Shng None 0.0 TA TA BrkTil TA Gd No ALQ 216 Unf 0 540 756 GasA Gd Y SBrkr 961 756 0 1717 1 0 1 0 3 1 Gd 7 Typ 1 Gd Detchd 1998.0 Unf 3 642 TA TA Y 0 35 272 0 0 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub FR2 Gtl NoRidge Norm Norm 1Fam 2Story 8 5 2000 2000 Gable CompShg VinylSd VinylSd BrkFace 350.0 Gd TA PConc Gd TA Av GLQ 655 Unf 0 490 1145 GasA Ex Y SBrkr 1145 1053 0 2198 1 0 2 1 4 1 Gd 9 Typ 1 TA Attchd 2000.0 RFn 3 836 TA TA Y 192 84 0 0 0 0 NaN NaN NaN 0 12 2008 WD Normal 250000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1455 1456 60 RL 62.0 7917 Pave NaN Reg Lvl AllPub Inside Gtl Gilbert Norm Norm 1Fam 2Story 6 5 1999 2000 Gable CompShg VinylSd VinylSd None 0.0 TA TA PConc Gd TA No Unf 0 Unf 0 953 953 GasA Ex Y SBrkr 953 694 0 1647 0 0 2 1 3 1 TA 7 Typ 1 TA Attchd 1999.0 RFn 2 460 TA TA Y 0 40 0 0 0 0 NaN NaN NaN 0 8 2007 WD Normal 175000
1456 1457 20 RL 85.0 13175 Pave NaN Reg Lvl AllPub Inside Gtl NWAmes Norm Norm 1Fam 1Story 6 6 1978 1988 Gable CompShg Plywood Plywood Stone 119.0 TA TA CBlock Gd TA No ALQ 790 Rec 163 589 1542 GasA TA Y SBrkr 2073 0 0 2073 1 0 2 0 3 1 TA 7 Min1 2 TA Attchd 1978.0 Unf 2 500 TA TA Y 349 0 0 0 0 0 NaN MnPrv NaN 0 2 2010 WD Normal 210000
1457 1458 70 RL 66.0 9042 Pave NaN Reg Lvl AllPub Inside Gtl Crawfor Norm Norm 1Fam 2Story 7 9 1941 2006 Gable CompShg CemntBd CmentBd None 0.0 Ex Gd Stone TA Gd No GLQ 275 Unf 0 877 1152 GasA Ex Y SBrkr 1188 1152 0 2340 0 0 2 0 4 1 Gd 9 Typ 2 Gd Attchd 1941.0 RFn 1 252 TA TA Y 0 60 0 0 0 0 NaN GdPrv Shed 2500 5 2010 WD Normal 266500
1458 1459 20 RL 68.0 9717 Pave NaN Reg Lvl AllPub Inside Gtl NAmes Norm Norm 1Fam 1Story 5 6 1950 1996 Hip CompShg MetalSd MetalSd None 0.0 TA TA CBlock TA TA Mn GLQ 49 Rec 1029 0 1078 GasA Gd Y FuseA 1078 0 0 1078 1 0 1 0 2 1 Gd 5 Typ 0 NaN Attchd 1950.0 Unf 1 240 TA TA Y 366 0 112 0 0 0 NaN NaN NaN 0 4 2010 WD Normal 142125
1459 1460 20 RL 75.0 9937 Pave NaN Reg Lvl AllPub Inside Gtl Edwards Norm Norm 1Fam 1Story 5 6 1965 1965 Gable CompShg HdBoard HdBoard None 0.0 Gd TA CBlock TA TA No BLQ 830 LwQ 290 136 1256 GasA Gd Y SBrkr 1256 0 0 1256 1 0 1 1 3 1 TA 6 Typ 0 NaN Attchd 1965.0 Fin 1 276 TA TA Y 736 68 0 0 0 0 NaN NaN NaN 0 6 2008 WD Normal 147500

1460 rows × 81 columns

Nosso conjunto de dados apresenta 1460 linhas e 81 colunas, que é um número bastante alto de features.

4 Análise Exploratória dos Dados¶

Nesta etapa, vamos procurar entender cada tipo de dado contido no dataset, e estudar de que maneira está distribuída, bem como as relações entre as features e a variável target ('SalePrice').

4.1 Separação entre duas variáveis: categóricas e numéricas¶

Primeiramente precisamos entender que tipo de dados temos em cada coluna. Como vimos, o dataset contém 81 colunas. Vejamos quais os tipos de cada uma:

In [ ]:
pd.DataFrame(train.dtypes, columns = ['Type']).T
Out[ ]:
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Condition1 Condition2 BldgType HouseStyle OverallQual OverallCond YearBuilt YearRemodAdd RoofStyle RoofMatl Exterior1st Exterior2nd MasVnrType MasVnrArea ExterQual ExterCond Foundation BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinSF1 BsmtFinType2 BsmtFinSF2 BsmtUnfSF TotalBsmtSF Heating HeatingQC CentralAir Electrical 1stFlrSF 2ndFlrSF LowQualFinSF GrLivArea BsmtFullBath BsmtHalfBath FullBath HalfBath BedroomAbvGr KitchenAbvGr KitchenQual TotRmsAbvGrd Functional Fireplaces FireplaceQu GarageType GarageYrBlt GarageFinish GarageCars GarageArea GarageQual GarageCond PavedDrive WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch ScreenPorch PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
Type int64 int64 object float64 int64 object object object object object object object object object object object object int64 int64 int64 int64 object object object object object float64 object object object object object object object int64 object int64 int64 int64 object object object object int64 int64 int64 int64 int64 int64 int64 int64 int64 int64 object int64 object int64 object object float64 object int64 int64 object object object int64 int64 int64 int64 int64 int64 object object object int64 int64 int64 object object int64

As colunas são dos tipos 'object', 'int64' ou 'float64'.
Para facilitar as análises, vamos separar as colunas, primeiramente, em dois tipos:

  • variáveis categóricas: 'object'
  • variáveis numéricas: 'float64' e 'int64'.

Mais a frente, analisaremos se as variáveis do tipo 'int64' podem ser, na verdade, categóricas.

In [ ]:
var_cat =[]
var_num =[]

for col in train.drop(columns=['Id','SalePrice']).columns:
  if train[col].dtypes == object:
    var_cat.append(col)
  else:
    var_num.append(col)
print(f"Há {len(var_cat)} variáveis categóricas ('object'): \n {var_cat}\n")
print(f"Há {len(var_num)} varáveis numéricas ('int64 e float 64'): \n {var_num}")
Há 43 variáveis categóricas ('object'): 
 ['MSZoning', 'Street', 'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2', 'Heating', 'HeatingQC', 'CentralAir', 'Electrical', 'KitchenQual', 'Functional', 'FireplaceQu', 'GarageType', 'GarageFinish', 'GarageQual', 'GarageCond', 'PavedDrive', 'PoolQC', 'Fence', 'MiscFeature', 'SaleType', 'SaleCondition']

Há 36 varáveis numéricas ('int64 e float 64'): 
 ['MSSubClass', 'LotFrontage', 'LotArea', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd', 'Fireplaces', 'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF', 'OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal', 'MoSold', 'YrSold']

4.2 Descrição dos dados¶

Vamos agora verificar que tipo de informações podemos obter sobre cada tipo de dado contidas nas colunas.

Primeiramente para as variáveis categóricas:

4.2.1 Variáveis categóricas¶

In [ ]:
train[var_cat].describe()
Out[ ]:
MSZoning Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Condition1 Condition2 BldgType HouseStyle RoofStyle RoofMatl Exterior1st Exterior2nd MasVnrType ExterQual ExterCond Foundation BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinType2 Heating HeatingQC CentralAir Electrical KitchenQual Functional FireplaceQu GarageType GarageFinish GarageQual GarageCond PavedDrive PoolQC Fence MiscFeature SaleType SaleCondition
count 1460 1460 91 1460 1460 1460 1460 1460 1460 1460 1460 1460 1460 1460 1460 1460 1460 1452 1460 1460 1460 1423 1423 1422 1423 1422 1460 1460 1460 1459 1460 1460 770 1379 1379 1379 1379 1460 7 281 54 1460 1460
unique 5 2 2 4 4 2 5 3 25 9 8 5 8 6 8 15 16 4 4 5 6 4 4 4 6 6 6 5 2 5 4 7 5 6 3 5 5 3 3 4 4 9 6
top RL Pave Grvl Reg Lvl AllPub Inside Gtl NAmes Norm Norm 1Fam 1Story Gable CompShg VinylSd VinylSd None TA TA PConc TA TA No Unf Unf GasA Ex Y SBrkr TA Typ Gd Attchd Unf TA TA Y Gd MnPrv Shed WD Normal
freq 1151 1454 50 925 1311 1459 1052 1382 225 1260 1445 1220 726 1141 1434 515 504 864 906 1282 647 649 1311 953 430 1256 1428 741 1365 1334 735 1360 380 870 605 1311 1326 1340 3 157 49 1267 1198

Podemos verificar que há algumas variáveis variáveis que apresentam apenas dois tipos de valores. São elas:

Street: Tipo de acesso rodoviário
Alley: Tipo de acesso ao beco
Utilities: Tipo de utilitários disponíveis
CentralAir: Ar condicionado central

No entanto, quando consultamos a descrição do problema, verificamos que as colunas 'Alley' e 'Utilities' apresentam 3 e 4 valores possíveis, respectivamente. Vamos armazená-las em uma nova lista::

In [ ]:
var_bin = ['Street','Alley','Utilities','CentralAir']

Outras colunas apresentam valores únicos variando de 3 a 25:

\ MSZoning: Identifica a classificação geral do zoneamento da venda
LotShape: Forma geral da propriedade
LandContour: Planicidade da propriedade
LotConfig: Configuração do lote
LandSlope: Declive da propriedade
Neighborhood: Locais físicos dentro dos limites da cidade
Condition1: Proximidade de várias condições
Condition2: Proximidade de várias condições (se mais de uma estiver presente)
BldgType: Tipo de habitação
HouseStyle: Estilo de habitação
RoofStyle: Tipo de telhado
RoofMatl: Material do telhado
Exterior1st: Revestimento exterior da casa
Exterior2nd: Revestimento externo da casa (se houver mais de um material)
MasVnrType: Tipo folheado de alvenaria
ExterQual: Avalia a qualidade do material no exterior
ExterCond: Avalia a condição atual do material no exterior
Foundation: Tipo de fundação
BsmtQual: Avalia a altura do porão
BsmtCond: Avalia o estado geral da cave
BsmtExposure: Refere-se a paralisações ou paredes no nível do jardim
BsmtFinType1: Classificação da área finalizada do porão
BsmtFinType2: Classificação da área finalizada do porão (se vários tipos)
Heating: Tipo de aquecimento
HeatingQC: Qualidade e condição do aquecimento
Electrical: Sistema elétrico
KitchenQual: Qualidade da cozinha
Functional: Funcionalidade doméstica
FireplaceQu: Qualidade de lareira
GarageType: Localização da garagem
GarageFinish: Acabamento interior da garagem
GarageQual: Qualidade de garagem
GarageCond: Condição de garagem
PavedDrive: Estrada pavimentada
PoolQC: Qualidade da piscina
Fence: Qualidade da cerca
MiscFeature: Diversos recursos não cobertos em outras categorias
SaleType: Tipo de venda
SaleCondition: Condição de venda

Algumas das variáveis categóricas acima, claramente apresentam uma relação ordinal ou de ranking entre seus valores. São elas:

Coluna Valores
ExterQual Ex/Gd/TA/Fa/Po/
ExterCond Ex/Gd/TA/Fa/Po/
BsmtQual Ex/Gd/TA/Fa/Po/
BsmtCond Ex/Gd/TA/Fa/Po/NA
BsmtExposure Gd/TA/Mn/No/NA
BsmtFinType1 GLQ/ALQ/BLQ/Rec/LwQ/Unf/NA
BsmtFinType2 GLQ/ALQ/BLQ/Rec/LwQ/Unf/NA
BsmtCond Ex/Gd/Av/Fa/Po/NA
HeatingQC Ex/Gd/Av/Fa/Po/
KitchenQual Ex/Gd/Av/Fa/Po/
FireplaceQu Ex/Gd/Av/Fa/Po/NA
GarageQual Ex/Gd/Av/Fa/Po/NA
GarageCond Ex/Gd/Av/Fa/Po/NA
PoolQC Ex/Gd/TA/Fa/No

Legendas:

   Ex   Excellent (Excelente)
   Gd   Good (Bom)
   TA   Typical (Típico)
   Fa   Fair (Justo)
   Po   Poor (Pobre)
   Av   Average (Médio)
   NA/No    Nonexistent (Não existe)
   Mn   Minimum (Mínimo)
   GLQ  Good Living Quarters (Bons Alojamentos)
   ALQ  Average Living Quarters (Alojamentos razoáveis)
   BLQ  Below Average Living Quarters   (Alojamentos abaixo da média)
   Rec  Average Rec Room (Quarto médio)
   LwQ  Low Quality (Baixa Qualidade)
   Unf  Unfinshed (Inacabado)

Vamos guardar tais variáveis em uma lista:

In [ ]:
var_rank = ['ExterQual','ExterCond','BsmtQual','BsmtCond','BsmtExposure','BsmtFinType1','BsmtFinType2','HeatingQC','KitchenQual','FireplaceQu','GarageQual','GarageCond','PoolQC']

4.2.2 Variáveis numéricas¶

Analisaremos agora as variáveis numéricas:

Descrição das variáveis numéricas:

MSSubClass: Identifica o tipo de habitação envolvido na venda
LotFrontage: pés lineares de rua conectados à propriedade
LotArea: Tamanho do lote em pés quadrados
OverallQual: Classifica o material geral e o acabamento da casa
OverallCond: Classifica a condição geral da casa
YearBuilt: data de construção original
YearRemodAdd: Data de remodelação (igual à data de construção se não houver remodelação ou acréscimos)
MasVnrArea: Área de folheado de alvenaria em pés quadrados
BsmtFinSF1: Tipo 1 pés quadrados acabados
BsmtFinSF2: Tipo 2 pés quadrados acabados
BsmtUnfSF: pés quadrados inacabados da área do porão
TotalBsmtSF: pés quadrados totais da área do porão
1stFlrSF: pés quadrados do primeiro andar
2ndFlrSF: pés quadrados do segundo andar
LowQualFinSF: pés quadrados acabados de baixa qualidade (todos os andares)
GrLivArea: Área habitável acima do solo (pés quadrados)
BsmtFullBath: Banheiros completos no porão
BsmtHalfBath: lavabos no porão
FullBath: Banheiros completos acima do nível do solo
HalfBath: Meios banhos acima do grau
BedroomAbvGr: Número de quartos acima do subsolo
KitchenAbvGr: Cozinhas acima do nível
TotRmsAbvGrd: Total de quartos acima do nível (não inclui banheiros)
Lareiras: Número de lareiras
GarageYrBlt: ano em que a garagem foi construída
GarageCars: Tamanho da garagem na capacidade do carro
GarageArea: Tamanho da garagem em pés quadrados
WoodDeckSF: Área de deck de madeira em pés quadrados
OpenPorchSF: Área de varanda aberta em pés quadrados
EnclosedPorch: Área da varanda fechada em pés quadrados
3SsnPorch: Área de varanda de três estações em pés quadrados
ScreenPorch: Área da varanda de tela em pés quadrados
PoolArea: Área da piscina em metros quadrados
MiscVal: $Valor do recurso diverso
MoSold: Mês Vendido (MM)
YrSold: Ano de venda (AAAA)

In [ ]:
train[var_num].describe()
Out[ ]:
MSSubClass LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF 2ndFlrSF LowQualFinSF GrLivArea BsmtFullBath BsmtHalfBath FullBath HalfBath BedroomAbvGr KitchenAbvGr TotRmsAbvGrd Fireplaces GarageYrBlt GarageCars GarageArea WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch ScreenPorch PoolArea MiscVal MoSold YrSold
count 1460.000000 1201.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1452.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1379.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000
mean 56.897260 70.049958 10516.828082 6.099315 5.575342 1971.267808 1984.865753 103.685262 443.639726 46.549315 567.240411 1057.429452 1162.626712 346.992466 5.844521 1515.463699 0.425342 0.057534 1.565068 0.382877 2.866438 1.046575 6.517808 0.613014 1978.506164 1.767123 472.980137 94.244521 46.660274 21.954110 3.409589 15.060959 2.758904 43.489041 6.321918 2007.815753
std 42.300571 24.284752 9981.264932 1.382997 1.112799 30.202904 20.645407 181.066207 456.098091 161.319273 441.866955 438.705324 386.587738 436.528436 48.623081 525.480383 0.518911 0.238753 0.550916 0.502885 0.815778 0.220338 1.625393 0.644666 24.689725 0.747315 213.804841 125.338794 66.256028 61.119149 29.317331 55.757415 40.177307 496.123024 2.703626 1.328095
min 20.000000 21.000000 1300.000000 1.000000 1.000000 1872.000000 1950.000000 0.000000 0.000000 0.000000 0.000000 0.000000 334.000000 0.000000 0.000000 334.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 2.000000 0.000000 1900.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 2006.000000
25% 20.000000 59.000000 7553.500000 5.000000 5.000000 1954.000000 1967.000000 0.000000 0.000000 0.000000 223.000000 795.750000 882.000000 0.000000 0.000000 1129.500000 0.000000 0.000000 1.000000 0.000000 2.000000 1.000000 5.000000 0.000000 1961.000000 1.000000 334.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 5.000000 2007.000000
50% 50.000000 69.000000 9478.500000 6.000000 5.000000 1973.000000 1994.000000 0.000000 383.500000 0.000000 477.500000 991.500000 1087.000000 0.000000 0.000000 1464.000000 0.000000 0.000000 2.000000 0.000000 3.000000 1.000000 6.000000 1.000000 1980.000000 2.000000 480.000000 0.000000 25.000000 0.000000 0.000000 0.000000 0.000000 0.000000 6.000000 2008.000000
75% 70.000000 80.000000 11601.500000 7.000000 6.000000 2000.000000 2004.000000 166.000000 712.250000 0.000000 808.000000 1298.250000 1391.250000 728.000000 0.000000 1776.750000 1.000000 0.000000 2.000000 1.000000 3.000000 1.000000 7.000000 1.000000 2002.000000 2.000000 576.000000 168.000000 68.000000 0.000000 0.000000 0.000000 0.000000 0.000000 8.000000 2009.000000
max 190.000000 313.000000 215245.000000 10.000000 9.000000 2010.000000 2010.000000 1600.000000 5644.000000 1474.000000 2336.000000 6110.000000 4692.000000 2065.000000 572.000000 5642.000000 3.000000 2.000000 3.000000 2.000000 8.000000 3.000000 14.000000 3.000000 2010.000000 4.000000 1418.000000 857.000000 547.000000 552.000000 508.000000 480.000000 738.000000 15500.000000 12.000000 2010.000000

Podemos observar que algumas colunas, como 'PoolArea', 'MiscVal', '3SsnPorch', 'LowQualFinSF' possuem um desvio padrão muito maior que o valor médio da coluna. Isso também implica em uma alta variância, que pode ser resultado, dentre outros fatores, da quantidade de valores ausentes na coluna.

De acordo com as descrições das variáveis numéricas, vemos que as colunas 'OverallQual' e 'OverallCond' também possuem caráter de ranking, pois atribuem uma nota à qualidade geral do material e à condição geral da casa, respectivamente, possuindo os seguintes valores:

   10   Very Excellent (Muito excelente)  
   9    Excellent (Excelente)  
   8    Very Good (Muito bom)  
   7    Good (Bom)  
   6    Above Average (Acima da média)  
   5    Average (Médio)  
   4    Below Average (Abaixo da média)  
   3    Fair (Justo)  
   2    Poor (Pobre)  
   1    Very Poor (Muito pobre)

Assim, vamos colocar essas duas variáveis também na lista 'var_rank':

In [ ]:
var_rank.append('OverallQual')
var_rank.append('OverallCond')

Uma vez que, algumas variáveis categóricas e numéricas foram redefinidas como binárias ou de ranking, vamos redefinir também as listas de variáveis categóricas e numéricas:

In [ ]:
for var in (var_rank+var_bin):
  if var in var_cat:
    var_cat.remove(var)

for var in var_rank:
  if var in var_num:
    var_num.remove(var)

4.3 Valores ausentes¶

Verificaremos agora a quantidade de valores nulos presentes em cada coluna:

In [ ]:
miss_value=pd.DataFrame(columns=['Coluna', '%Ausente'])

for index,col in enumerate(train.columns):
  
  value = (train[col].isna().sum()/train.shape[0])*100

  if value>0:

    nova_linha=pd.DataFrame([[col,value]], columns=['Coluna', '%Ausente'], index=[index])

    miss_value = pd.concat([miss_value,nova_linha])

miss_value.sort_values(by='%Ausente', ascending=False).T
Out[ ]:
72 74 6 73 57 3 58 59 60 63 64 32 35 33 31 30 26 25 42
Coluna PoolQC MiscFeature Alley Fence FireplaceQu LotFrontage GarageType GarageYrBlt GarageFinish GarageQual GarageCond BsmtExposure BsmtFinType2 BsmtFinType1 BsmtCond BsmtQual MasVnrArea MasVnrType Electrical
%Ausente 99.520548 96.30137 93.767123 80.753425 47.260274 17.739726 5.547945 5.547945 5.547945 5.547945 5.547945 2.60274 2.60274 2.534247 2.534247 2.534247 0.547945 0.547945 0.068493

Vericamos que as colunas PoolQC, MiscFeature, Alley, Fence e FireplaceQu possuem alta porcentagem de valores ausentes, que nos impede de tirar conclusões mais precisas.

4.4 Visualização dos dados¶

Vamos agora visualizar a distribuição de algumas colunas, de forma a obter alguns insights.

4.4.1 Distribuição da variável target¶

In [ ]:
fig, ax = plt.subplots(1,2,figsize=(15,5))
sns.histplot(train['SalePrice'],kde=True, ax=ax[0])
sns.boxplot(x=train['SalePrice'],ax=ax[1])
plt.show()

Podemos observar que a variável target (SalePrice) não segue uma distribuição normal, tendo maior assimetria para a direita. Segundo o que podemos ver no boxplot, o valor médio das casas do dataset se encontram por volta de 17 mil, mas há muitos outliers cujos valores podem chegar a mais de 70 mil.

4.4.2 Distribuição das variáveis binárias¶

Vamos analisar de que forma as variáveis binárias se relacionam com os preços das casas:

In [ ]:
plt.figure(figsize=(25,5))
for i,col in enumerate(train[var_bin],1):
  plt.subplot(1,4,i)
  sns.boxplot(data=train, x= col, y='SalePrice').set_title(f"Gráfico {i}")

A partir do Gráfico 1, é possível observar que as casas situadas em ruas não pavimentadas (Grvl) possuem valor médio e valor máximo inferior às casas em ruas pavimentadas.

No Gráfico 2, embora a variável 'Alley' não seja binária, pois apresenta 3 possibilidades (Grvl, Pave e NO), no dataset há apenas as os dois primeiros tipos de valores, onde podemos novamente constatar que o tipo de acesso à rua 'pavimentada' (Pave) tem valor médio e valor máximo maiores do que quando a rua não é pavimentada.

No Gráfico 3, novamente vemos que a variável 'Utilities' pode apresentar 4 tipos de valores, mas apresenta apensa 2.

Finalmente no Gráfico 4, relativo à presença ou não de central de ar condicionado, fica evidente que as casas que apresental ar condicionado possuem valor maior do que as casas que não apresentam.

4.4.3 Distribuição das variáveis ordinais ou de ranking¶

Como já abordado anteriormente, as variáveis ordinais são aquelas que podem apresentar comportamento no qual há uma relação entre os valores. No caso estudado aqui, as variáveis 'ExterQual', 'ExterCond', 'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2', 'HeatingQC', 'KitchenQual', 'FireplaceQu', 'GarageQual', 'GarageCond', 'PoolQC', 'OverallQual', 'OverallCond' apresentam um comportamento de ranking, onde os valores são como notas atribuídas ao quesito descrito na coluna.

Dessa forma, vamos analisar o comportamento da variável target em relação a cada uma delas. Para isso, primeiramente vamos substituir os valores categóricos contidos em cada coluna, por valores numéricos, onde 0 é a menor nota na escala.

In [ ]:
df = train.copy()

df[['ExterQual','ExterCond','HeatingQC','KitchenQual','PoolQC']] = df[['ExterQual','ExterCond','HeatingQC','KitchenQual','PoolQC']].replace(to_replace=['Ex','Gd','TA','Fa','Po'], value=[4,3,2,1,0])
df[['BsmtQual','BsmtCond','FireplaceQu','GarageQual','GarageCond']] = df[['BsmtQual','BsmtCond','FireplaceQu','GarageQual','GarageCond']].replace(to_replace=['Ex','Gd','TA','Fa','Po','NA'], value=[5,4,3,2,1,0])
df[['BsmtExposure']] = df[['BsmtExposure']].replace(to_replace=['Gd','Av','Mn','No','NA'], value=[4,3,2,1,0])
df[['BsmtFinType1','BsmtFinType2']] = df[['BsmtFinType1','BsmtFinType2']].replace(to_replace=['GLQ','ALQ','BLQ','Rec','LwQ','Unf','NA'], value=[6,5,4,3,2,1,0])

df[var_rank]
Out[ ]:
ExterQual ExterCond BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinType2 HeatingQC KitchenQual FireplaceQu GarageQual GarageCond PoolQC OverallQual OverallCond
0 3 2 4.0 3.0 1.0 6.0 1.0 4 3 NaN 3.0 3.0 NaN 7 5
1 2 2 4.0 3.0 4.0 5.0 1.0 4 2 3.0 3.0 3.0 NaN 6 8
2 3 2 4.0 3.0 2.0 6.0 1.0 4 3 3.0 3.0 3.0 NaN 7 5
3 2 2 3.0 4.0 1.0 5.0 1.0 3 3 4.0 3.0 3.0 NaN 7 5
4 3 2 4.0 3.0 3.0 6.0 1.0 4 3 3.0 3.0 3.0 NaN 8 5
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1455 2 2 4.0 3.0 1.0 1.0 1.0 4 2 3.0 3.0 3.0 NaN 6 5
1456 2 2 4.0 3.0 1.0 5.0 3.0 2 2 3.0 3.0 3.0 NaN 6 6
1457 4 3 3.0 4.0 1.0 6.0 1.0 4 3 4.0 3.0 3.0 NaN 7 9
1458 2 2 3.0 3.0 2.0 6.0 3.0 3 3 NaN 3.0 3.0 NaN 5 6
1459 3 2 3.0 3.0 1.0 4.0 2.0 3 2 NaN 3.0 3.0 NaN 5 6

1460 rows × 15 columns

In [ ]:
plt.figure(figsize=(20,30))
for i,col in enumerate(df[var_rank],1):
  plt.subplot(5,3,i)
  sns.boxplot(data=df, x= col, y='SalePrice').set_title(f'Gráfico {i+4}')

Neste formato, torna-se muito mais simples analisar de que forma cada variável ordinal se relaciona com o valor das casas. De maneira geral, podemos ver que fica evidente a relação ascendente entre os valores de cada variável e a variável SalePrice, ou seja, quanto maior a nota em cada quisito, maior o valor médio da casa.

4.4.4 Distribuição das variáveis categóricas¶

Agora analisaremos as variáveis categóricas:

In [ ]:
plt.figure(figsize=(25,45))
for i,col in enumerate(train[var_cat],1):
  plt.subplot(7,4,i)
  sns.boxplot(data=train, x= col,y='SalePrice').set_title(f'Gráfico {i+19}')

Como alguns dos gráficos acima (25, 32 e 36) não apresentaram boa qualidade de visualização, vamos plotá-los separadamente abaixo:

In [ ]:
plt.figure(figsize=(20,20))

plt.subplot(3,1,1)
sns.boxplot(data=train, x='Neighborhood', y='SalePrice').set_title(f'Gráfico 25')

plt.subplot(3,1,2)
sns.boxplot(data=train, x='Exterior1st', y='SalePrice').set_title(f'Gráfico 32')

plt.subplot(3,1,3)
sns.boxplot(data=train, x='Exterior2nd', y='SalePrice').set_title(f'Gráfico 36')

plt.show()

4.4.5 Distribuição das Variáveis numéricas¶

In [ ]:
plt.figure(figsize=(30,50))
for i, col in enumerate(train[var_num].columns,1):
  plt.subplot(9,4,i)
  sns.histplot(train[col],kde=True).set_title(f'Gráfico {i+45}')

4.4 Variância¶

Um fator importante a ser observado antes dos processos de modelagem, pode ser a variância de cada feature. Como a quantidade de atributos é bastante alta, procuraremos analisá-las a fim de encontrar variáveis constantes ou quasi-constantes, isto é, variáveis que apresentam variância nula ou muito baixa, e que terão pouca influência sobre a modelagem.

É importante que seja feita a normalização dos dados para que seja realizada uma comparação justa, pois a variância depende também da escala em que os valores se encontram. Para isso, optaremos pordividir cada coluna pela sua média, para garantir que todas estejam na mesma escala:

In [ ]:
mean = df[var_num].mean()
df[var_num] = df[var_num]/mean
In [ ]:
variance = pd.DataFrame(df[var_num].var().sort_values(), columns=['Variance'])

fig, ax = plt.subplots(figsize=(13,10))
ax = sns.barplot(y=variance.index,x=variance['Variance'])
ax.set_title(f'Gráfico 91: Variância das colunas numéricas')

for index, value in enumerate (variance['Variance']):
  plt.text(value, index, f'{value:.3}')

plt.show()

Podemos verificar que as variâncias vão da ordem de 10^-7 até 10^2, e há muitas features com baixa variância, que teriam sua remoção estudada em casos de modelagem.

In [ ]:
train[['PoolArea','MiscVal','3SsnPorch','LowQualFinSF','BsmtHalfBath','ScreenPorch','BsmtFinSF2','EnclosedPorch','MasVnrArea','OpenPorchSF','WoodDeckSF','HalfBath','2ndFlrSF','BsmtFullBath','Fireplaces']].describe()
Out[ ]:
PoolArea MiscVal 3SsnPorch LowQualFinSF BsmtHalfBath ScreenPorch BsmtFinSF2 EnclosedPorch MasVnrArea OpenPorchSF WoodDeckSF HalfBath 2ndFlrSF BsmtFullBath Fireplaces
count 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1452.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000 1460.000000
mean 2.758904 43.489041 3.409589 5.844521 0.057534 15.060959 46.549315 21.954110 103.685262 46.660274 94.244521 0.382877 346.992466 0.425342 0.613014
std 40.177307 496.123024 29.317331 48.623081 0.238753 55.757415 161.319273 61.119149 181.066207 66.256028 125.338794 0.502885 436.528436 0.518911 0.644666
min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
25% 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
50% 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 25.000000 0.000000 0.000000 0.000000 0.000000 1.000000
75% 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 166.000000 68.000000 168.000000 1.000000 728.000000 1.000000 1.000000
max 738.000000 15500.000000 508.000000 572.000000 2.000000 480.000000 1474.000000 552.000000 1600.000000 547.000000 857.000000 2.000000 2065.000000 3.000000 3.000000

4.5 Correlação¶

Nesta etapa, procuraremos visualizar as possíveis correlações entre as variáveis numéricas e ordinais com a vaariável target, e também entre elas mesmas.
Para isso, utilizaremos os métodos relacionados à correlação linear de Pearson.

In [ ]:
plt.figure(figsize=(10,15))

corr = pd.DataFrame(train[['SalePrice']+var_num+var_rank].corr()['SalePrice'].abs().sort_values(ascending = False)).drop(index=['SalePrice'])
corr.columns = ['Correlation']

bar = sns.barplot(y = corr.index, x=corr['Correlation']).set_title("Gráfico 80: Correlação de Pearson das variáveis numéricas e ordinais com a variável 'SalePrice' (em valores absolutos)")

for index, value in enumerate (corr['Correlation']):
  plt.text(value, index, f'{value:.2}')

plt.show()

Observamos que as colunas 'OverallQual', 'GrLivArea', 'GarageCars','GarageArea', 'TotalBsmtSF', 'FullBath', 'TotRmsAbvGrd', 'YearBuilt' apresentam alta correlação linear com a variável 'SalePrice'.

Tais colunas se referem-se às condições, tamanho, quantidade de cômodos e ano de construção dos imóveis, fatores já esperados como influência sobre os preços.

In [ ]:
plt.figure(figsize=(20,20))
ax = sns.heatmap(train[['SalePrice']+var_num+var_rank].corr().abs(), annot = True, fmt=".1f")
ax.set_title('Gráfico 81: Correlação de Pearson')
plt.show()

Podemos ainda destacar outras relações entre as variáveis:

  • 'TotalBsmtSF' x '1stFlrSF': Área do porão e Área do 1º andar.

Essa relação é esperada e quase redundante, uma vez que a área do 1º andar corresponde, na maioria das vezes, à área do porão.

  • 'YearBuilt'x'GarageYrBlt': Ano de construção do imóvel e ano de construção da garagem.

Aqui a correlação é quase que óbvia, uma vez que na maioria das vezes a garagem do imóvel é construída simultaneamente ao imóvel.

  • 'GarageCars' x 'GarageArea': Quantidade de vagas de carro na garagem e Área da garagem.

Mais uma correlação esperada: quanto maior a área da garagem, maior a quantidade de vagas disponíveis.

  • 'GrLivArea' x 'YearBuilt': Área habitável (acima do solo) e ano de construção.

Essa relação mostrou que, com o passar dos anos, as áreas dos terrenos também aumentaram.

Abaixo, vejamos de que forma a variável independente 'SalePrice' se distribui em função das 9 variáveis dependentes com maior correlação de Pearson.

In [ ]:
plt.figure(figsize=(20,17))
for i, col in enumerate(corr.head(9).index,1):
  plt.subplot(3,3,i)
  sns.regplot(data=train, x=col, y='SalePrice').set_title(f'Gráfico {i+81}')

5 Analisando os outliers¶

Nesta etapa, vamos analisar os outliers, ou seja, as linhas do dataset, no qual o valor do preço foge da normalidade, ou seja, são discrepantes. Existem vários métodos para calcular qual valor de preço define o que é ou não um outlier. Em nosso trabalho, vamos utilizar o método estatístico de calcular todos os quartis, em seguida o Intervalo Interquartil e finalmente o limite máximo, a partir do qual, um valor é considerado outlier.

Vamos iniciar pelo cálculo do segundo quartil (denominado de Q2), que é a mediana. A partir daí, calculamos o primeiro quartil (Q1) é a mediana entre o menor valor e Q2 (mediana do conjunto), Q3, que é a mediana entre o maior valor e Q2.

In [ ]:
Q2 = np.median(train['SalePrice'])
Q1 = np.median(train[train['SalePrice']<=Q2]['SalePrice'])
Q3 = np.median(train[train['SalePrice']>=Q2]['SalePrice'])
print(f'Q1 = {Q1} \nQ2 = {Q2} \nQ3 = {Q3}')
Q1 = 130000.0 
Q2 = 163000.0 
Q3 = 214000.0

Calculamos agora o IQR (Interquartil Range) ou Intervalo Interquartil, que é a diferença entre Q3 e Q1:

In [ ]:
IQR = Q3 - Q1
IQR
Out[ ]:
84000.0

Poderíamos também ter usado o pacote Scipy:

In [ ]:
from scipy import stats
 
# Interquartile range (IQR)
IQR = stats.iqr(train['SalePrice'], interpolation = 'nearest')
  
print(IQR)
84000

São considerados outliers todos os valores maiores que Q3 + 1.5xIQR:

In [ ]:
Outliers = Q3+ 1.5*IQR
Outliers
Out[ ]:
340000.0

Ou seja, vamos analisar as características dos imóveis cujo valor ultrapassa 340.000.

In [ ]:
plt.figure(figsize=(5,6))

box = sns.boxplot(data=train, y ='SalePrice')

box.set_title('Gráfico 91: Boxplot da variável Saleprice, com identificação dos quartis')

box.text(0.4,Q1,f'------> Q1={Q1}')
box.text(0.4,Q2,f'------> Q2={Q2}')
box.text(0.4,Q3,f'------> Q3={Q3}')
box.text(0.4,Outliers,f'------> Outliers acima de {Outliers}')

plt.show()
In [ ]:
train_outliers = train[train['SalePrice']>Outliers] #dataframe para outliers
train_no_outliers = train[train['SalePrice']<Outliers] #dtaframe para não outliers

print(f'Há {train_outliers.shape[0]} outliers.')
Há 61 outliers.

Faremos uma análise breve, para tentar achar algum padrão presente nessas casas.

In [ ]:
print(f"Área mínima das casas outliers: {train_outliers['GrLivArea'].min()}")
print(f"Área máxima das casas comuns: {train_no_outliers['GrLivArea'].min()}")
Área mínima das casas outliers: 1419
Área máxima das casas comuns: 334

A área mínima das casas mais caras é de 1.419 pés², que é cerca de 5 vezes menor que a menor área das casas que não são outliers (5.642).

In [ ]:
train_outliers['Street'].value_counts()
Out[ ]:
Pave    61
Name: Street, dtype: int64

Todas as ruas são pavimentadas.

In [ ]:
print(f"Total de bairros: {len(train['Neighborhood'].unique())}")
print(f"Total de bairros outliers: {len(train_outliers['Neighborhood'].unique())}")
Total de bairros: 25
Total de bairros outliers: 11

Há 25 bairros no dataset, mas as casas mais caras estão situados em apenas 11.

In [ ]:
print(f"Total de tipos de domicílio: {len(train['BldgType'].unique())} \n")
print(f"Tipos de domicílios outliers:\n")
print('Tipo  Quantidade')
print(train_outliers['BldgType'].value_counts())
Total de tipos de domicílio: 5 

Tipos de domicílios outliers:

Tipo  Quantidade
1Fam      59
TwnhsE     2
Name: BldgType, dtype: int64

Há 5 tipos de habitação, mas apenas 2 estão entre as mais caras: 'Single-family Detached' e 'TwnhsE'.

In [ ]:
print('Nota  Quantidade')
train_outliers['OverallQual'].value_counts()
Nota  Quantidade
Out[ ]:
9     23
8     22
10    13
7      3
Name: OverallQual, dtype: int64

A maioria das casas apresentam no mínimo nota 7 para a qualidade do acabamento.

In [ ]:
train_outliers['TotRmsAbvGrd'].value_counts()
Out[ ]:
10    15
7     12
9     10
8     10
11     7
12     3
5      2
6      2
Name: TotRmsAbvGrd, dtype: int64

As casas consideradas outliers tem pelo menos 5 cômodos, e a maioria tem mais de 8 cômodos.

In [ ]:
train_outliers['Fireplaces'].value_counts()
Out[ ]:
1    43
2    15
3     2
0     1
Name: Fireplaces, dtype: int64

Apenas uma casa não possui lareira, todas as outras têm pelo menos 1.

In [ ]:
train_outliers['FullBath'].value_counts()
Out[ ]:
2    44
3    13
1     3
0     1
Name: FullBath, dtype: int64

A grande maioria das casas possuem pelo menos 2 banheiros.

In [ ]:
train_outliers['PoolArea'].value_counts() 
Out[ ]:
0      60
555     1
Name: PoolArea, dtype: int64

Diferente do que usualmente alguém imaginaria, apenas 1 casa dos outilers possui piscina.

In [ ]:
train_outliers['CentralAir'].value_counts() 
Out[ ]:
Y    61
Name: CentralAir, dtype: int64

Todas as casas outliers possuem ar condicionado.

In [ ]:
train_outliers['GarageCars'].value_counts() 
Out[ ]:
3    55
2     6
Name: GarageCars, dtype: int64

As casas possuem vagas para pelo menos 2 carros, e 55 das 61 casas possuem vagas para 3 carros.

6 Conclusão¶

Neste trabalho, procurou-se realizar uma Análise Exploratória do dataset de competição do Kaggle, entitulado "House Prices - Advanced Regression Techniques".

Alguns pontos importantes:

  • O dataset se constitui de 81 colunas, que é uma quantidade grande de colunas a serem analisadas.
  • Várias colunas apresentam apenas 2 tipos de valores, no entanto não são binárias, devendo isso ao fato de que tais colunas possuem muitos valores ausentes.
  • Muitas colunas com valores categóricos carregam implicitamente uma relação de ordem, sendo mais apropriados tratá-los como ordinais ou de renking.
  • Alguns observações, como a relação entre a idade, condições, número de quartos, banheiros, e área do imóvel já eram esperadas e se confirmaram com a análise dos dados.
  • Algumas correlações bastante óbvias como a área da garagem e a quantidade de vagas de carro na garagem também se confirmaram.
  • A análise final, sobre os outliers revelou algumas características interessante, como a presença apenas em alguns bairros, a quantidade de cômodos na casa, a não existência de piscina e outras.