Aprendizagem de Máquina

Introdução à Python

Prof. Jodavid Ferreira

UFPE

Ambientes Virtuais


  • Em python, geralmente utilizamos ambientes virtuais para isolar as dependências de um projeto. Isso é útil para que possamos ter diferentes versões de uma mesma biblioteca em projetos diferentes.

  • O Anaconda é um gerenciador de ambientes virtuais é o mais utilizado nos últimos anos por cientistas, desenvolvedores e engenheiros de dados que utilizam python. A vantagem de utilizar o anaconda é que ele já vem com várias bibliotecas instaladas, o que facilita o trabalho do cientista de dados.

  • Para fazer o download do Anaconda acesse o link: https://www.anaconda.com/products/distribution e faça o download da versão mais recente para seu sistema operacional.

Anaconda


Alguns comandos são importantes para utilização do Anaconda, como por exemplo:

  • Criação de ambiente virtual: conda create -n nome_do_ambiente python=3.11.5
  • Lista de ambientes virtuais: conda env list
  • Ativação de ambiente virtual: conda activate nome_do_ambiente
  • Desativação de ambiente virtual: conda deactivate
  • Remoção de ambiente virtual: conda env remove -n nome_do_ambiente

Anaconda


  • E as instalações de bibliotecas são realizadas utilizando o comando conda install nome_da_biblioteca, mas geralmente as bibliotecas em python sao utilizando o pip, que é o gerenciador de pacotes do python. Para instalar uma biblioteca utilizando o pip, utilizamos o comando pip install nome_da_biblioteca.

Por exemplo, para instalar a biblioteca pandas, utilizamos o comando:

pip install pandas

E podemos verificar se a instalação foi bem sucessida, utilizando:

pip show pandas
Name: pandas
Version: 2.1.4
Summary: Powerful data structures for data analysis, time series, and statistics
Home-page: https://pandas.pydata.org
Author: 
Author-email: The Pandas Development Team <pandas-dev@python.org>
License: BSD 3-Clause License

Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
All rights reserved.

Copyright (c) 2011-2023, Open source contributors.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Location: /home/jodavid/anaconda3/lib/python3.11/site-packages
Requires: numpy, python-dateutil, pytz, tzdata
Required-by: altair, category-encoders, datasets, datashader, gradio, holoviews, hvplot, mizani, panel, plotly-resampler, plotnine, pmdarima, pycaret, pymilvus, satveg-api, seaborn, sktime, statsmodels, streamlit, sweetviz, TTS, xarray

Módulos


  • Também conhecidos como bibliotecas, os módulos são arquivos que contém funções, variáveis e classes que podem ser utilizadas em outros programas.

  • Para utilizar um módulo em python, utilizamos o comando import nome_do_modulo. Caso deseje utilizar apenas uma função específica de um módulo, utilizamos o comando from nome_do_modulo import nome_da_funcao.

  • Como por exemplo, utilizando o modulo math:

# Exemplo de importação de módulo
import math
math.sqrt(25)
5.0

Acima o math é o módulo e sqrt é a função que calcula a raiz quadrada de um número.

Módulos


  • Em python é comum utilizarmos a abreviação de um módulo, para facilitar a utilização de suas funções. Por exemplo, o módulo pandas é comumente abreviado como pd, o módulo numpy é abreviado como np, o módulo matplotlib é abreviado como plt, entre outros.

Vale uma observação é que essas abreviações elas são abraçadas pela comunidade, ou seja, não é uma regra, mas existe uma boa prática de por exemplo, abreviar o pandas como pd, o numpy como np, o matplotlib como plt, e existe isso para várias outras bibliotecas.

Módulos


Também existe o caso de você explicitar as funções que desejas nos módulos, com o intuito de usar diretamente o nome da função, sem a necessidade de chamar o módulo. Por exemplo, ao invés de utilizar math.sqrt(25), você pode utilizar from math import sqrt e depois utilizar sqrt(25).

# Exemplo de importação de função
from math import sqrt
sqrt(25)
5.0

