Analyser un Excel ou CSV avec une IA locale
Analyser un Excel ou CSV avec une IA locale ne demande pas de confier les additions au modèle. Ce guide répartit le travail : pandas lit le fichier et calcule, un second script recompte par une autre voie, puis un modèle servi par Ollama commente des résultats déjà contrôlés. Le code complet est fourni pour un CSV, avec les changements à prévoir pour un classeur Excel. Une section indique précisément ce qui a été vérifié sur le terrain et ce qui ne l'a pas été.
#Analyser un Excel ou CSV avec une IA locale : qui calcule, qui interprète
Coller un tableau dans une conversation est tentant : la réponse arrive en phrases, avec des totaux qui ont l'air justes. Mais un LLM génère du texte plausible et n'exécute pas de calcul quand il écrit un total. Rien, dans sa réponse, ne distingue un chiffre juste d'un chiffre faux. Et plus le fichier est long, plus il risque de déborder du contexte du modèle, parfois sans message clair.
La répartition proposée ici est simple : tout ce qui peut être recalculé à l'identique revient à un outil déterministe. Le même fichier et le même script donnent le même résultat, et ce résultat se contrôle. Le modèle garde ce qu'il sait faire : mettre des résultats en mots, signaler ce qui mérite un regard et proposer des questions.
- Lire et valider : pandas
- Colonnes présentes, cellules vides, montants numériques, dates au format attendu. Le script s'arrête au lieu de deviner.
- Calculer : pandas
- Totaux et parts par catégorie, écrits dans un fichier faits.json.
- Contrôler : Python seul
- Un second script relit le fichier source sans pandas et recompte. Tout écart bloque la suite.
- Interpréter : le modèle local
- Il reçoit uniquement faits.json, pas les lignes du fichier, et rédige un commentaire sans écrire un seul chiffre lui-même.
- Décider : vous
- Un total prouve une somme, pas une cause. Le commentaire du modèle reste une piste à examiner.
#Différence avec le tutoriel text-to-SQL
Profite de notre expérience et d’un parcours guidé pour créer ton assistant local et utiliser ton IA au quotidien.
- Espace en ligne à vie
- PDF + fichiers
- Remboursé 30 j
QuelLLM propose déjà un tutoriel text-to-SQL en local. Les deux guides empêchent le LLM d'inventer des résultats, mais ils ne lui confient pas le même rôle. Le choix dépend surtout de votre besoin : poser des questions variées, ou refaire un calcul connu.
- Text-to-SQL : rôle du modèle
- Il écrit la requête à partir d'une question en français. La base exécute ensuite ce code généré, d'où un rôle en lecture seule et une validation du SQL.
- Ce guide : rôle du modèle
- Il n'écrit aucun code et n'exécute rien. Vous écrivez le calcul une fois, puis le modèle commente son résultat.
- Text-to-SQL : quand le choisir
- Des données dans PostgreSQL ou MySQL, et des questions qui changent souvent.
- Ce guide : quand le choisir
- Un export ou un classeur, avec un calcul récurrent : bilan mensuel, ventilation par catégorie, suivi de dépenses.
- Limite de ce guide
- Une nouvelle question suppose de modifier le script. C'est le prix d'un calcul relu et reproductible.
#Prérequis et fichier d'exemple
- Ollama
- Le service doit répondre sur http://localhost:11434. Le guide d'installation est listé en fin de page.
- Python
- Un environnement virtuel avec Python 3.11 ou plus récent pour pandas 3.
- Un modèle
- L'exemple utilise qwen3.5:9b, environ 6,6 Go en Q4, soit une taille qui tient sur une RTX 3060 12GB. Il reprend le modèle du guide sur les sorties structurées ; la qualité de ses commentaires sur des données tabulaires n'a pas été évaluée ici.
- Un fichier factice
- Commencez avec le petit fichier ci-dessous. Vous pouvez vérifier ses totaux de tête, ce qui permet de voir si le montage fonctionne avant de lui donner de vraies données.
Ce format est celui qu'on rencontre souvent dans un export français : point-virgule entre les colonnes, virgule pour les décimales, date en jour/mois/année. Vérifiez le vôtre dans un éditeur de texte, pas dans Excel, qui reformate l'affichage.
#Étape 1 : calculer avec pandas
Le script décrit explicitement le format du fichier et préfère s'arrêter plutôt que produire un total douteux. La documentation de pandas consultée le 03/11/2026 (version 3.1.0) décrit les paramètres employés : sep pour le délimiteur, decimal pour les données européennes et on_bad_lines, dont la valeur par défaut « error » lève une erreur sur une ligne mal formée.
Deux choix méritent une explication. D'abord keep_default_na=False : la liste par défaut de pandas traite notamment NA, N/A et null comme des valeurs manquantes. Or une catégorie « NA » lue comme manquante pourrait disparaître d'un regroupement sans alerte. Ensuite, les doublons sont comptés mais pas retirés : deux achats identiques le même jour peuvent être légitimes, et cette décision vous revient.
Pour le fichier d'exemple, le résultat peut se calculer à la main : A = 100 + 25 = 125, B = 50, soit une somme de 175. Votre sortie doit correspondre aux valeurs suivantes.
#Étape 2 : recompter par une autre voie
Un calcul déterministe peut être faux de façon parfaitement reproductible : mauvais séparateur, colonne mal lue, filtre oublié. Ce second script ne fait donc pas confiance à pandas : il relit le fichier source avec les modules standard csv et decimal, recompte, puis compare. Il s'agit d'un contrôle de lecture et d'addition. Il ne dit pas si le calcul choisi répond à votre question.
Enchaînez les étapes avec && : si l'une échoue, la suivante ne démarre pas. Le modèle ne verra donc jamais de résultats refusés par le contrôle.
#Étape 3 : faire interpréter les résultats par le modèle
Le modèle reçoit le contenu de faits.json et répond selon un schéma JSON, avec le paramètre format d'Ollama expliqué dans le guide sur les sorties structurées. Ce schéma fixe la forme de la réponse, pas sa justesse. Le garde-fou utile est ailleurs : le modèle voit les valeurs pour pouvoir les comparer, mais doit les citer par leur clé. La fonction remplir rejette tout chiffre écrit directement ainsi que toute clé inventée.
Cette garde ne couvre pas tout. Elle ne détecte pas un nombre écrit en toutes lettres (« trois fois plus »), ni une conclusion fausse construite avec des valeurs justes, par exemple une cause présentée comme établie. Elle bloque les chiffres recopiés ou inventés, mais la relecture humaine reste nécessaire. Si une réponse est rejetée, ne la corrigez pas à la main : relancez ou reformulez la consigne, puis gardez une trace du rejet.
Envoyer uniquement des agrégats réduit aussi ce que le modèle peut lire : ni noms de clients, ni texte libre issu des lignes. Les libellés de catégories restent toutefois transmis et peuvent contenir un texte hostile si le fichier vient de l'extérieur. Ici, le modèle n'a pas d'outil et ne peut que produire du texte, ce qui limite les dégâts possibles sans supprimer le risque.
#Étape 4 : analyser un Excel, ce qui change
Pour un classeur .xlsx, seule la lecture change dans calculs.py : read_excel remplace read_csv, et les paramètres sep, decimal, encoding et on_bad_lines disparaissent. Ce bloc n'a pas été exécuté sur un fichier Excel : essayez-le d'abord sur un petit classeur dont vous connaissez les totaux.
- Moteur
- Dans la documentation 3.1.0, openpyxl reste utilisé par défaut pour .xlsx, mais ce choix est annoncé comme amené à passer à calamine dans une version future. Le nommer évite de changer de moteur à son insu lors d'une mise à jour.
- Feuille
- sheet_name vaut 0 par défaut, soit la première feuille. Avec None ou une liste, read_excel renvoie un dictionnaire de tableaux et non un seul : le script ci-dessus devrait alors être adapté.
- En-tête
- Le script suppose les noms de colonnes en première ligne. Si un titre précède le tableau, utilisez le paramètre header, ou mieux, nettoyez une copie du classeur.
- Dates
- Si la colonne contient de vraies dates Excel, le format jour/mois/année du script ne les concerne pas forcément. Vérifiez date_min et date_max dans faits.json.
- Lignes de total
- Une ligne « Total » en bas de feuille serait comptée comme une catégorie et doublerait la somme. Elle apparaît alors comme clé dans faits.json : relisez cette liste.
Le contrôle de l'étape 2 lit un CSV. Pour le garder, exportez la feuille depuis Excel (Enregistrer sous, format CSV UTF-8), puis lancez python controle.py export.csv. L'export passe par Excel et non par le moteur de lecture de pandas : c'est une autre voie de lecture, et les écarts sont justement ce qu'on cherche. Vérifiez le délimiteur : le script attend un point-virgule. Un montant exporté avec son format d'affichage, comme « 1 250,00 € », fera échouer le contrôle au lieu de passer inaperçu : retirez ce format dans la copie à exporter. Un format arrondi à l'affichage peut aussi créer un écart, à traiter de la même manière.
#Ce qui a été vérifié, et ce qui ne l'a pas été
Le 30/10/2026, un CSV factice a été lu et agrégé avec pandas 3.0.2 ; le contrôle a donné A=125 et B=50. C'est la seule preuve terrain de ce guide. Le fichier d'exemple ci-dessus reprend ces totaux pour rester lisible, sans que cela prouve le fonctionnement des scripts publiés.
- Vérifié
- Lecture et agrégation d'un CSV factice avec pandas 3.0.2, totaux A=125 et B=50 (30/10/2026).
- Relu, non exécuté
- Paramètres de read_csv et read_excel, dans la documentation pandas 3.1.0 consultée le 03/11/2026. Elle est plus récente que la version de l'essai : contrôlez votre version avec pip show pandas.
- Non vérifié
- Exécution complète de calculs.py, controle.py et interpreter.py dans leur forme publiée, et valeurs de faits.json en sortie : celles indiquées sont calculées à la main.
- Non vérifié
- Tout appel à un LLM : qualité des commentaires, respect de la consigne, fréquence des rejets. Aucun exemple de réponse n'est donc présenté.
- Non vérifié
- Toute lecture d'un fichier Excel, formules et export CSV compris.
Aucune durée, aucun taux d'erreur et aucune comparaison de modèles ne figurent ici, faute de mesure. Traitez ces scripts comme une base à essayer sur le fichier factice avant vos données. Le test utile consiste aussi à provoquer des échecs : modifiez un montant dans faits.json et le contrôle doit refuser le résultat ; donnez à remplir un texte contenant un chiffre et la réponse doit être rejetée.
#Dépannage
- « La colonne montant contient autre chose que des nombres »
- Un symbole monétaire, un texte ou un séparateur de milliers subsiste. Si le fichier utilise un séparateur de milliers, ajoutez le paramètre thousands à read_csv avec le bon caractère. Dans les fichiers français, il s'agit souvent d'une espace insécable, invisible à l'œil. Le contrôle devra ensuite retirer ce même caractère avant Decimal.
- Une seule colonne lue, ou colonnes absentes
- Le délimiteur n'est pas le bon. Ouvrez le fichier dans un éditeur de texte et adaptez sep dans calculs.py et delimiter dans controle.py.
- UnicodeDecodeError
- Le fichier n'est pas en UTF-8. Un ancien export Windows est souvent en cp1252 : changez encoding dans les deux scripts, puis vérifiez les accents dans les noms de catégories.
- Erreur sur le format de date
- Une date ne respecte pas jour/mois/année. Corrigez la donnée ou adaptez format. Évitez une conversion permissive, qui peut masquer une inversion du jour et du mois.
- Parts incohérentes
- Avec des remboursements ou des montants négatifs, une part en pourcentage peut dépasser 100 ou perdre son sens. Le script ne le signale pas : retirez ces parts de faits.json dans ce cas.
- Réponse rejetée à chaque essai
- Le modèle recopie les valeurs malgré la consigne. Reformulez-la ou essayez un autre modèle, sans retirer la garde.
- « Connection refused » côté Ollama
- Le service n'est pas démarré. Vérifiez avec ollama list et l'adresse http://localhost:11434.
#Pour aller plus loin
Ces guides prolongent le montage : le text-to-SQL si vos données sont en base, les sorties structurées pour le paramètre format, et les risques liés aux instructions cachées dans des fichiers venus de l'extérieur.
Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.