Capítulo 5, Básico
DataFrame: criar e carregar dados
Os dados chegam de arquivos. Aqui você aprende a montar uma tabela à mão e, principalmente, a ler um CSV sem cair nas três armadilhas clássicas: o separador, a codificação e a coluna de índice que aparece do nada.
Criar um DataFrame
Os dois jeitos mais comuns espelham o modo como você já pensa nos dados. Um dicionário de listas tem uma lista por campo. Uma lista de dicionários tem um dicionário por linha. O resultado é o mesmo:
from pathlib import Path
import numpy as np
import pandas as pd
pd.set_option("display.width", 170)
pd.set_option("display.max_columns", 20)
Path("saida").mkdir(exist_ok=True)
por_coluna = pd.DataFrame({"nome": ["Ana", "Bruno"], "salario": [4500, 6500]})
por_linha = pd.DataFrame([{"nome": "Ana", "salario": 4500}, {"nome": "Bruno", "salario": 6500}])
print(por_coluna)
print(por_coluna.equals(por_linha))
print(pd.DataFrame(np.arange(6).reshape(3, 2), columns=["a", "b"]))
nome salario
0 Ana 4500
1 Bruno 6500
True
a b
0 0 1
1 2 3
2 4 5
Com um array do NumPy, você dá os nomes das colunas à parte, e o resto vem da forma do array.
Ler um CSV
O read_csv é a função que você vai usar o tempo todo. Os parâmetros que resolvem 90% dos casos reais:
| Parâmetro | Para que serve |
|---|---|
sep | O separador de colunas (, por padrão, mas arquivos brasileiros costumam usar ;) |
decimal | O separador decimal (. por padrão, e , em arquivos brasileiros) |
header e names | Em que linha estão os nomes das colunas, ou os nomes a usar se o arquivo não tiver |
usecols | Ler só algumas colunas, o que economiza memória |
dtype | Forçar o tipo de colunas específicas |
na_values | Quais textos significam "ausente" além dos padrões |
parse_dates | Converter colunas em datas já na leitura |
encoding | A codificação de caracteres (utf-8 por padrão) |
Um arquivo "à brasileira" (ponto e vírgula, vírgula decimal) lido do jeito certo:
import io
texto = "id;valor;data\n1;1,5;2025-01-10\n2;2,25;2025-02-11\n"
errado = pd.read_csv(io.StringIO(texto))
certo = pd.read_csv(io.StringIO(texto), sep=";", decimal=",", parse_dates=["data"])
print(errado.shape, certo.shape)
print(certo.dtypes)
print(certo["valor"].sum())
(2, 1) (2, 3)
id int64
valor float64
data datetime64[us]
dtype: object
3.75
Sem o sep, o arquivo inteiro vira uma coluna só (a forma (2, 1)), e o Pandas não reclama. Esse é o sinal de que o separador está errado. Para um arquivo sem linha de títulos, use header=None e dê os nomes:
sem_titulos = pd.read_csv(io.StringIO("1,Ana\n2,Bruno\n"), header=None, names=["id", "nome"])
print(sem_titulos)
id nome
0 1 Ana
1 2 Bruno
A coluna `Unnamed: 0`
Uma armadilha clássica: o to_csv grava o índice como uma coluna, por padrão. Ao reler, ele aparece como uma coluna sem nome:
por_coluna.to_csv("saida/com_indice.csv")
print(pd.read_csv("saida/com_indice.csv").columns.tolist())
por_coluna.to_csv("saida/sem_indice.csv", index=False)
print(pd.read_csv("saida/sem_indice.csv").columns.tolist())
['Unnamed: 0', 'nome', 'salario']
['nome', 'salario']
Use index=False, a não ser que o índice tenha informação que você queira guardar.
Codificação de caracteres
Um arquivo gravado em latin-1 (comum em exportações antigas) não é UTF-8, e a leitura padrão falha em qualquer acento. A correção é dizer a codificação:
Path("saida/antigo.csv").write_bytes("nome\nJoão\n".encode("latin-1"))
try:
pd.read_csv("saida/antigo.csv")
except UnicodeDecodeError as erro:
print("UnicodeDecodeError:", erro.reason)
print(pd.read_csv("saida/antigo.csv", encoding="latin-1")["nome"].tolist())
UnicodeDecodeError: invalid continuation byte
['João']
Outros formatos
O mesmo DataFrame lê e grava vários formatos. O CSV é universal, o JSON serve para APIs, o Excel para quem trabalha em planilhas, e o Parquet (capítulo 26) é o formato binário feito para análise:
por_coluna.to_json("saida/tabela.json", orient="records")
print(Path("saida/tabela.json").read_text(encoding="utf-8"))
print(pd.read_json("saida/tabela.json").equals(por_coluna))
por_coluna.to_excel("saida/tabela.xlsx", index=False)
print(pd.read_excel("saida/tabela.xlsx").equals(por_coluna))
[{"nome":"Ana","salario":4500},{"nome":"Bruno","salario":6500}]
True
True
O Excel exige o openpyxl, que está nas dependências deste curso.
O arquivo que não existe
O erro mais comum de iniciante: o caminho relativo não bate com a pasta de onde você executou. O Pandas diz exatamente o que procurou:
try:
pd.read_csv("dados/nao_existe.csv")
except FileNotFoundError as erro:
print("FileNotFoundError:", erro)
FileNotFoundError: [Errno 2] No such file or directory: 'dados/nao_existe.csv'
Execute os arquivos deste curso sempre a partir da raiz do repositório, onde a pasta dados/ está. Em dúvida, Path.cwd() mostra onde você está.
Exercício 1
Ler um arquivo brasileiro
Escreva ler_vendas(texto), que leia um CSV com ; e vírgula decimal, converta a coluna data em data e devolva o total da coluna valor. Teste com um texto de 3 linhas.