Análise Exploratória de Dados com python
UFPE
![]()
.png)

Compreender os dados e descobrir o que pode ser digno de nota ou interessante a destacar para outras pessoas.
em termos quantitavivos e de nosso dia a dia
podemos pensar em iniciar nossa AED por esses dois caminhos:
variáveis?variáveis?Através destes pontos, é possível extrair informações interessantes sobre os dados em estudo.

- Hadley Wickham
Há três regras inter-relacionadas que tornam um conjunto de dados arrumados (tidy):
Cada variável deve ter sua própria coluna.
Cada observação deve ter sua própria linha.
Cada valor deve ter sua própria célula.
Vamos ao python?
DataSet utilizado: used_cars_data.csv
link: https://www.kaggle.com/datasets/sukhmanibedi/cars4u
Problemática: Esta base de dados é referente a carros usados na ‘Índia’. Através dos dados existentes, quais informações relevantes poderíamos obter sobre esses carros usados do país em questão?
=> id: Número único por linha para representar cada observação;
=> nome: Nome do carro usado
=> localizacao: Cidade de localização do carro na Índia
=> ano: Ano de fabricação do carro
=> quilometros_percorridos: Quilômetros percorridos pelo carro em km
=> tipo_de_combustivel: Tipo de combustível utilizado pelo carro
=> transmissao: Transmissão do carro
=> tipo_proprietario: Quantos donos o carro já possuiu
=> quilometragem_por_litro: Quantos km o carro faz com 1 lt
=> motor: Quantidade de cilindradas do motor
=> potencia: Potência do motor em bhp
=> assentos: Quantidade de assentos do carro
=> novo_preco: Variável que possui um preço do carro em LAKh
=> preco: Variável que possui preco do carro também em LAKh
O primeiro passo nesse caso é importar bibliotecas necessárias para análise:
| id | nome | localizacao | ano | quilometros_percorridos | tipo_de_combustivel | transmissao | tipo_proprietario | quilometragem_por_litro | motor | potencia | assentos | novo_preco | preco | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | Maruti Wagon R LXI CNG | Mumbai | 2010 | 72000 | CNG | Manual | First | 26.6 km/kg | 998 CC | 58.16 bhp | 5.0 | NaN | 1.75 |
. . .
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7253 entries, 0 to 7252
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 7253 non-null int64
1 nome 7253 non-null object
2 localizacao 7253 non-null object
3 ano 7253 non-null int64
4 quilometros_percorridos 7253 non-null int64
5 tipo_de_combustivel 7253 non-null object
6 transmissao 7253 non-null object
7 tipo_proprietario 7253 non-null object
8 quilometragem_por_litro 7251 non-null object
9 motor 7207 non-null object
10 potencia 7207 non-null object
11 assentos 7200 non-null float64
12 novo_preco 1006 non-null object
13 preco 6019 non-null float64
dtypes: float64(2), int64(3), object(9)
memory usage: 793.4+ KB

