Ogni filiale manda il proprio file di vendite, ogni tecnico compila il proprio foglio ore, ogni mese il gestionale esporta un file nuovo. A fine trimestre qualcuno deve aprirli uno per uno e copiare tutto in un unico foglio. È un lavoro lungo e soggetto a errori: una riga saltata, un file dimenticato, una colonna incollata nel posto sbagliato. La libreria pandas permette di fare il consolidamento in pochi secondi e, soprattutto, nello stesso modo ogni volta.
L'idea di base
pandas rappresenta una tabella come un DataFrame. Il consolidamento consiste in tre passi: leggere ogni file in un DataFrame, metterli in una lista, concatenarli con pd.concat.
pip install pandas openpyxl
from pathlib import Path
import pandas as pd
cartella = Path("C:/Dati/Vendite filiali")
tabelle = []
for file in sorted(cartella.glob("*.xlsx")):
df = pd.read_excel(file)
df["file_origine"] = file.name
tabelle.append(df)
totale = pd.concat(tabelle, ignore_index=True)
totale.to_excel("vendite_consolidate.xlsx", index=False)
print(len(tabelle), "file,", len(totale), "righe")
ignore_index=True rinumera le righe da capo, evitando indici duplicati. Il pacchetto openpyxl è necessario perché pandas lo usa per leggere e scrivere i file .xlsx.
Sapere sempre da dove arriva ogni riga
La colonna file_origine aggiunta nell'esempio è il dettaglio più utile di tutto lo script. Quando una cifra nel consolidato sembra sbagliata, permette di risalire subito al file che l'ha prodotta. Se il nome del file contiene informazioni, come vendite_Torino_2025-03.xlsx, si possono anche estrarre in colonne separate:
filiale, periodo = file.stem.split("_")[1:3]
df["filiale"] = filiale
df["periodo"] = periodo
Questo funziona solo se i nomi seguono una convenzione rigorosa, ed è un buon motivo per concordarla con chi invia i file.
Quando le colonne non coincidono
Nella realtà i file non sono mai perfettamente uguali. Qualcuno scrive «Importo», qualcun altro «Importo €», un terzo aggiunge una colonna di note. pd.concat allinea le colonne per nome: quelle con nomi diversi diventano colonne separate, piene di valori vuoti per i file che non le hanno. Il rimedio è normalizzare i nomi prima di concatenare:
rinomina = {"importo €": "importo", "imp.": "importo", "data doc": "data"}
df.columns = df.columns.str.strip().str.lower()
df = df.rename(columns=rinomina)
df = df[["data", "cliente", "importo"]]
L'ultima riga tiene solo le colonne attese, nell'ordine voluto. Se una manca, pandas solleva un errore che indica quale: meglio un errore chiaro che un consolidato incompleto.
Intestazioni non in prima riga e fogli multipli
Molti file hanno qualche riga di titolo prima della tabella vera. Il parametro skiprows le salta: pd.read_excel(file, skiprows=3) inizia a leggere dalla quarta riga. Se il dato si trova in un foglio specifico, si indica con sheet_name="Vendite". Con sheet_name=None si ottengono invece tutti i fogli del file sotto forma di dizionario, utile quando ogni foglio rappresenta un mese.
Anche i CSV
Lo stesso schema vale per i CSV, con qualche attenzione in più sul formato italiano:
df = pd.read_csv(file, sep=";", decimal=",", thousands=".", encoding="utf-8")
Senza decimal="," l'importo 1.234,56 verrebbe letto come testo. Se il file proviene da un vecchio gestionale e le lettere accentate appaiono come simboli strani, provate encoding="cp1252", la codifica storica di Windows.
Duplicati e controlli
Capita che lo stesso file venga inviato due volte con nomi diversi, o che due esportazioni si sovrappongano di qualche giorno. Prima di consegnare il consolidato conviene cercare i duplicati:
doppi = totale.duplicated(subset=["data", "cliente", "importo"], keep=False)
print(doppi.sum(), "righe sospette")
totale[doppi].to_excel("da_verificare.xlsx", index=False)
Non conviene eliminarli automaticamente alla cieca: due vendite identiche nello stesso giorno possono essere reali. Salvarle in un file a parte permette a una persona di decidere. Nel mio lavoro aggiungo anche un riepilogo per file, con numero di righe e somma degli importi, da confrontare con i totali che ogni mittente dichiara.
riepilogo = totale.groupby("file_origine")["importo"].agg(["count", "sum"])
print(riepilogo)
| Problema | Soluzione in pandas |
|---|---|
| Nomi di colonna diversi | str.lower(), rename() |
| Righe di titolo | skiprows |
| Foglio specifico | sheet_name |
| Numeri in formato italiano | decimal=",", thousands="." |
| Duplicati | duplicated() |
| Verifica per file | groupby().agg() |
In sintesi
pd.concatunisce in un colpo i DataFrame letti da tutti i file di una cartella.- Aggiungete sempre una colonna con il nome del file di origine.
- Normalizzate i nomi delle colonne e selezionate solo quelle attese.
- Per i CSV italiani indicate separatore, decimali e codifica.
- Segnalate i duplicati invece di eliminarli e confrontate i totali per file.