Note que a função sqrt foi importada diretamente do módulo math, e por isso não é necessário chamar o módulo para utilizá-la, ou seja, se a função não for utilizada como na forma acima, e utilizar o import math é necessário utilizar o math.sqrt(25) para obter o resultado, informando que a função sqrt pertence ao módulo math.

Módulos


  • O python também permite que você utilize um apelido para a função importada, por exemplo, ao invés de utilizar from math import sqrt, você pode utilizar from math import sqrt as raiz_quadrada, e depois utilizar raiz_quadrada(25) para obter o resultado. Isso é útil quando a função importada possui um nome muito grande, ou quando o nome da função importada é muito comum e pode gerar confusão com outras funções. Então, um exemplo para esse caso é:
# Exemplo de importação de função com apelido
from math import sqrt as raiz_quadrada
raiz_quadrada(25)
5.0

Laços e Condicionais


Laços e Condicionais


  • Muitas linguagens usam chaves para delimitar blocos de código, mas em Python, a indentação é usada para isso. A indentação é uma parte importante da linguagem Python e, muitas vezes, é uma fonte de erros para os programadores que estão começando a aprender a linguagem.
# Exemplo de condicional
x = 10
if x > 5:
    print("x é maior que 5")
else:
    print("x é menor ou igual a 5")
x é maior que 5
  • Como é possível observar acima, o bloco de código que está dentro do if e do else está indentado, ou seja, está com um espaço a mais em relação ao bloco de código que está fora do if e do else. Isso é necessário para que o python entenda que o bloco de código está dentro do if e do else.

Laços e Condicionais


Quando o laço é utilizando for e while, a indentação também é necessária para delimitar o bloco de código que está dentro do laço.

# Exemplo de laço for
for i in range(5):
    print(i)
0
1
2
3
4
# Exemplo de laço while
i = 0
while i < 5:
    print(i)
    i += 1

Uma observação importante, é que diferente da linguagem R o python inicia sua indexação em 0, ou seja, o primeiro elemento de uma lista, por exemplo, é o elemento 0, o segundo elemento é o elemento 1, e assim por diante. No R a indexação inicia em 1.

Laços Complexos


  • Em python, se você possui uma lista, é possível acessar os elementos da lista diretamente da iteração no laço for. Isso é muito útil quando você deseja acessar o índice e o valor de um elemento da lista.
# Exemplo de laço for com acesso ao índice e ao valor
lista = [10, 20, 30, 40, 50,  60, 70, 80, 90, 100]
for i in lista:
    print(i)

Laços Complexos


  • Em python, se você possui uma lista, é possível acessar os elementos da lista diretamente da iteração no laço for. Isso é muito útil quando você deseja acessar o índice e o valor de um elemento da lista.
# Exemplo de laço for com acesso ao índice e ao valor
lista = [10, 20, 30, 40, 50,  60, 70, 80, 90, 100]
for i in lista:
    print(i)
10
20
30
40
50
60
70
80
90
100

Laços Complexos


  • Uma forma mais complexa é utilizando a função enumerate para acessar o índice e o valor de um elemento da lista.
# Exemplo de laço for com acesso ao índice e ao valor
lista = [10, 20, 30, 40, 50]
for i, valor in enumerate(lista):
    print(f"O elemento {i} da lista é {valor}")
O elemento 0 da lista é 10
O elemento 1 da lista é 20
O elemento 2 da lista é 30
O elemento 3 da lista é 40
O elemento 4 da lista é 50
  • Mas vamos avançando aos poucos, e vamos ver como podemos criar funções em python.

Funções


Em python, as funções são criadas utilizando a palavra-chave def, seguida pelo nome da função, seguida por parênteses, seguida por dois pontos. O bloco de código que está dentro da função é indentado, ou seja, está com um espaço a mais em relação ao bloco de código que está fora da função.

# Exemplo de função
def minha_funcao():
    print("Olá, mundo!")

Para chamar a função, basta utilizar o nome da função seguido por parênteses.

# Chamando a função
minha_funcao()
Olá, mundo!