7253
id 7253
nome 2041
localizacao 11
ano 23
quilometros_percorridos 3660
tipo_de_combustivel 5
transmissao 2
tipo_proprietario 4
quilometragem_por_litro 450
motor 150
potencia 386
assentos 9
novo_preco 625
preco 1373
dtype: int64
# -----------------
# Checando variáveis que possuem dados ausentes
dados.isnull().sum()
# -----------------id 0
nome 0
localizacao 0
ano 0
quilometros_percorridos 0
tipo_de_combustivel 0
transmissao 0
tipo_proprietario 0
quilometragem_por_litro 2
motor 46
potencia 46
assentos 53
novo_preco 6247
preco 1234
dtype: int64
# -----------------
# Remover coluna 'S.No.' dos dados
dados = dados.drop(columns = ['id'])
dados.info()
# -----------------<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7253 entries, 0 to 7252
Data columns (total 13 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 nome 7253 non-null object
1 localizacao 7253 non-null object
2 ano 7253 non-null int64
3 quilometros_percorridos 7253 non-null int64
4 tipo_de_combustivel 7253 non-null object
5 transmissao 7253 non-null object
6 tipo_proprietario 7253 non-null object
7 quilometragem_por_litro 7251 non-null object
8 motor 7207 non-null object
9 potencia 7207 non-null object
10 assentos 7200 non-null float64
11 novo_preco 1006 non-null object
12 preco 6019 non-null float64
dtypes: float64(2), int64(2), object(9)
memory usage: 736.8+ KB
| ano | quilometros_percorridos | assentos | preco | |
|---|---|---|---|---|
| count | 7253.000000 | 7.253000e+03 | 7200.000000 | 6019.000000 |
| mean | 2013.365366 | 5.869906e+04 | 5.279722 | 9.479468 |
| std | 3.254421 | 8.442772e+04 | 0.811660 | 11.187917 |
| min | 1996.000000 | 1.710000e+02 | 0.000000 | 0.440000 |
| 25% | 2011.000000 | 3.400000e+04 | 5.000000 | 3.500000 |
| 50% | 2014.000000 | 5.341600e+04 | 5.000000 | 5.640000 |
| 75% | 2016.000000 | 7.300000e+04 | 5.000000 | 9.950000 |
| max | 2019.000000 | 6.500000e+06 | 10.000000 | 160.000000 |
OBS.: Ele considera os tipos de dados numéricos e calcula as métricas como int, float.
Calculando Média de diferentes formas:
Calculando Mínimo de diferentes formas:
Calculando quantis:
Porque com numpy retornou nan?
Calculando quantis:
array([ 0.44, 3.5 , 5.64, 9.95, 160. ])
Calculando quantis em mais de uma coluna:
# -----------------
# Quantis mais colunas
# -----------------
dados[["quilometros_percorridos","preco"]].quantile([0,0.25,0.5,0.75,1]) #Pandas
# -----------------| quilometros_percorridos | preco | |
|---|---|---|
| 0.00 | 171.0 | 0.44 |
| 0.25 | 34000.0 | 3.50 |
| 0.50 | 53416.0 | 5.64 |
| 0.75 | 73000.0 | 9.95 |
| 1.00 | 6500000.0 | 160.00 |
OBS.: Para não ficar sempre mostrando mais de uma solução, vamos focar no Pandas e seguir com ela até o fim desse minicurso.
Calculando variância das variáveis
ano 1.059125e+01
quilometros_percorridos 7.128040e+09
assentos 6.587914e-01
preco 1.251695e+02
dtype: float64
OBS.: Ele considera os tipos de dados numéricos e calcula as métricas como int, float.
Calculando covariância entre as variáveis
| ano | quilometros_percorridos | assentos | preco | |
|---|---|---|---|---|
| ano | 10.591255 | -5.161682e+04 | 0.021573 | 11.169366 |
| quilometros_percorridos | -51616.822165 | 7.128040e+09 | 6201.221577 | -11735.383472 |
| assentos | 0.021573 | 6.201222e+03 | 0.658791 | 0.473281 |
| preco | 11.169366 | -1.173538e+04 | 0.473281 | 125.169489 |
OBS.: Ele considera os tipos de dados numéricos e calcula as métricas como int, float.
Calculando correlação entre as variáveis
# -----------------
# Quantis mais colunas
# -----------------
dados.corr(numeric_only=True) # O padrão é False e correlação de Pearson
# -----------------| ano | quilometros_percorridos | assentos | preco | |
|---|---|---|---|---|
| ano | 1.000000 | -0.187859 | 0.008216 | 0.305327 |
| quilometros_percorridos | -0.187859 | 1.000000 | 0.090221 | -0.011493 |
| assentos | 0.008216 | 0.090221 | 1.000000 | 0.052225 |
| preco | 0.305327 | -0.011493 | 0.052225 | 1.000000 |
OBS.: Ele considera os tipos de dados numéricos e calcula as métricas como int, float.
Calculando frequências quando as variáveis são categóricas
nome
Mahindra XUV500 W8 2WD 55
Maruti Swift VDI 49
Maruti Swift Dzire VDI 42
Honda City 1.5 S MT 39
Maruti Swift VDI BSIV 37
..
Chevrolet Beat LT Option 1
Skoda Rapid 1.6 MPI AT Elegance Plus 1
Ford EcoSport 1.5 TDCi Ambiente 1
Hyundai i10 Magna 1.1 iTech SE 1
Hyundai Elite i20 Magna Plus 1
Name: count, Length: 2041, dtype: int64
Calculando frequências quando as variáveis são categóricas
# ---------------------
dados.groupby(["nome"])["nome"] \
.count() \
.reset_index(name='count') \
.sort_values(['count'], ascending=False)
# ---------------------| nome | count | |
|---|---|---|
| 1017 | Mahindra XUV500 W8 2WD | 55 |
| 1265 | Maruti Swift VDI | 49 |
| 1241 | Maruti Swift Dzire VDI | 42 |
| 457 | Honda City 1.5 S MT | 39 |
| 1266 | Maruti Swift VDI BSIV | 37 |
| ... | ... | ... |
| 939 | Mahindra NuvoSport N8 | 1 |
| 937 | Mahindra Logan Petrol 1.4 GLE | 1 |
| 936 | Mahindra Logan Diesel 1.5 DLS | 1 |
| 935 | Mahindra KUV 100 mFALCON G80 K8 | 1 |
| 1020 | Mahindra Xylo D2 BS III | 1 |
2041 rows × 2 columns
Criando tabelas cruzadas entre as variáveis
Criando tabelas cruzadas entre as variáveis
# ---------------------
# Teste de Qui-Quadrado com Transmissao e Localização
tabela_cruzada = pd.crosstab(dados['transmissao'], dados['localizacao'])
# ---
c, p, dof, expected = chi2_contingency(tabela_cruzada)
print(p)
# ---------------------1.3894902634085349e-55
| localizacao | Ahmedabad | Bangalore | Chennai | Coimbatore | Delhi | Hyderabad | Jaipur | Kochi | Kolkata | Mumbai | Pune |
|---|---|---|---|---|---|---|---|---|---|---|---|
| transmissao | |||||||||||
| Automatic | 72 | 179 | 136 | 303 | 204 | 232 | 62 | 245 | 88 | 359 | 169 |
| Manual | 203 | 261 | 455 | 469 | 456 | 644 | 437 | 527 | 566 | 590 | 596 |
# -----------------
# Criação da variável 'Car_Age'como uma novas variável
from datetime import date
# ---
print("O ano atual é: " + str(date.today().year) )
# --
dados['idade_carro'] = date.today().year - dados['ano']
# --
dados[["nome", "preco", "ano", "idade_carro"]]
# -----------------O ano atual é: 2026
| nome | preco | ano | idade_carro | |
|---|---|---|---|---|
| 0 | Maruti Wagon R LXI CNG | 1.75 | 2010 | 16 |
| 1 | Hyundai Creta 1.6 CRDi SX Option | 12.50 | 2015 | 11 |
| 2 | Honda Jazz V | 4.50 | 2011 | 15 |
| 3 | Maruti Ertiga VDI | 6.00 | 2012 | 14 |
| 4 | Audi A4 New 2.0 TDI Multitronic | 17.74 | 2013 | 13 |
| ... | ... | ... | ... | ... |
| 7248 | Volkswagen Vento Diesel Trendline | NaN | 2011 | 15 |
| 7249 | Volkswagen Polo GT TSI | NaN | 2015 | 11 |
| 7250 | Nissan Micra Diesel XV | NaN | 2012 | 14 |
| 7251 | Volkswagen Polo GT TSI | NaN | 2013 | 13 |
| 7252 | Mercedes-Benz E-Class 2009-2013 E 220 CDI Avan... | NaN | 2014 | 12 |
7253 rows × 4 columns
# -----------------
# Criação da variável 'Marca' do carro
# str.split: quebra as strings
# str.get(0): pega todas as posições 0 de cada lista criada da linha
dados['marca'] = dados.nome.str.split().str.get(0)
# --
dados[['nome','marca']].head()
# -----------------| nome | marca | |
|---|---|---|
| 0 | Maruti Wagon R LXI CNG | Maruti |
| 1 | Hyundai Creta 1.6 CRDi SX Option | Hyundai |
| 2 | Honda Jazz V | Honda |
| 3 | Maruti Ertiga VDI | Maruti |
| 4 | Audi A4 New 2.0 TDI Multitronic | Audi |
OBS.: Para retornar data.frames com duas ou mais colunas selecionadas, é necessário utilizar dois pares de
[], ou seja,df[[colname(s)]]. O primeiro par retorna uma série, enquanto os colchetes duplos retornam um dataframe.
Antes dos gráficos, vamos verificar quais variáveis são numéricas e quais são categóricas
# -----------------
cat_cols = dados.select_dtypes(include=['object']).columns
num_cols = dados.select_dtypes(include=np.number).columns.tolist()
print("Variáveis Categóricas: " + str(cat_cols))
print("Variáveis Numéricas:"+ str(num_cols))
# -----------------Variáveis Categóricas: Index(['nome', 'localizacao', 'tipo_de_combustivel', 'transmissao',
'tipo_proprietario', 'quilometragem_por_litro', 'motor', 'potencia',
'novo_preco', 'marca'],
dtype='object')
Variáveis Numéricas:['ano', 'quilometros_percorridos', 'assentos', 'preco', 'idade_carro']
Antes dos gráficos, vamos verificar quais variáveis são numéricas e quais são categóricas
idade_carro
Assimetria : 0.84

