Excel e documentos de trabalho

Crie um resumo mensal com groupby do pandas e verifique os totais

Resuma dados CSV em nível de pedido por mês com pandas e depois reconcilie as contagens, unidades e valores agrupados com a fonte. Um pequeno exemplo sintético facilita a verificação manual de todos os resultados esperados.

Ver o sumário

A tradução foi feita com IA. Confira o código, as unidades e os valores junto com o original. A revisão por falantes nativos de cada idioma ainda não foi concluída. English

Para quem éEste guia é voltado a pessoas que precisam de um resumo CSV mensal repetível e querem verificações explícitas de que a agregação não perdeu registros.

Preparação
  • Python 3.12 e um comando de terminal que inicie essa versão.
  • pandas instalado com python -m pip install pandas.
  • Uma pasta de trabalho em que o script possa criar uma nova pasta dentro de outputs.
  • O CSV de origem deve conter as colunas order_id, order_date, units e amount.

01Defina as medidas mensais

Este exemplo produz uma linha por calendar month com três medidas: order count, total units e total amount. A fonte sintética usa uma linha por order, portanto contar linhas equivale a contar orders neste dataset específico.

A etapa importante é a reconciliation. Depois do groupby, os valores mensais são somados novamente e comparados com os source totals. Um summary pode parecer razoável mesmo quando rows foram acidentalmente filtradas, duplicadas ou descartadas.

02Crie o CSV sintético

O dataset a seguir é sintético e foi criado especificamente para este artigo. Salve-o como monthly_orders.csv. Ele contém sete orders entre janeiro, fevereiro e março de 2026.

csv
order_id,order_date,team,units,amount
O001,2026-01-05,North,2,40
O002,2026-01-20,South,3,60
O003,2026-02-02,North,1,25
O004,2026-02-18,South,4,100
O005,2026-02-28,North,2,50
O006,2026-03-03,South,5,125
O007,2026-03-15,North,1,30

Os source totals são simples o suficiente para serem verificados manualmente. Há 7 orders. Units totalizam 18: 2 + 3 + 1 + 4 + 2 + 5 + 1. Amount totaliza 430: 40 + 60 + 25 + 100 + 50 + 125 + 30.

MedidaTotal da fonte
Orders7
Units18
Amount430

03Calcule manualmente as linhas mensais esperadas

Janeiro contém O001 e O002. Fevereiro contém O003, O004 e O005. Março contém O006 e O007. Somar cada group fornece a tabela mensal esperada.

monthordersunitsamount
2026-0125100
2026-0237175
2026-0326155

Os monthly totals reconciliam com a fonte: 2 + 3 + 2 = 7 orders, 5 + 7 + 6 = 18 units e 100 + 175 + 155 = 430 amount.

04Crie e verifique o resumo com pandas

Salve o script a seguir como monthly_summary_pandas.py. Ele valida as required columns, rejeita order IDs ausentes ou duplicados, interpreta datas com um único formato explícito, converte numeric columns, agrupa por month, reconcilia os totals e grava o resultado somente depois que essas verificações passam.

python
from pathlib import Path
import pandas as pd

SOURCE = Path("monthly_orders.csv")
OUTPUT_DIR = Path("outputs") / "monthly_summary_result"
OUTPUT = OUTPUT_DIR / "monthly_summary.csv"
REQUIRED = ["order_id", "order_date", "units", "amount"]


def main() -> None:
    if not SOURCE.is_file():
        raise FileNotFoundError(f"Source CSV not found: {SOURCE}")
    if OUTPUT_DIR.exists():
        raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")

    data = pd.read_csv(SOURCE, dtype={"order_id": "string"})

    missing = [name for name in REQUIRED if name not in data.columns]
    if missing:
        raise ValueError(f"Missing required columns: {missing}")
    if data.empty:
        raise ValueError("Source CSV contains no data rows.")
    if data[REQUIRED].isna().any().any():
        raise ValueError("A required field contains a missing value.")
    if data["order_id"].str.strip().eq("").any():
        raise ValueError("order_id contains a blank value.")
    if data["order_id"].duplicated().any():
        raise ValueError("Duplicate order_id found.")

    data["order_date"] = pd.to_datetime(
        data["order_date"], format="%Y-%m-%d", errors="raise"
    )
    data["units"] = pd.to_numeric(data["units"], errors="raise")
    data["amount"] = pd.to_numeric(data["amount"], errors="raise")
    data["month"] = data["order_date"].dt.to_period("M").astype(str)

    summary = (
        data.groupby("month", as_index=False, sort=True)
        .agg(
            orders=("order_id", "count"),
            units=("units", "sum"),
            amount=("amount", "sum"),
        )
    )

    source_totals = (len(data), data["units"].sum(), data["amount"].sum())
    summary_totals = (
        summary["orders"].sum(),
        summary["units"].sum(),
        summary["amount"].sum(),
    )
    if summary_totals != source_totals:
        raise RuntimeError("Monthly totals do not reconcile with the source.")

    OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_DIR.mkdir()
    summary.to_csv(OUTPUT, index=False)

    check = pd.read_csv(OUTPUT)
    if check.to_dict("records") != summary.to_dict("records"):
        raise RuntimeError("Saved CSV does not match the calculated summary.")

    print(f"Source rows: {len(data)}.")
    print(f"Months: {len(summary)}.")
    print(f"Verified totals: units={source_totals[1]}, amount={source_totals[2]}.")
    print(f"Output: {OUTPUT.as_posix()}")