Como boas práticas de programação, é interessante que as funções possuam argumentos e docstring, ou seja, parâmetros que são passados para a função e dentro da função um cabeçalho indicando o que cada argumento representa, respectivamente. Isso torna a função mais flexível e mais útil.

Funções


Um exemplo de função com argumentos e docstring é:

# Exemplo de função com argumentos e docstring
def saudacao(nome, saudacao="Olá"):
    """
    Função para saudar alguém
    Argumentos:
    nome: str, nome da pessoa a ser saudada
    saudacao: str, saudação a ser utilizada
    """
    print(f"{saudacao}, {nome}!")

No exemplo acima, a função saudacao possui dois argumentos, nome e saudacao, onde nome é obrigatório e saudacao é opcional, pois possui um valor padrão. Além disso, a função possui um cabeçalho que indica o que cada argumento representa.

Funções


Também existe em python as chamdas funções anônimas ou funções lambda, que são funções que não possuem um nome, e são utilizadas para criar funções simples e rápidas.

E o interessante é que as funções lambda podem ser utilizadas em conjunto com as funções map, filter e reduce para realizar operações em listas.

# Exemplo de função lambda com map
lista = [1, 2, 3, 4, 5]
quadrado = map(lambda x: x ** 2, lista)
resultado = list(quadrado)
print(resultado)

Funções


É possível também atribuir funções lambda a variáveis, como no exemplo abaixo:

# Exemplo de função lambda
quadrado = lambda x: x ** 2
quadrado(5)

Entretanto, a maioria das pessoas vão preferir e lhe dizer para usar a função def ao invés da função lambda, pois a função def é mais legível e mais fácil de entender.

Como por exemplo:

soma = lambda x, y: x + y # Não faça isso
def soma(x, y): return x + y # faça isso

Strings


As strings podem ser demilitadas por aspas simples ou duplas, e podem ser acessadas como listas, ou seja, é possível acessar cada caractere da string utilizando a indexação.

# Exemplo de string
single_quoted_string = 'data science'
double_quoted_string = "data science"
single_quoted_string == double_quoted_string
True

O python usa barra invertida para codificar caracteres especiais. Por exemplo, para incluir uma aspa simples em uma string delimitada por aspas simples, você deve usar \'.

# Exemplo de string com aspas simples
tab_string = "\t" # representa o caractere de tabulação
len(tab_string)
1

Strings


Também é possível criar strings múltiplas linhas utilizando três aspas simples ou duplas.

# Exemplo de string com múltiplas linhas
multi_line_string = """Esta é a primeira linha.
e esta é a segunda linha
e esta é a terceira linha"""
print(multi_line_string)
Esta é a primeira linha.
e esta é a segunda linha
e esta é a terceira linha

O python também possui uma série de funções para manipular strings, como por exemplo, a função split que divide uma string em uma lista de substrings.

# Exemplo de função split
s = "Olá, mundo!"
s.split()
['Olá,', 'mundo!']

Listas