# -----------------
fig, axes = plt.subplots(3, 2, figsize = (18, 18))
fig.suptitle('Gráficos de Barras para todas as variáveis categóricas da base de dados')
sns.countplot(ax = axes[0, 0], x = 'tipo_de_combustivel', data = dados, color = 'blue',
order = dados['tipo_de_combustivel'].value_counts().index);
sns.countplot(ax = axes[0, 1], x = 'transmissao', data = dados, color = 'blue',
order = dados['transmissao'].value_counts().index);
sns.countplot(ax = axes[1, 0], x = 'tipo_proprietario', data = dados, color = 'blue',
order = dados['tipo_proprietario'].value_counts().index);
sns.countplot(ax = axes[1, 1], x = 'localizacao', data = dados, color = 'blue',
order = dados['localizacao'].value_counts().index);
sns.countplot(ax = axes[2, 0], x = 'marca', data = dados, color = 'blue',
order = dados['marca'].head(20).value_counts().index);
sns.countplot(ax = axes[2, 1], x = 'ano', data = dados, color = 'blue',
order = dados['ano'].head(20).value_counts().index);
axes[1][1].tick_params(labelrotation=45);
axes[2][0].tick_params(labelrotation=90);
axes[2][1].tick_params(labelrotation=90);
# -----------------