if __name__ == "__main__":
    main()
text
python monthly_summary_pandas.py

05Compare a saída esperada

A saída deve conter três data rows ordenadas por month. O conteúdo esperado do CSV é mostrado abaixo.

csv
month,orders,units,amount
2026-01,2,5,100
2026-02,3,7,175
2026-03,2,6,155

A saída esperada do console abaixo foi derivada manualmente a partir dos dados sintéticos e do código. Não é um execution log capturado.

text
Source rows: 7.
Months: 3.
Verified totals: units=18, amount=430.
Output: outputs/monthly_summary_result/monthly_summary.csv

06Reconcilie o resultado e reconheça erros comuns

  1. Conte as source rows: 7.
  2. Some os monthly orders: 2 + 3 + 2 = 7.
  3. Some as monthly units: 5 + 7 + 6 = 18.
  4. Some o monthly amount: 100 + 175 + 155 = 430.
  5. Confirme que a saída contém exatamente 2026-01, 2026-02 e 2026-03.
  6. Execute o script novamente sem alterar OUTPUT_DIR. Ele deve parar com FileExistsError em vez de substituir o resultado existente.
SintomaO que verificar
ModuleNotFoundError for pandasInstale pandas no mesmo Python environment com python -m pip install pandas.
Missing required columnsVerifique o CSV header antes de alterar o expected schema.
Date parsing errorConfirme que todo order_date usa YYYY-MM-DD.
Numeric conversion errorInspecione units e amount para text, currency symbols ou separators que exijam uma cleanup rule explícita.
Duplicate order_id foundDetermine se o ID repetido é um accidental duplicate ou representa um data model diferente.
FileExistsErrorRevise o resultado anterior e use uma nova output folder em vez de sobrescrevê-lo.

Grand totals correspondentes não provam que todos os months estão corretos, porque dois erros mensais podem se compensar. Para reports importantes, inspecione também algumas source rows conhecidas e month-level subtotals.

07Entenda os limites

O exemplo pressupõe uma linha por order e amounts inteiros. Se um order ocupar várias line-item rows, use uma rule como order_id.nunique() em vez de row count. Monetary data reais também podem exigir fixed-point integer units ou processamento baseado em Decimal em vez de ordinary floating-point arithmetic.

Month é derivado diretamente de uma date sem time-zone handling. Se dados reais contiverem timestamps de várias zones, defina a business time zone antes do grouping. Refunds, cancellations, filters e missing records também precisam de business rules explícitas; arithmetic reconciliation sozinha não consegue determinar se essas rows pertencem ao report.

Registro de execução e verificação

2026-09-20 · exemplo verificado manualmente · alvo: Python 3.12 · pandas necessário · sem execução

  • Foram contados manualmente 7 source records entre janeiro, fevereiro e março de 2026.
  • Foram calculados manualmente source totals de 18 units e 430 amount.
  • Foi calculado manualmente janeiro como 2 orders, 5 units, 100 amount; fevereiro como 3 orders, 7 units, 175 amount; e março como 2 orders, 6 units, 155 amount.
  • Os monthly totals foram reconciliados manualmente de volta para 7 orders, 18 units e 430 amount.
  • O script foi inspecionado quanto a required-column checks, duplicate IDs, explicit date parsing, numeric conversion, groupby aggregation, reconciliation, saved-file comparison e output collision protection.
  • O CSV esperado e a saída do console foram derivados manualmente.
Limites da verificação
  • O código não foi executado pelo autor desta resposta; o comportamento do pandas e as filesystem writes não foram testados aqui.
  • Decimal currency, time zones, refunds, cancellations, line-item order data e very large files não foram testados.
  • As URLs da documentação oficial foram fornecidas com base em locais de documentação conhecidos, mas não foram verificadas ao vivo.

Princípios de redação e verificação de todo o site

Fontes de referência

As explicações e os exemplos são de elaboração própria. Os comportamentos e conceitos relacionados podem ser consultados nas fontes oficiais abaixo.