As listas são uma das estruturas de dados mais importantes do python. Elas são similares aos vetores em outras linguagens, como por exemplo na linguagem R^[No R,tipos diferentes no vetor ele converte para character, por exemplo vetor <-c("a",1,TRUE), entretanto, são mais flexíveis. Elas são mais flexíveis, pois podem armazenar qualquer tipo de dado, e não são limitadas a um único tipo de dado.

# Exemplo de lista
integer_list = [1, 2, 3]
heterogeneous_list = ["string", 0.1, True]
list_of_lists = [integer_list, heterogeneous_list, []]
list_length = len(integer_list)
list_sum = sum(integer_list)

print(integer_list)
[1, 2, 3]
print(heterogeneous_list)
['string', 0.1, True]
print(list_of_lists)
[[1, 2, 3], ['string', 0.1, True], []]
print(list_length)
3
print(list_sum)
6

Listas


Você pode acessar ou modificar o i-ésimo elemento de uma lista utilizando colchetes.

# Exemplo de acesso a elementos de uma lista
x = list(range(10))
zero = x[0]
one = x[1]
nine = x[-1]
eight = x[-2]
x[0] = -1



print(x)
[-1, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Listas


Além disso, o python possui uma sintaxe de corte que permite acessar múltiplos elementos de uma lista.

# Exemplo de corte de lista
first_three = x[:3]
three_to_end = x[3:]
one_to_four = x[1:5]
last_three = x[-3:]
without_first_and_last = x[1:-1]
copy_of_x = x[:]

print(first_three)
[-1, 1, 2]
print(three_to_end)
[3, 4, 5, 6, 7, 8, 9]
print(one_to_four)
[1, 2, 3, 4]
print(last_three)
[7, 8, 9]
print(without_first_and_last)
[1, 2, 3, 4, 5, 6, 7, 8]
print(copy_of_x)
[-1, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Listas


Um operação interessante é utilizando o operator in para verificar se um elemento está contido em uma lista.

# Exemplo de operador in
1 in [1, 2, 3]
True
0 in [1, 2, 3]
False

OBS.: Essa operação é muito mais lenta em listas do que em dicionários e conjuntos, pois o python faz uma busca linear em listas, ou seja, verifica os elementos da lista um de cadas vez, sendo assim a verificação em um conjunto ou dicionário é muito rápido. Vamos estudar consjuntos e dicionários mais a frente.

Com listas, também podemos concatenar, ou seja, adicionar mais informações a lista, e isso pode ser feito de várias formas, como adição de elementos a lista, junção de várias listas, ou multiplicação de listas. Abaixo segue exemplos de como fazer isso.

Listas


# Exemplo de concatenação de listas
x = [1, 2, 3]
x.extend([4, 5, 6])
print(x)
[1, 2, 3, 4, 5, 6]
# Exemplo de concatenação de listas
x = [1, 2, 3]
y = x + [4, 5, 6]
print(y)
[1, 2, 3, 4, 5, 6]
# Exemplo de concatenação de elementos a lista
x = [1, 2, 3]
x.append(0)
y = x[-1]
z = len(x)
print(x)
[1, 2, 3, 0]
print(y)
0
print(z)
4

Listas


# Exemplo de junção de listas
x, y = [1, 2], [3, 4]
z = x + y
print(z)
[1, 2, 3, 4]
# Exemplo de multiplicação de listas
x = [1, 2] * 3
print(x)
[1, 2, 1, 2, 1, 2]

Tuplas


Chegamos a Tuplas, e o que seria isso? Tuplas são muito parecidas com listas, mas com uma diferença fundamental, elas são imutáveis, ou seja, uma vez que você cria uma tupla, você não pode adicionar, remover ou modificar elementos dela. Tuplas são geralmente utilizadas para funções que retornam múltiplos valores. Vamos a exemplos:

# Exemplo de tuplas
my_list = [1, 2]
my_tuple = (1, 2)
other_tuple = 3, 4
my_list[1] = 3
try:
    my_tuple[1] = 3
except TypeError:
    print("Não é possível modificar uma tupla")
Não é possível modificar uma tupla

Tuplas


Um outro exemplo:

# Exemplo de tuplas
def sum_and_product(x, y):
    return (x + y), (x * y)
  
sp = sum_and_product(2, 3)
s, p = sum_and_product(5, 10)
print(sp)
(5, 6)
print(s)
15
print(p)
50

As tuplas (e listas) podem ser usadas para atribuições múltiplas, o que é muito útil para trocar valores de variáveis.

# Exemplo de atribuição múltipla
x, y = 1, 2
x, y = y, x
print(x)
2
print(y)
1

Dicionários


Outra estrutura fundamental é o dicionário, que é uma coleção de pares chave-valor, onde as chaves devem ser únicas. Dicionários são como listas, mas mais gerais, pois você pode indexá-los com qualquer tipo imutável, não apenas inteiros. Vamos a exemplos:

# Exemplo de dicionários
empty_dict = {}
empty_dict2 = dict()
grades = {"Joel": 80, "Tim": 95}
joels_grade = grades["Joel"]
print(empty_dict)
{}
print(empty_dict2)
{}
print(grades)
{'Joel': 80, 'Tim': 95}
print(joels_grade)
80

Dicionários


# Exemplo de operador in
joel_has_grade = "Joel" in grades
kate_has_grade = "Kate" in grades
print(joel_has_grade)
True
print(kate_has_grade)
False
# Exemplo de get
joels_grade = grades.get("Joel", 0)
kates_grade = grades.get("Kate", 0)
no_ones_grade = grades.get("No One")
print(joels_grade)
80
print(kates_grade)
0
print(no_ones_grade)
None

Dicionários


# Exemplo de atribuição de valores
grades["Tim"] = 99
grades["Kate"] = 100
num_students = len(grades)
print(grades)
{'Joel': 80, 'Tim': 99, 'Kate': 100}
print(num_students)
3

Dicionários são muito utilizados para contadores, ou seja, para contar a frequência de ocorrência de elementos em uma lista. Vamos a um exemplo:

# Exemplo de contadores
document = ["data", "science", "from", "scratch", "data", "science", "data"]
word_counts = {}
for word in document:
    if word in word_counts:
        word_counts[word] += 1
    else:
        word_counts[word] = 1
print(word_counts)
{'data': 3, 'science': 2, 'from': 1, 'scratch': 1}

Dicionários


Frequentemente usamos dicionários para representar dados “semi-estruturados”. Por exemplo, poderíamos ter um dicionário por usuário em uma rede social, onde as chaves são os nomes das colunas e os valores são os dados do usuário. Por exemplo:

# Exemplo de dicionários semi-estruturados
tweet = {
    "user" : "joelgrus",
    "text" : "Data Science.",
    "retweet_count" : 100,
    "hashtags" : ["#data", "#science", "#datascience", "#bigdata"]
}
print(tweet)
{'user': 'joelgrus', 'text': 'Data Science.', 'retweet_count': 100, 'hashtags': ['#data', '#science', '#datascience', '#bigdata']}

Dicionários


Além de procurar por chaves específicas, podemos olhar para todas elas. Por exemplo:

# Exemplo de chaves e valores
tweet_keys = tweet.keys()
tweet_values = tweet.values()
tweet_items = tweet.items()
print(tweet_keys)
dict_keys(['user', 'text', 'retweet_count', 'hashtags'])
print(tweet_values)
dict_values(['joelgrus', 'Data Science.', 100, ['#data', '#science', '#datascience', '#bigdata']])
print(tweet_items)
dict_items([('user', 'joelgrus'), ('text', 'Data Science.'), ('retweet_count', 100), ('hashtags', ['#data', '#science', '#datascience', '#bigdata'])])

As chaves dos dicionários devem ser imutáveis, o que significa que podemos usar strings, números ou tuplas como chaves, mas não listas. Por exemplo:

# Exemplo de chaves imutáveis
#bad idea
#bad_dict = {[1, 2, 3]: "one two three"}
#good idea
good_dict = {(1, 2, 3): "one two three"}
print(good_dict)
{(1, 2, 3): 'one two three'}

Conjuntos


Conjuntos são uma outra estrutura de dados em Python. Um conjunto é uma coleção de elementos distintos, ou seja, não há repetição de elementos. Os conjuntos em python são similares aos conjuntos em matemática e utilizam a função set() para criá-los. Vamos a exemplos:

# Exemplo de conjuntos
s = set()
s.add(1)
s.add(2)
s.add(2)
x = len(s)
y = 2 in s
z = 3 in s
print(s)
{1, 2}
print(x)
2
print(y)
True
print(z)
False

Conjuntos


Conjuntos são muito úteis para verificar a existência de elementos distintos em uma coleção1. Por exemplo, podemos verificar a existência de palavras distintas em um texto. Vamos a um exemplo:

# Exemplo de palavras distintas
text = "data science from scratch data science data"
words = text.split()
word_set = set(words)
print(words)
['data', 'science', 'from', 'scratch', 'data', 'science', 'data']
print(word_set)
{'science', 'scratch', 'data', 'from'}






Análise Exploratória de Dados

com python









Python - Base de dados



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?


Python - Base de dados




=> 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


Obs.: 1 Lakh, chamado de um laque, é uma unidade do sistema de numeração indiana. Um laque indiano equivale a 100.000 (cem mil) rupias indianas. E 1 rupia equivale a 0,06 centavos. Assim, 1 Lakh = 6.415,62 reais.

Python - Importação das Bibliotecas



O primeiro passo nesse caso é importar bibliotecas necessárias para análise:

# -----------------
# Bibliotecas necessarias para Analise dos Dados
import pandas as pd
import numpy as np
import scipy as sp
# -----------------
# Bibliotecas Gráficas
import matplotlib.pyplot as plt
import seaborn as sns
# -----------------
import plotly.express as px
# -----------------



Python - Lendo base de dados


# -----------------
# Lendo a Base de dados
dados = pd.read_csv("dataset/used_cars_data.csv")
# -----------------

Visualizando um cabeçalho dos dados

# -----------------
# Visualizando um cabeçalho dos dados
dados.head()
   id                              nome localizacao  ...  assentos  novo_preco  preco
0   0            Maruti Wagon R LXI CNG      Mumbai  ...       5.0         NaN   1.75
1   1  Hyundai Creta 1.6 CRDi SX Option        Pune  ...       5.0         NaN  12.50
2   2                      Honda Jazz V     Chennai  ...       5.0   8.61 Lakh   4.50
3   3                 Maruti Ertiga VDI     Chennai  ...       7.0         NaN   6.00
4   4   Audi A4 New 2.0 TDI Multitronic  Coimbatore  ...       5.0         NaN  17.74

[5 rows x 14 columns]
# -----------------


# -----------------
# Visualizando os últimos dados
dados.tail()
# -----------------

Python - Tipos das variáveis



# -----------------
# Visualizando Informações das colunas
dados.info()
<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
# -----------------


Python - Tamanho da base de dados



# -----------------
# Visualizando Quantidades de Linhas e colunas
len(dados)
7253
# -----------------


# -----------------
len(dados.columns)
14
# -----------------
# -----------------
dados.columns
Index(['id', 'nome', 'localizacao', 'ano', 'quilometros_percorridos',
       'tipo_de_combustivel', 'transmissao', 'tipo_proprietario',
       'quilometragem_por_litro', 'motor', 'potencia', 'assentos',
       'novo_preco', 'preco'],
      dtype='object')
# -----------------
# -----------------
dados.shape
(7253, 14)
# -----------------

Python - Dados únicos por variável



# -----------------
# Checando dados únicos por variável
dados.nunique()
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
# -----------------


Python - Valores nulos nas colunas



# -----------------
# 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
# -----------------


Python - Removendo colunas


# -----------------
# Remover coluna 'S.No.' dos dados
dados = dados.drop(['id'], axis = 1)
dados.info()
# -----------------

# -----------------
# 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
# -----------------


Python - Métricas Estatísticas



# -----------------
dados.describe()
               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.

Python - Medidas de tend. central


Calculando Média de diferentes formas:

Usando Pandas

# -----------------
dados["preco"].mean()
9.47946835022429
# -----------------

Usando numpy

# -----------------
np.mean(dados["preco"])
9.47946835022429
# -----------------

Python - Medidas de tend. central


Calculando Mínimo de diferentes formas:

Usando Pandas

# -----------------
dados["preco"].min()
0.44
# -----------------

Usando numpy

# -----------------
np.min(dados["preco"])
0.44
# -----------------

Python - Medidas de tend. central


Calculando quantis:

Usando Pandas

# -----------------
dados["preco"].quantile()
5.64
# -----------------
# -----------------
dados["preco"].median()
5.64
# -----------------

Usando numpy

# -----------------
np.quantile(dados["preco"], 0.5)
nan
# -----------------

Porque com numpy retornou nan?

Python - Medidas de tend. central


Calculando quantis:

Corrigindo numpy

# -----------------
np.nanquantile(dados["preco"], 0.5)
5.64
# -----------------
considerando mais de um quantil
# -----------------
np.nanquantile(dados["preco"], [0,0.25,0.5,0.75,1]) #Numpy
array([  0.44,   3.5 ,   5.64,   9.95, 160.  ])
# -----------------

Usando pandas

# -----------------
dados["preco"].quantile([0,0.25,0.5,0.75,1]) #Pandas
0.00      0.44
0.25      3.50
0.50      5.64
0.75      9.95
1.00    160.00
Name: preco, dtype: float64
# -----------------

Python - Medidas de tend. central



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.

Python - Medidas de dispersão



Calculando variância das variáveis

# -----------------
dados.var(numeric_only=True) # O padrão  é False
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.

Python - Medidas de dispersão



Calculando covariância entre as variáveis

# -----------------
dados.cov(numeric_only=True) # O padrão é False
                                  ano  ...         preco
ano                         10.591255  ...     11.169366
quilometros_percorridos -51616.822165  ... -11735.383472
assentos                     0.021573  ...      0.473281
preco                       11.169366  ...    125.169489

[4 rows x 4 columns]
# -----------------


OBS.: Ele considera os tipos de dados numéricos e calcula as métricas como int, float.

Python - Medidas de dispersão



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.

Python - Variáveis Qualitativas


Calculando frequências quando as variáveis são categóricas


# ---------------------
dados["nome"].value_counts()
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
# ---------------------


Python - Variáveis Qualitativas


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 x 2 columns]
# ---------------------


Python - Variáveis Qualitativas


Criando tabelas cruzadas entre as variáveis


# ---------------------
tabela_cruzada = pd.crosstab(dados['transmissao'], dados['tipo_proprietario']) 
# -------
tabela_cruzada
tipo_proprietario  First  Fourth & Above  Second  Third
transmissao                                            
Automatic           1682               1     332     34
Manual              4270              11     820    103
# ---------------------


# ---------------------
# Teste de Qui-Quadrado
from scipy.stats import chisquare
from scipy.stats import chi2_contingency

# Aplicando Teste Qui-Quadrado na Tabela. 
c, p, dof, expected = chi2_contingency(tabela_cruzada)
print(p)
0.34358871263824625
# ---------------------

Python - Variáveis Qualitativas


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
# ---------------------


# ---------------------
# Tabela Cruzada para Transmissao e Localização
tabela_cruzada
localizacao  Ahmedabad  Bangalore  Chennai  ...  Kolkata  Mumbai  Pune
transmissao                                 ...                       
Automatic           72        179      136  ...       88     359   169
Manual             203        261      455  ...      566     590   596

[2 rows x 11 columns]
# --------

Python - Criação de variáveis



# -----------------
# Criação da variável 'Car_Age'como uma novas variável
from datetime import date
# ---
print("O ano atual é: " + str(date.today().year) )
O ano atual é: 2025
# --
dados['idade_carro'] = date.today().year - dados['ano']
# --
dados[["nome", "preco", "ano", "idade_carro"]]
                                                   nome  ...  idade_carro
0                                Maruti Wagon R LXI CNG  ...           15
1                      Hyundai Creta 1.6 CRDi SX Option  ...           10
2                                          Honda Jazz V  ...           14
3                                     Maruti Ertiga VDI  ...           13
4                       Audi A4 New 2.0 TDI Multitronic  ...           12
...                                                 ...  ...          ...
7248                  Volkswagen Vento Diesel Trendline  ...           14
7249                             Volkswagen Polo GT TSI  ...           10
7250                             Nissan Micra Diesel XV  ...           13
7251                             Volkswagen Polo GT TSI  ...           12
7252  Mercedes-Benz E-Class 2009-2013 E 220 CDI Avan...  ...           11

[7253 rows x 4 columns]
# -----------------


Python - Criação de variáveis



# -----------------
# 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.

Python - Verificando variáveis


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))
Variáveis Categóricas: Index(['nome', 'localizacao', 'tipo_de_combustivel', 'transmissao',
       'tipo_proprietario', 'quilometragem_por_litro', 'motor', 'potencia',
       'novo_preco', 'marca'],
      dtype='object')
