Introdução ao Python

Autor: Felipe Maia Polo - Fundador e ex-presidente do Neuron - Data science and Artificial Intelligence, economista pela USP e mestrando em Estatística pela mesma instituição. Apaixonado por matemática, estatística e data science.

Contato: felipemaiapolo@gmail.com - https://www.linkedin.com/in/felipemaiapolo/

Feedback: https://forms.gle/U6yBVSYwxNRWaE15A

Sugestões de leitura

  1. Probabilidade: Ross, S. (2014). A first course in probability. Pearson.
  2. Probabilidade e Estatística: Morettin, P. A., & BUSSAB, W. O. (2017). Estatística básica. Editora Saraiva.
  3. Análise de Regressão (linear & logística): Wooldridge, J. M. (2015). Introductory econometrics: A modern approach. Nelson Education.
  4. Machine Learning: James, G., Witten, D., Hastie, T., & Tibshirani, R. (2013). An introduction to statistical learning (Vol. 112, p. 18). New York: springer.

Python é uma versátil linguagem de programação e que, ultimamente, vem sendo muito usada no mercado para se fazer análise de dados, sobretudo fazer o uso de modelos estatísticos e de machine learning. Vou primeiramente apresentar algumas das principais funções da linguagem e depois introduzir os pacotes mais importantes para nós: Numpy e Pandas.

Funcionalidades da linguagem

Variáveis

Variáveis são os espaços de memória criado pela linguagem para você manipular e armazenar dados. Para usar uma variável basta escolher uma letra ou palavra e atribuir um valor a ela com o sinal de "=". É importante dizer que há diferenciação entre letras maiúsculas e minúsculas, que não pode haver espaços na nomeação e que o primeiro caracter não pode ser um número. Existem basicamente três tipos de variáveis que são mais importantes para nós: as strings (guardam textos), integers (guardam números inteiros) e floats (guardam números racionais).

In [1]:
#Criando variável do tipo string
x="Data Science"

#Criando variável do tipo integer
y=42

#Criando variável do tipo float
z=3.1415

#Mostrando os valores e tipos das nossas variáveis
print(type(x),x)
print(type(y),y)
print(type(z),z)
<class 'str'> Data Science
<class 'int'> 42
<class 'float'> 3.1415

O Python designa o tipo da variável automaticamente quando incluímos seus valores. É possível fazer a conversão de um tipo de variável para outro:

In [2]:
#Convertendo uma string em float

w="2.71"
w=float(w)

print(type(w),w)

#Convertendo uma integer em float

y=float(y)

print(type(y),y)
<class 'float'> 2.71
<class 'float'> 42.0

Operadores

Para realizarmos as operações (matemáticas e testes lógicos) no Python usamos os operadores. Os operadores matemáticos nos permitem fazer somas, subtrações, divisões entre outras operações. Já os operadores lógicos realizam comparações e a resposta da linguagem será ou Verdadeiro (true) ou Falso (false).

In [3]:
#Realizando algumas operações matemáticas
x=3
y=8
z=-1

print(x-y) #Subtração
print(y*z+x) #Multiplicação e adição
print(y/x) #Divisão
print(y**z) #Potenciação
-5
-5
2.6666666666666665
0.125
In [4]:
#Realizando alguns testes lógicos

print("3<4:",3<4)
print("3>4:",3>4)
print("1>=1:",1>=1)
print("9==9:",9==9)
print("x>(z+3)**2:",x>(z+3)**2)

#Podemos guardar o valor do teste dentro de uma variável
teste=3<4
print("\n")
print(type(teste),teste)
3<4: True
3>4: False
1>=1: True
9==9: True
x>(z+3)**2: False


<class 'bool'> True

Listas

Listas são objetos capazes de armazenar outros objetos, sendo que uma lista pode conter qualquer coisa, inclusive outra lista. Cada valor da lista recebe um índice a partir do 0:

In [5]:
#Criando uma lista
lista = [2,'1',['big','data'],4,5.0]

print(type(lista)) 
print(len(lista)) #Tamanho da lista
print(lista)
<class 'list'>
5
[2, '1', ['big', 'data'], 4, 5.0]
In [6]:
#Acessando alguns dos objetos dentra da lista pelos índices
print("lista[0]:   ",lista[0])
print("lista[-1]:  ",lista[-1])
print("lista[1:4]: ",lista[1:4]) #perceba que quando utilizamos "x:y", o Python retorna os elementos de "x" a "y-1"
print("lista[4:]:  ",lista[4:])
print("lista[:2]:  ",lista[:2])
lista[0]:    2
lista[-1]:   5.0
lista[1:4]:  ['1', ['big', 'data'], 4]
lista[4:]:   [5.0]
lista[:2]:   [2, '1']

