Curso de Python / Limpar e analisar tabelas com pandas
pandas representa dados tabulares como um DataFrame e oferece operações de seleção, conversão e agregação. Separe leitura, validação, cálculo e gravação, mantendo visível quais valores foram rejeitados para interpretar corretamente os totais.
Escolher os tipos antes de analisar os dados
Um DataFrame é uma estrutura de linhas e colunas; uma Series representa uma sequência unidimensional, como uma coluna da tabela. A inferência automática de um CSV pode contrariar o contrato da aplicação: um ID como 0012 precisa ser lido como texto se os zeros iniciais forem significativos.
O exemplo lê todas as colunas como strings e só depois converte amount para um tipo numérico. pandas é um pacote externo, não um módulo da biblioteca padrão. Selecione o ambiente virtual do projeto e instale uma versão compatível com seu Python e sistema:
python -m pip install pandas
Confirme que o terminal usa o mesmo ambiente na instalação e na execução. Se ocorrer ModuleNotFoundError, verifique o interpretador selecionado antes de repetir a instalação em outro lugar. A documentação de pandas.read_csv detalha tipos de colunas e opções de leitura.
Executar uma validação e um resumo completos
Salve o programa abaixo como pandas_demo.py, em UTF-8, em uma pasta de prática. Execute python pandas_demo.py com o ambiente selecionado. No macOS ou Ubuntu, fora de um ambiente virtual, use python3 se esse for o comando do interpretador.
from io import StringIO
import pandas as pd
raw = "id,category,amount\ne1,food,3500\ne2,food,8000\ne3,transport,2500\ne4,food,bad\n"
df = pd.read_csv(StringIO(raw), dtype="string", keep_default_na=False)
amounts = pd.to_numeric(df["amount"], errors="coerce")
valid = amounts.notna() & (amounts >= 0) & (amounts % 1 == 0)
clean = df.loc[valid].copy()
clean["amount"] = amounts.loc[valid].astype("int64")
report = clean.groupby("category", as_index=False, sort=True)["amount"].sum()
print("accepted:", len(clean), "rejected:", int((~valid).sum()))
for row in report.itertuples(index=False):
print(row.category, row.amount)
Resultado esperado:
accepted: 3 rejected: 1
food 11500
transport 2500
StringIO apresenta o texto da amostra como um arquivo em memória. keep_default_na=False evita transformar automaticamente certas strings em valores ausentes durante essa leitura. A conversão seguinte marca bad como ausente; a máscara valid exige um número presente, não negativo e sem parte fracionária.
df.loc[valid] seleciona os registros aceitos, e copy() cria uma tabela separada para receber a coluna convertida. O agrupamento soma as quantias por categoria e ordena as chaves. as_index=False mantém a categoria como coluna no relatório; itertuples(index=False) permite percorrer suas linhas sem incluir o índice.
Interpretar coerção, ausências e o alcance da máscara
errors="coerce" em to_numeric transforma falhas de conversão em valores ausentes. Isso permite identificar a rejeição, não tratá-la como se o registro nunca tivesse existido. Compare len(clean), a contagem de rejeitados e a quantidade original de linhas. A referência de to_numeric também alerta sobre limites e precisão em valores muito grandes.
O critério do exemplo é numérico: uma representação como 3.0 pode ser aceita porque seu valor não tem parte fracionária, enquanto 3.5 é excluído. Isso difere da regra textual de aceitar somente algarismos usada no projeto CSV com a biblioteca padrão. Escolha deliberadamente qual contrato atende à sua entrada.
Esta prática pressupõe quantias pequenas e resultados que cabem em int64. Grandes inteiros, somas muito grandes e valores monetários decimais exatos exigem uma política própria para precisão, intervalo e unidade. A conversão e o tipo escolhido não oferecem uma garantia universal de exatidão para qualquer quantia.
A máscara verifica somente o valor numérico: ela não valida ID vazio, ID repetido ou categoria ausente. Ao ler um arquivo real, substitua a criação de df por pd.read_csv("expenses-input.csv", dtype={"id":"string", "category":"string", "amount":"string"}, keep_default_na=False) para manter a mesma política de leitura. Adicione as regras de identidade e categoria de que a aplicação necessita. Se optar pelo reconhecimento padrão de valores ausentes, reavalie também o agrupamento: categorias ausentes podem não aparecer nos grupos padrão.
Para investigar os descartes, retenha separadamente os registros de df.loc[~valid].copy() antes de distribuir o relatório. Não preencha quantias ausentes com zero sem uma regra explícita; “quantia desconhecida” e “quantia igual a zero” têm significados diferentes.
Gravar e reconciliar o relatório
Acrescente esta linha ao final de pandas_demo.py, depois de criar e imprimir o relatório:
report.to_csv("category-report.csv", index=False, encoding="utf-8")
Use uma pasta ou caminho de saída novo: esta chamada substitui um arquivo existente com o mesmo nome. index=False evita gravar o índice do DataFrame como uma coluna extra; encoding="utf-8" define a codificação textual. Veja as opções de DataFrame.to_csv.
Abra category-report.csv e confira o cabeçalho category,amount e os dois totais: food 11500 e transport 2500. O total dos registros aceitos e a soma do relatório devem ser 14000. Conferir somente uma soma correta não revela por si só se uma categoria ficou ausente ou um ID foi duplicado.
- Troque
badpor0. Devem aparecer quatro aceitos e nenhum rejeitado, mantendo o total 14000. - Troque o mesmo campo por
-1. Ele deve voltar a ser rejeitado: três aceitos e um rejeitado. - Experimente
3.5para observar a condição de parte fracionária e3.0para compará-la com um valor inteiro representado em decimal. - Restaure
bade confirme novamente a saída original e a relação três aceitos + um rejeitado = quatro registros de entrada. Faça as gravações de teste em um caminho descartável.