print("Variáveis Numéricas:"+ str(num_cols))
Variáveis Numéricas:['ano', 'quilometros_percorridos', 'assentos', 'preco', 'idade_carro']
# -----------------


Python - Gráficos


Histogramas e BoxPlot

Antes dos gráficos, vamos verificar quais variáveis são numéricas e quais são categóricas


# -----------------
for col in num_cols:
    print(col)
    print('Assimetria :', round(dados[col].skew(), 2))
    plt.figure(figsize = (15, 4))
    plt.subplot(1, 2, 1)
    dados[col].hist(grid=False)
    plt.ylabel('Frequência')
    plt.subplot(1, 2, 2)
    sns.boxplot(x=dados[col])
    plt.show()
# -----------------

Python - Gráficos


Histogramas e BoxPlot

idade_carro
Assimetria : 0.84


Python - Gráficos


Gráficos de Barras

# -----------------
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);
# -----------------


Python - Gráficos


Gráficos de Barras


Python - Gráficos


Gráficos Bivariados

# -----------------
sns.pairplot(data=dados[['quilometros_percorridos','preco','transmissao']], \
             height=4.5, \
             corner = True,\
             hue="transmissao")

# -----------------


Python - Gráficos


Gráficos Bivariados

Python - Gráficos


Gráficos de Barras entre variável categórica e uma numérica

