Garimpagem de Dados

Aula 1 - Python Básico

Nulo

Em Python, o tipo None representa a falta de valor em uma variável


In [ ]:
a = None
if a is None:
    print('nulo')

Boolean

Booleanos são escritos com a primeira letra maiúscula


In [ ]:
a = True
b = False
c = True
print(a == b)
print(a == c)

Números

Em python, existem dois tipos básicos de números: Inteiros (int) e Ponto Flutuante (float)


In [ ]:
print(type(1))
print(type(1.2))

Ao dividir dois números (inteiros ou flutuantes), podemos fazer a divisão comum (/) ou divisão inteira (//), onde a última mantém apenas a parte inteira do resultado


In [ ]:
print("Divisao: ",1 / 2)
print("Divisao inteira: ",1 // 2)

Existe também o operador de potência, permitindo elevar um número ao outro. PS: como as raízes também são potências (porém, invertidas), podemos computá-las com o mesmo operador


In [ ]:
print(2 ** 3)
print(25 ** (1/2))

Python, assim como muitas linguagens, conta com um módulo que implementa diversas funções matemáticas (raíz, logaritmo, topo, piso, etc.


In [ ]:
import math
print(math.sqrt(2))
print(math.log(2))
print(math.ceil(2 ** 0.5))
print(math.floor(2 ** 0.5))

Python também conta um módulo de funções para operações randômicas


In [ ]:
import random
print(random.random())        # normalizado entre 0 e 1
print(random.randint(1,10))   # intervalo fechado

Strings

Em Python, trabalhar com strings é bem simples, uma vez que já existem diversas funções implementadas.

Para criar uma string em Python, basta colocar o conteúdo entre aspas, simples ou duplas (o tipo de aspas que começa a string é o mesmo tipo que irá finalizá-la)


In [ ]:
single_quoted_string = 'Data Science'
print(single_quoted_string, type(single_quoted_string))

In [ ]:
print(len(single_quoted_string))    # tamanho da string
print(single_quoted_string.upper()) # colocar caracteres em maiusculo
print(single_quoted_string.lower()) # colocar caracteres em minusculo

Podemos facilmente substituir a ocorrência de um caractere/substring utilizando o método replace


In [ ]:
str1 = 'Hoje_vai_chover_novamente.'.replace('_', ' ')
print(str1)

Outra operação interessante de limpeza de strings é o strip, o qual remove os espaços em branco no começo e no final da string


In [ ]:
print(' Hello '.strip())  # remove no começo e no final
print(' Hello '.lstrip()) # remove no começo
print(' Hello '.rstrip()) # remove no final

Também podemos criar string mais longas, com múltiplas linhas, utilizando um total de 6 aspas (3 para abrir e 3 para fechar)


In [ ]:
multi_line_string = """linha 1
linha 2
linha 3"""
print(multi_line_string)
print(repr(multi_line_string))

Quando temos strings que contém múltiplas informações e desejamos separá-la, podemos usar a função split, informando o caractere/substring a ser utilizado para dividir a string


In [ ]:
multi_line_string.split("\n")

Fato interessante: strings em python podem ser manipuladas com operadores de soma (concatenação) ou multiplicação (repetição)


In [ ]:
print("Big" + " " + "Data")
print('Repete ' * 5)

Existem algumas maneiras de interpolar strings, ou seja, injetar valores dentro dela


In [ ]:
# %d e %f indicam, respectivamente, que um número inteiro ou ponto flutuante será inserido
print("%d/%f/%d" % (2, 4.5, 6))
print("%s/%s/%s" % ('a', 2, False)) # %s indica que algo será inserido como string

Outra maneira de interpolar strings é usando o format


In [ ]:
print("{}/{}/{}".format(2, 4, 6))
print("{:2d}/{:2d}/{:2d}".format(2, 4, 16))
print("{:02d}/{:02d}/{:02d}".format(2, 4, 160))
print('{:.2f}'.format(99.8765))
print('{:.0f}'.format(99.8765))

Condições

Estruturas condicionais em Python seguem a mesma lógica de diversas outras linguagens. Uma diferença é que, para os casos em que encadeamos várias condições, para não escrevermos else if ... temos o operador elif


In [ ]:
valor = 99
if valor == 99:
    print('veloz')
elif value > 200:
    print('muito veloz')
else:
    print('lento')

Atribuição ternário

Python também conta com atribuição ternária


In [ ]:
x = 5
par_ou_impar = "par" if x % 2 == 0 else "impar"
print(par_ou_impar)

Laços / Loops

Em Python, a estrutura de repetição while funciona de maneira análoga a diversas outras linguagens:


In [ ]:
x = 0
while x < 5:
    print(x)
    x += 1

Entretanto, o for funciona iterando sobre uma coleção/sequência de valores. Existem diversas maneiras de fazer isso:


In [ ]:
# definindo um intervalo

for i in range(10): # de 0 a 9, pulando de 1 em 1
    print(i, end= " ")
    
print()

for i in range(5,10): # de 5 a 9, pulando de 1 em 1
    print(i, end= " ")
    
print()

for i in range(0,10,2): # de 0 a 9, pulando de 2 em 2
    print(i, end= " ")
    
print()

In [ ]:
# utilizando uma sequência pre-definida
a = [1, 3, 4, 5, 7]
for i in a:
    print(i)

In [ ]:
# a função enumerate retorna uma lista de pares (i,x), onde: 
# i é o índice (0, 1, 2, ...)
# x é o elemento da sequência original
a = [1, 3, 4, 5, 7]
for indice, valor in enumerate(a):
    print(indice, valor)

In [ ]:
# podemos também percorrer uma coleção mas não utilizar o valor daquele passo
for _ in range(5):
    print('oi')

In [ ]:
# existem também dois operadores dentro de um for:
# continue - encerra o passo atual e passa para o próximo
# break - encerra o laço
for x in range(10):
    if x == 3:
        continue
    if x == 5:
        break
    print(x)

Funções

Para definir uma função em python, basta utilizarmos a seguinte estrutua:

def nome_da_função (argumento1, argumento2, ...): 
    corpo da função

In [ ]:
def soma(a, b):
    return a + b

print(soma(3, 5))
print(soma('casa ', 'organizada'))

Manipulando Funções

Python pode ser considerada uma linguagem funcional. Uma das características do paradigma funcional é permitir que uma função seja manipulada como um valor ou variável, ou seja, podemos passar funções como argumentos para outras funções


In [ ]:
def f1():
    print("Function 1")
    
def f2():
    print("Function 2")
    
def chamar_funcao(f):
    f()
    
chamar_funcao(f1)
chamar_funcao(f2)

Existem também as funções anônimas (chamadas, em Python, de lambda). Uma função anônima é uma função que contém apenas a assinatura e o corpo, sem um nome definido. Em Python, elas recebem o nome de lambda pois elas são funções de um comando só (diferente de linguagens como Javascript e Scala, que permitem funções anônimas de múltiplas linhas).


In [ ]:
chamar_funcao(lambda : print("Lambda function"))

Data

Em Python, podemos manipular informações de data, hora e tempo utilizando o módulo datetime


In [ ]:
from datetime import datetime
import time

inicio = datetime.now() # obtém o timestamp do momento atual
print(inicio)
for i in range(2):
    time.sleep(1) # aplica um delay, em segundos
fim = datetime.now()
print(fim)
print("Tempo de execução: {}".format(fim - inicio))

Listas

Quando desejamos trabalhar com uma sequência de dados, podemos utilizar uma lista


In [ ]:
lista = [1, 2, 3, 4, 5]
print(lista)

Existem diversas maneiras de acessar os elementos de uma lista:


In [ ]:
lista[2] #elemento da lista

In [ ]:
lista[-1] # último elemento

In [ ]:
lista[1:3] #sublista

In [ ]:
lista[:3] # 3 primeiros elementos

In [ ]:
lista[-2:] # 2 últimos elementos

In [ ]:
lista[1:-1] # do segundo ao penúltimo elemento

O operador len pode ser utilizado para medir tamanhos de objetos com múltiplas informações (strings, lista, etc.)


In [ ]:
len(lista)

Podemos somar elementos de uma lista simplesmente usando a função sum


In [ ]:
sum(lista)

Podemos também consultar a pertinência de um elemento em uma lista utilizando o operador in


In [ ]:
print(10 in lista)
print(5 in lista)

Em Python, as listas são mutáveis, ou seja, ela pode ser modificada.


In [ ]:
lista.append(7) # adiciona elemento na lista
lista.append(6)
lista.append(7)
print(lista)

lista.remove(7) # remove o primeiro elemento cujo valor é 7
print(lista)

lista.extend([8, 9, -10]) #extende a lista com outra lista
lista

Por padrão, as variáveis em Python (quando apontando para tipos de dados mais complexos) são ponteiros, ou seja, elas são uma referência a um dado alocado na memória. Logo, quando salvamos o valor de uma variável A em uma variável B, estamos apenas dizendo que B aponta para a mesma informação que A


In [ ]:
lista2 = lista  # lista2 referencia lista
lista2[-1] = 10
print(lista)
print(lista2)

Embora a lista seja mutável, as operações de acesso aos elementos (com o operador [ ]) retornam novos elementos. Logo, podemos fazer uma cópia de uma lista da seguinte maneira


In [ ]:
lista3 = lista[:]  # lista3 é uma nova lista com o mesmo conteúdo de lista
lista3[-1] = -10
print(lista)
print(lista3)

Existem duas maneiras de se ordenar uma lista em Python: uma abordagem mutável (que altera a lista original) e uma imutável (que retorna uma nova lista ordenada)


In [ ]:
lista4 = [-4, 1, -2, 3]

print(sorted(lista4)) # ordena sem alterar a lista
print(sorted(lista4, reverse=True))
print(sorted(lista4, key=abs))
print(lista4)

lista4.sort() # altera a lista original
print(lista4)

O módulo random contém também um conjunto de funções para trabalharmos com listas. Podemos embaralhá-las, escolher um elemento aleatório ou obter uma amostra de tamanho n


In [ ]:
import random

a = ['a', 'casa', 'está', 'muito', 'bem', 'organizada']

random.shuffle(a) # mutável
print(a)
random.shuffle(a)
print(a)

random.choice(a) # com repetição

numeros = range(1, 100)
random.sample(numeros, 5) # sem repetição

A representação padrão de lista em string é uma sequência das strings de seu conteúdo, separado por ', ' e cercados por colchetes. O método join, de strings, existe para usar uma string como separador de uma lista, conforme o exemplo abaixo


In [ ]:
print(a)
print(' '.join(a))

OBS: se um elemento da lista não for uma string, o método join não funciona


In [ ]:
b = [1, 'a', 25, 'abc']
print(b)
print(' '.join(b))

Operações funcionais sobre listas

Existem algumas funções primitivas para operar sobre os elementos de uma lista. Duas delas são transformação (map) e filtragem (filter).

Transformação

O objetivo desta função é, como o próprio nome sugere, transformar os elementos de uma lista, gerando uma nova lista. Em termos mais matemáticos: dada uma função f(x) definida para todos os elementos de uma lista L [a1, a2, ..., an], será gerada uma nova lista L2 [b1, b2, ..., bn] tal que bi = f(ai).

Para realizar uma trnasformação, utilizamos a função map


In [ ]:
a = [1, 2, 3, 4, 5]

doubled_a = map(lambda x: 2*x, a)
doubled_a

O retorno do map é iterador, ou seja, os seus valores só existirão qdo forem chamados (seja em um for, outro map ou fazendo um cast para lista) e, uma vez que forem consumidos, o iterador fica vazio


In [ ]:
#descomente uma alternativa para checar seu funcionamento

doubled_a = map(lambda x: 2*x, a)

# for x in doubled_a:
#     print(x, end=" ")

# str_doubled_a = map(lambda x: str(x), doubled_a)
# print(" ".join(str_doubled_a))

# list(doubled_a)

Filtragem

Obviedades a parte, o objetivo dessa operação é gerar uma nova coleção apenas com os elementos que satisfaçam uma condição. De maneira mais matemática: dado um predicado p(x) definido para todos os elementos de uma lista L [a1, a2, ..., an], será gerada uma nova lista L2 [b1, b2, ..., bm] tal que bi $\in$ L e p(bi) é verdade.


In [ ]:
even_a = filter(lambda x: x%2 == 0, a)
even_a

Novamente temos um iterator como retorno. Podemos utilizar as mesmas abordagens do iteratoor apresentado no map


In [ ]:
#descomente uma alternativa para checar seu funcionamento

even_a = filter(lambda x: x%2 == 0, a)

# for x in even_a:
#     print(x, end=" ")

# str_even_a = map(lambda x: str(x), even_a)
# print(" ".join(str_even_a))

# list(even_a)

Combinando transformação e filtragem: Compressão de Listas

Uma maneira prática para combinar as operações de transformação e filtragem é utilizar uma compressão de lista. A anatomia da compressão de lista é a seguinte:

[f(x) for x in lista if p(x)]


In [ ]:
quadrados = [x * x for x in range(5)]
print(quadrados)

quadrados_dos_pares = [x * x for x in range(5) if x%2 == 0]
print(quadrados_dos_pares)

Tuplas

Tuplas são grupos ordenados de valores. Esse par é imutável e normalmente é utilizado para representar informações estruturadas (linha de um csv, tupla de um banco de dados, etc)


In [ ]:
tupla = (1, 2, 3, 4)
print(tupla)

Dicionários

Dicionários são pares de chave : valor, utilizados para representar um dado cujos valores tem uma semântica atribuída a ela.


In [ ]:
dicionario = { 'nome': 'Fulano', 'sobrenome': 'Da Silva' }
print(dicionario['nome'])
print(dicionario['sobrenome'])

Em Python, podemos acessar, separadamente, suas chaves e seus valores


In [ ]:
print(dicionario.keys())
print(dicionario.values())