É possível adicionar ou remover objetos dentro de listas já existentes, além de ser possível concatenar duas listas:

In [7]:
#Criando lista vazia
lista2=[]

#Preenchendo a lista
lista2.append(6)
lista2.append("99")
lista2.append("Data Science")
lista2.append("99")

print(lista2)

#Checando se há um elemento específico dentro da lista
print("\n") #Pulando uma linha no output
print("99" in lista2)

#Excluindo um elemento específico
lista2.remove('99')

print("\n") #Pulando uma linha no output
print(lista2)

#Concatenando duas listas
lista.extend(lista2)

print("\n") #Pulando uma linha no output
print(lista)
[6, '99', 'Data Science', '99']


True


[6, 'Data Science', '99']


[2, '1', ['big', 'data'], 4, 5.0, 6, 'Data Science', '99']

Dicionário

Outro tipo de objeto semelhante às listas é o Dicionário. O dicionário armazena uma sequência de objetos os quais cada item é uma chave, que é associada a um valor:

In [8]:
#Criando um dicionário
dic={'carro': 'gol', 'comida': 'pizza', 
            'animal': 'abelha', 'matéria': 'matemática','número':70}

print(dic)
{'carro': 'gol', 'comida': 'pizza', 'animal': 'abelha', 'matéria': 'matemática', 'número': 70}

Podemos adicionar, alterar e acessar os objetos dentro dos dicionários por suas chaves:

In [9]:
#Acessando um objeto
print(dic["carro"])

#Alterando o objeto 
dic["carro"]="corsa"
print(dic["carro"])

#Adicionando objeto 
dic[99]=3.14
print(dic[99])
gol
corsa
3.14

O dicionário é muito útil pois os índices são customizáveis, ao contrário das listas, e pode-se guardar qualquer tipo de objeto dentro, até mesmo bases de dados.

Loops

Os loops são estruturas usadas para repetir o mesmo bloco de comandos várias vezes. Estudaremos duas função de repetição do python o while(): e o for.

O for repete o bloco de comando até que um limite estabelecido seja atingido (e.g. "para i começando de 0 até i=4, faça alguma coisa"), a sintaxe é feita da seguinte forma:

In [10]:
#Exemplo For
for item in range(5):
    print (item, item**2) #número e seu quadrado
0 0
1 1
2 4
3 9
4 16

É importante dizer que é possível iterar sobre objetos de uma lista:

In [11]:
#Criando um dicionário
dic={'carro': 'gol', 'comida': 'pizza', 
            'animal': 'abelha', 'matéria': 'matemática','número':70}

index=['carro','animal','matéria']

for i in index:
    print(i,":",dic[i])
carro : gol
animal : abelha
matéria : matemática

O loop While repete ações até que uma condição, inicialmente verdadeira, seja falsa:

In [12]:
#Exemplo While
i=0

while i<10:
    i=i+1
    print(i)
1
2
3
4
5
6
7
8
9
10

Condicionais

Um aspecto intrínseco à codificação é o processo decisório. No Python, este processo se dá por meio da avaliação de expressões booleanas (expressões cujo resultado ou é TRUE ou é FALSE). Ou seja, em determinada situação, se a expressão booleana der TRUE, o programa seguirá um caminho, caso dê false, seguirá outro. A estrutura decisória é apresentada da seguinte forma:

In [13]:
#Exemplo If
x=2

if x<3:
    print(x**2)
else:
    print(x)
4

No exemplo acima temos uma estrutura condicional muito simples com somente uma condição: Abaixo um exemplo mais complexo:

In [14]:
#Exemplo If
x=4

if x<3:
    print(x**2)
elif x<5:
    print(x**3)
else:
    print(x)
64

Vamos agora utilizar mais de uma condição para nossos testes:

In [15]:
#Exemplo If
x=40

if x>3 and x<10: #As duas condições devem ser verdadeiras
    print("Primeiro.")
elif x>50 or x<30: #Pelo menos uma das condições deve ser verdadeira
    print("Segundo.")
else:
    print("Terceiro.")
Terceiro.

Funções

As funções em Python são caracterizadas pelo comando "def" seguido pelo nome da função e os argumentos que ela recebe, assim indicando o início de uma função:

def minha_funcao(.):

Chamamos de argumentos de uma função os elementos que serão manipuladas dentro de uma função, sendo esses elementos de qualquer tipo oferecido pela linguagem (listas, strings, etc). Para usarmos o resultado gerado por uma função usamos o comando "return" - ele permite fazer que esse resultado seja mandado para uma variável fora da função:

In [16]:
#Exemplo 1
def media(x1,x2):
    return (x1+x2)/2
  