# -----------------
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)
# -----------------

Python - Gráficos


Gráficos de Barras entre duas variáveis categóricas e uma numérica

# -------------------
# 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
# -----------

Python - Gráficos


Gráficos de Barras entre duas variáveis categóricas e uma numérica

dfp.plot.barh(fontsize=10, rot = 0) \
  .set_title("Transmissao Vs Preço", fontsize=18)

Python - Gráficos


HeatMap - Mapa de calor para correlação

sns.heatmap(dados[['quilometros_percorridos','assentos', 'idade_carro','preco']].corr(), \
            annot = True, vmin = -1, vmax = 1)

Python - Outras bibliotecas Gráficas


import plotly.express as px
# ------
dados_agrupados_p = dados_agrupados.reset_index(name = 'preco_medio')
# ------
fig = px.bar(dados_agrupados_p, x='transmissao', y = 'preco_medio')
fig.show()

Python - Outras bibliotecas Gráficas


from plotnine import ggplot, geom_bar, aes
# ------
dados_agrupados_p = dados_agrupados.reset_index(name = 'preco_medio')
# ------
ggplot(dados_agrupados_p, aes(x = 'transmissao', y = 'preco_medio')) \
+ geom_bar(stat = "identity")
<Figure Size: (640 x 480)>

Python - Relatório com o SweetViz