# -----------------
fig, axarr = plt.subplots(1,1, figsize=(7, 8))
dados_agrupados = dados.groupby('transmissao')['preco'].mean().sort_values(ascending=False)
dados_agrupados.plot.bar(fontsize=12) \
.set_title("Transmissao Vs Preço", fontsize=18)
# -----------------Text(0.5, 1.0, 'Transmissao Vs Preço')

# -------------------
# Criando uma Tabela para geração do gráfico distinta por categorias
dfp = dados.pivot_table(index='ano', columns='transmissao', values='preco', aggfunc='mean')
# -------------------
dfp.head(10)
# -----------| transmissao | Automatic | Manual |
|---|---|---|
| ano | ||
| 1998 | 3.900000 | 0.610000 |
| 1999 | NaN | 0.835000 |
| 2000 | NaN | 1.175000 |
| 2001 | NaN | 1.543750 |
| 2002 | NaN | 1.294000 |
| 2003 | 11.305000 | 1.258000 |
| 2004 | 3.931667 | 1.463600 |
| 2005 | 4.467778 | 1.569167 |
| 2006 | 10.853636 | 2.124925 |
| 2007 | 6.825000 | 2.514286 |
ggplot2
Link: SWEETVIZ_REPORT.html
O que podemos concluir de forma breve até esse momento com o estudo:
OBRIGADO!
Slide produzido com quarto
Introdução à Ciência de Dados - Prof. Jodavid Ferreira