media(2,3)
Out[16]:
2.5
In [17]:
#Exemplo 2 (equações de 2º grau)
def bhaskara(a,b,c):
    
    delta=b**2-4*a*c
    
    if delta<0:
        return "A equação não tem raízes reais."
    elif delta==0:
        return -b/(2*a)
    else:
        return (-b-(delta)**.5)/(2*a), (-b+(delta)**.5)/(2*a)
In [18]:
#Resolvendo equações de 2º grau
print(bhaskara(1,1,1))
print(bhaskara(1,4,0))
print(bhaskara(2,0,0))
A equação não tem raízes reais.
(-4.0, 0.0)
0.0
In [19]:
#Exemplo 3 (concatenando strings)

def concat(s1,s2,s3):
    return s1+s2+s3
In [20]:
print(concat("Hello"," ","World!"))
Hello World!

Numpy

Numpy é um biblioteca do Python que nos permite trabalhar com vetores, matrizes e tensores de forma geral (arrays) de forma mais eficiente que as ferramentas nativas da linguagem que usa listas.

In [21]:
#importando biblioteca
import numpy as np

Criando arrays usando a biblioteca Numpy:

In [22]:
#inicializando um array

#array unidimensional (vetor)
arrayU=np.array([1,2,3])
print("Array unidimensional(vetor): ")
print(arrayU,'\n')

#array bidimensional(matriz)
arrayB=np.array([[1,2,3],[4,5,6],[7,8,9]])
print("Array Bidimensional(matriz): ")
print(arrayB,'\n')
Array unidimensional(vetor): 
[1 2 3] 

Array Bidimensional(matriz): 
[[1 2 3]
 [4 5 6]
 [7 8 9]] 

Podemos criar arrays apenas com zeros com o método np.zeros(). No argumento do método colocamos o formato que o array assumirá:

In [23]:
#podemos criar um array apenas com zeros
arrayZeros = np.zeros(3)
print("Array de zeros: ",arrayZeros)

#Automaticamente, a função faz com que os números sejam do tipo float
print(type(arrayZeros[0]))

#basta fazer o seguinte para mudar o tipo da variável
arrayZeros = np.zeros(3,dtype=int)
print("Array de zeros Inteiros: ",arrayZeros)
Array de zeros:  [0. 0. 0.]
<class 'numpy.float64'>
Array de zeros Inteiros:  [0 0 0]

Podemos criar também arrays de números 1 com o método np.ones() e arrays vazios com o método np.empty():

In [24]:
#Array de 1s
arrayOne = np.ones([3,2])
print("array de 1: ")
print(arrayOne)

#Array vazio
arrayEmpty= np.empty(3) #inicializa com o endereço de memória da variável
print("array vazio: ")
print(arrayEmpty)
array de 1: 
[[1. 1.]
 [1. 1.]
 [1. 1.]]
array vazio: 
[0. 0. 0.]

Podemos também modificar um array já criado mudando seu formato (shape) como for necessário. Usar método np.shape():

In [25]:
#criando um array normal
arrayShape = np.array([1,2,3,4])
print("Array com formato inicial: ",arrayShape)
print("Dimensões do array: ",arrayShape.shape)
Array com formato inicial:  [1 2 3 4]
Dimensões do array:  (4,)

Modificando as dimensões originais:

In [26]:
arrayShape.shape =(2,2)
print("Array modificado: ")
print(arrayShape)
print("Dimensões do array: ",arrayShape.shape)
Array modificado: 
[[1 2]
 [3 4]]
Dimensões do array:  (2, 2)

É possível também realizar cortes de diversas maneiras no array unidimensional. Agora estudaremos como fazer isso:

In [27]:
#vamos criar array
arrayCortes = np.arange(1,10)

#podemos printar o array inteiro com [:]
print("Array inicial: ",arrayCortes[:])

#podemos printar o array ao contrário com [::-1]
print("Array ao contrário: ",arrayCortes[::-1])

#podemos cortar do meio pra frente
print("Array do meio pra frente: ",arrayCortes[5:])
Array inicial:  [1 2 3 4 5 6 7 8 9]
Array ao contrário:  [9 8 7 6 5 4 3 2 1]
Array do meio pra frente:  [6 7 8 9]

O mesmo vale para matrizes:

In [28]:
#criando matriz bidimensional
arrayCortes.shape= (3,3)
print("Matriz inicial: ")
print(arrayCortes)

#podemos imprimir só uma coluna específica
print("\n","Matriz Coluna: ")
print(arrayCortes[:,1]) 

#ou uma linha específica
print("\n","Matriz Linha: ")
print(arrayCortes[1,:])

#até mesmo um pedaço da matriz
print("\n","Matriz pedaço: ")
print(arrayCortes[1:,1:])
Matriz inicial: 
[[1 2 3]
 [4 5 6]
 [7 8 9]]

 Matriz Coluna: 