# ---------
# Importanto a biblioteca
import sweetviz as sv
# ---------
report = sv.analyze(dados)
report.show_html()
# ---------


Link: SWEETVIZ_REPORT.html

Conclusões



O que podemos concluir de forma breve até esse momento com o estudo:


  • Existem uma frequência maior de carros manuais;
  • Os carros de transmissão automáticos são mais caros que os carros manuais;
  • Existe uma correlação fraca/moderada negativa, entre o ano dos carros e os preços, ou seja, quanto maior a idade do carro, mais barato ele é.
  • Existe uma correlação fraca entre idade do carro e quilometragem percorrida, ou seja, quanto mais antigo for o carro, mais quilometragem provavelmente percorreu.

Referências



Básicas

  • Aprendizado de Máquina: uma abordagem estatística, Izibicki, R. and Santos, T. M., 2020, link: https://rafaelizbicki.com/AME.pdf.

  • An Introduction to Statistical Learning: with Applications in R, James, G., Witten, D., Hastie, T. and Tibshirani, R., Springer, 2013, link: https://www.statlearning.com/.

  • Mathematics for Machine Learning, Deisenroth, M. P., Faisal. A. F., Ong, C. S., Cambridge University Press, 2020, link: https://mml-book.com.

Referências



Complementares




OBRIGADO!


Slide produzido com quarto