[2 5 8]

 Matriz Linha: 
[4 5 6]

 Matriz pedaço: 
[[5 6]
 [8 9]]

Agora vamos ver alguns métodos matemáticos do Numpy:

In [29]:
#Criando array
A = np.array([1,0,3,6,2,1,7,5,2])
print("Array Inicial: ",A)

#Ordenando o array
A.sort()
print("\n","Array ordenado: ",A)

#Soma elementos do array
print("\n","Soma dos elementos: ",A.sum())

#Média dos elementos do array
print("\n","Média dos elementos: ",A.mean())

#Maior elemento
print("\n","Array maior elemento: ",A.max())

#Transposta de um matriz
A.shape =(3,3)
print("\n","Transposta: ")
print(A.T)

#Matriz Inversa
print("\n","Inversa: ")
print(np.linalg.inv(A))
Array Inicial:  [1 0 3 6 2 1 7 5 2]

 Array ordenado:  [0 1 1 2 2 3 5 6 7]

 Soma dos elementos:  27

 Média dos elementos:  3.0

 Array maior elemento:  7

 Transposta: 
[[0 2 5]
 [1 2 6]
 [1 3 7]]

 Inversa: 
[[-1.33333333 -0.33333333  0.33333333]
 [ 0.33333333 -1.66666667  0.66666667]
 [ 0.66666667  1.66666667 -0.66666667]]

Com matrizes (array bidimensional) é a mesma coisa, com exceção da multiplicação - a veremos agora. Primeiramente, lembremos que para multiplicar duas matrizes (A e B) o número de colunas da matriz A tem que ser iqual ao número de linhas da Coluna B:

Podemos realizar operações algébricas de maneira muito simples:

In [30]:
A = np.array([1,2,3,4])
B=np.array([5,6,7,8])

A.shape=(2,2)
B.shape=(2,2)

print("Matriz A: ")
print(A, "\n")

print("Matriz B: ")
print(B, "\n")

#Matriz A X B
print("Matriz A X B : ")
print(A @ B, "\n")

#Array X matriz
print("Array [2,3] x A : ")
print( [2,3] @ A)
Matriz A: 
[[1 2]
 [3 4]] 

Matriz B: 
[[5 6]
 [7 8]] 

Matriz A X B : 
[[19 22]
 [43 50]] 

Array [2,3] x A : 
[11 16]

Pandas

Conheceremos agora uma das bibliotecas mais importantes e mais usadas para a manipulação e análises de dados no Python - o Pandas. O Pandas oferece diversas funções que facilitam a manipulação e visualização dos dados.

In [32]:
#Importando a biblioteca
import pandas as pd

Como dito anteriormente, o Pandas facilita a visualização de dados por causa da estrutura que ele é capaz de comportar as bases de dados - essa estrutura é chamada de DataFrame. Vamos criar um dicionário e depois transformá-lo em DataFrame para vermos sua estrutura:

In [36]:
dicionario =  {"País": ["Brasil", "Rússia", "Índia", "China", "África do Sul"],
       "Capital": ["Brasília", "Moscou", "Nova Deli", "Pequim", "Pretória"],
       "Área": [8.516, 17.10, 3.286, 9.597, 1.221],
       "População": [200.4, 143.5, 1252, 1357, 52.9]}
               
Brics = pd.DataFrame(dicionario)
print(Brics)
            País    Capital    Área  População
0         Brasil   Brasília   8.516      200.4
1         Rússia     Moscou  17.100      143.5
2          Índia  Nova Deli   3.286     1252.0
3          China     Pequim   9.597     1357.0
4  África do Sul   Pretória   1.221       52.9

Podemos checar as variáveis contidas nesse com a função ".columns":

In [34]:
#Variáveis
Brics.columns
Out[34]:
Index(['País', 'Capital', 'Área', 'População'], dtype='object')

Podemos ver mais ou menos o que está contido no data set utilizando a função ".head()". Ela retorna as cinco primeiras linhas da base de dados:

In [35]:
Brics.head()
Out[35]:
País Capital Área População
0 Brasil Brasília 8.516 200.4
1 Rússia Moscou 17.100 143.5
2 Índia Nova Deli 3.286 1252.0
3 China Pequim 9.597 1357.0
4 África do Sul Pretória 1.221 52.9

É possível também tirar algumas medidas descritivas das variáveis numéricas:

In [36]:
Brics.describe()
Out[36]:
Área População
count 5.000000 5.000000
mean 7.944000 601.160000
std 6.200557 645.278446
min 1.221000 52.900000
25% 3.286000 143.500000
50% 8.516000 200.400000
75% 9.597000 1252.000000
max 17.100000 1357.000000