Analizar un Excel o CSV con una IA locale
Analizar un Excel o CSV con una IA local no exige confiarle las sumas al modelo. Esta guía reparte el trabajo: pandas lee el archivo y calcula, un segundo script vuelve a contar por otra vía y, después, un modelo servido por Ollama comenta unos resultados ya verificados. Se incluye el código completo para un CSV, con los cambios necesarios para un libro de Excel. Una sección indica con precisión qué se ha comprobado sobre el terreno y qué no.
#Analizar un Excel o CSV con una IA local: quién calcula, quién interpreta
Pegar una tabla en una conversación es tentador: la respuesta llega en frases, con totales que parecen correctos. Pero un LLM genera texto plausible y no ejecuta ningún cálculo cuando escribe un total. Nada en su respuesta distingue una cifra correcta de una incorrecta. Y cuanto más largo es el archivo, más riesgo hay de que desborde el contexto del modelo, a veces sin ningún mensaje claro.
El reparto que se propone aquí es sencillo: todo lo que se pueda recalcular de forma idéntica corresponde a una herramienta determinista. El mismo archivo y el mismo script dan el mismo resultado, y ese resultado se puede comprobar. El modelo se queda con lo que sabe hacer: expresar los resultados con palabras, señalar lo que merece una revisión y proponer preguntas.
- Leer y validar: pandas
- Columnas presentes, celdas vacías, importes numéricos, fechas en el formato esperado. El script se detiene en lugar de adivinar.
- Calcular: pandas
- Totales y porcentajes por categoría, escritos en un archivo faits.json.
- Comprobar: Python solo
- Un segundo script vuelve a leer el archivo de origen sin pandas y recuenta. Cualquier diferencia bloquea lo que sigue.
- Interpretar: el modelo local
- Recibe únicamente faits.json, no las filas del archivo, y redacta un comentario sin escribir él mismo ni una sola cifra.
- Decidir: tú
- Un total demuestra una suma, no una causa. El comentario del modelo sigue siendo una pista que hay que examinar.
#Diferencia con el tutorial de text-to-SQL
Aprovecha nuestra experiencia y un recorrido guiado para crear tu asistente local y usar tu IA en el día a día.
- Espacio en línea de por vida
- PDF + archivos
- Reembolsado 30 d
QuelLLM ya ofrece un tutorial de text-to-SQL en local. Las dos guías impiden que el LLM invente resultados, pero no le asignan el mismo papel. La elección depende sobre todo de lo que necesites: hacer preguntas variadas o repetir un cálculo conocido.
- Text-to-SQL: papel del modelo
- Escribe la consulta a partir de una pregunta en francés. Después, la base de datos ejecuta ese código generado; de ahí la necesidad de un rol de solo lectura y de una validación del SQL.
- Esta guía: papel del modelo
- No escribe código ni ejecuta nada. Tú escribes el cálculo una vez y luego el modelo comenta su resultado.
- Text-to-SQL: cuándo elegirlo
- Datos en PostgreSQL o MySQL, y preguntas que cambian a menudo.
- Esta guía: cuándo elegirla
- Una exportación o un libro, con un cálculo recurrente: balance mensual, desglose por categoría, seguimiento de gastos.
- Límite de esta guía
- Una pregunta nueva implica modificar el script. Es el precio de un cálculo revisado y reproducible.
#Requisitos previos y archivo de ejemplo
- Ollama
- El servicio debe responder en http://localhost:11434. La guía de instalación aparece al final de la página.
- Python
- Un entorno virtual con Python 3.11 o posterior para pandas 3.
- Un modelo
- El ejemplo usa qwen3.5:9b, unos 6,6 GB en Q4, un tamaño que cabe en una RTX 3060 12GB. Retoma el modelo de la guía sobre salidas estructuradas; aquí no se ha evaluado la calidad de sus comentarios sobre datos tabulares.
- Un archivo ficticio
- Empieza con el pequeño archivo que aparece a continuación. Puedes comprobar sus totales mentalmente, lo que te permite ver si el montaje funciona antes de darle datos reales.
Este es el formato que suele encontrarse en una exportación francesa: punto y coma entre columnas, coma para los decimales y fecha en día/mes/año. Comprueba el tuyo en un editor de texto, no en Excel, que cambia el formato de lo que se muestra.
#Paso 1: calcular con pandas
El script describe explícitamente el formato del archivo y prefiere detenerse antes que producir un total dudoso. La documentación de pandas consultada el 03/11/2026 (versión 3.1.0) describe los parámetros empleados: sep para el delimitador, decimal para los datos europeos y on_bad_lines, cuyo valor predeterminado «error» genera un error ante una línea mal formada.
Dos decisiones merecen una explicación. Primero, keep_default_na=False: la lista predeterminada de pandas trata, entre otros, NA, N/A y null como valores faltantes. Y una categoría «NA» leída como faltante podría desaparecer de una agrupación sin ninguna alerta. Segundo, los duplicados se cuentan, pero no se eliminan: dos compras idénticas el mismo día pueden ser legítimas, y esa decisión te corresponde a ti.
Para el archivo de ejemplo, el resultado se puede calcular a mano: A = 100 + 25 = 125, B = 50, es decir, una suma de 175. Tu salida debe coincidir con los siguientes valores.
#Paso 2: volver a contar por otra vía
Un cálculo determinista puede ser erróneo de forma perfectamente reproducible: separador incorrecto, columna mal leída, filtro olvidado. Por eso, este segundo script no se fía de pandas: vuelve a leer el archivo de origen con los módulos estándar csv y decimal, vuelve a contar y luego compara. Se trata de un control de lectura y de suma. No indica si el cálculo elegido responde a tu pregunta.
Encadena los pasos con &&: si uno falla, el siguiente no se inicia. Así, el modelo nunca verá resultados rechazados por el control.
#Paso 3: hacer que el modelo interprete los resultados
El modelo recibe el contenido de faits.json y responde según un esquema JSON, con el parámetro format de Ollama explicado en la guía sobre salidas estructuradas. Este esquema fija la forma de la respuesta, no su exactitud. La salvaguarda útil está en otra parte: el modelo ve los valores para poder compararlos, pero debe citarlos por su clave. La función remplir rechaza cualquier cifra escrita directamente, así como cualquier clave inventada.
Esta protección no lo cubre todo. No detecta un número escrito con letras («tres veces más») ni una conclusión falsa construida con valores correctos, por ejemplo una causa presentada como demostrada. Bloquea las cifras copiadas o inventadas, pero la revisión humana sigue siendo necesaria. Si se rechaza una respuesta, no la corrijas a mano: vuelve a ejecutar o reformula la instrucción y deja constancia del rechazo.
Enviar solo agregados también reduce lo que el modelo puede leer: ni nombres de clientes ni texto libre procedente de las filas. Sin embargo, las etiquetas de categoría se siguen transmitiendo y pueden contener texto hostil si el archivo viene del exterior. Aquí el modelo no tiene herramientas y solo puede producir texto, lo que limita los daños posibles sin eliminar el riesgo.
#Paso 4: analizar un Excel, qué cambia
Para un libro .xlsx, solo cambia la lectura en calculs.py: read_excel reemplaza a read_csv, y los parámetros sep, decimal, encoding y on_bad_lines desaparecen. Este bloque no se ha ejecutado con un archivo Excel: pruébalo primero con un libro pequeño cuyos totales conozcas.
- Motor
- En la documentación 3.1.0, openpyxl sigue usándose por defecto para .xlsx, pero se anuncia que esta opción pasará a ser calamine en una versión futura. Indicarlo por su nombre evita cambiar de motor sin que te des cuenta durante una actualización.
- Feuille
- sheet_name vale 0 de forma predeterminada, es decir, la primera hoja. Con None o una lista, read_excel devuelve un diccionario de tablas y no una sola: en ese caso, habría que adaptar el script anterior.
- Encabezado
- El script da por hecho que los nombres de las columnas están en la primera fila. Si hay un título antes de la tabla, usa el parámetro header o, mejor aún, limpia una copia del libro.
- Dates
- Si la columna contiene fechas reales de Excel, el formato día/mes/año del script no tiene por qué aplicarse a ellas. Comprueba date_min y date_max en faits.json.
- Filas de total
- Una fila «Total» al final de la hoja se contaría como una categoría y duplicaría la suma. En ese caso aparece como clave en faits.json: revisa esa lista.
El control del paso 2 lee un CSV. Para conservarlo, exporta la hoja desde Excel (Guardar como, formato CSV UTF-8) y luego ejecuta python controle.py export.csv. La exportación pasa por Excel y no por el motor de lectura de pandas: es otra vía de lectura, y las diferencias son justo lo que se busca. Comprueba el delimitador: el script espera un punto y coma. Un importe exportado con su formato de visualización, como «1 250,00 €», hará que el control falle en lugar de pasar inadvertido: quita ese formato en la copia que vayas a exportar. Un formato redondeado en pantalla también puede crear una diferencia, que se trata de la misma manera.
#Lo que se verificó y lo que no
El 30/10/2026 se leyó y agregó un CSV ficticio con pandas 3.0.2; el control dio A=125 y B=50. Es la única prueba sobre el terreno de esta guía. El archivo de ejemplo anterior retoma esos totales para que resulte legible, sin que eso demuestre el funcionamiento de los scripts publicados.
- Verificado
- Lectura y agregación de un CSV ficticio con pandas 3.0.2, totales A=125 y B=50 (30/10/2026).
- Revisado, no ejecutado
- Parámetros de read_csv y read_excel, en la documentación de pandas 3.1.0 consultada el 03/11/2026. Es más reciente que la versión de la prueba: comprueba tu versión con pip show pandas.
- No verificado
- Ejecución completa de calculs.py, controle.py e interpreter.py en su forma publicada, y valores de faits.json en la salida: los indicados están calculados a mano.
- No verificado
- Cualquier llamada a un LLM: calidad de los comentarios, cumplimiento de la instrucción, frecuencia de los rechazos. Por eso no se presenta ningún ejemplo de respuesta.
- No verificado
- Cualquier lectura de un archivo Excel, incluidas las fórmulas y la exportación a CSV.
Aquí no figura ninguna duración, ninguna tasa de error ni ninguna comparación de modelos, por falta de mediciones. Trata estos scripts como una base que debes probar con el archivo ficticio antes de usar tus datos. La prueba útil también consiste en provocar fallos: modifica un importe en faits.json y la comprobación debe rechazar el resultado; pide rellenar un texto que contenga una cifra y la respuesta debe rechazarse.
#Solución de problemas
- «La columna montant contiene algo distinto de números»
- Queda un símbolo monetario, un texto o un separador de miles. Si el archivo usa un separador de miles, añade el parámetro thousands a read_csv con el carácter correcto. En los archivos franceses suele ser un espacio de no separación, invisible a simple vista. Después, el control tendrá que quitar ese mismo carácter antes de Decimal.
- Una sola columna leída o columnas ausentes
- El delimitador no es el correcto. Abre el archivo en un editor de texto y ajusta sep en calculs.py y delimiter en controle.py.
- UnicodeDecodeError
- El archivo no está en UTF-8. Una exportación antigua de Windows suele estar en cp1252: cambia encoding en los dos scripts y luego comprueba los acentos en los nombres de las categorías.
- Error en el formato de fecha
- Una fecha no respeta el formato día/mes/año. Corrige el dato o ajusta format. Evita una conversión permisiva, que puede ocultar una inversión del día y el mes.
- Porcentajes incoherentes
- Con devoluciones o importes negativos, un porcentaje puede superar 100 o perder su sentido. El script no lo señala: en ese caso, quita esos porcentajes de faits.json.
- Respuesta rechazada en cada intento
- El modelo copia los valores pese a la instrucción. Reformúlala o prueba otro modelo, sin quitar la protección.
- «Connection refused» en Ollama
- El servicio no está iniciado. Compruébalo con ollama list y la dirección http://localhost:11434.
#Para ir más allá
Estas guías amplían el montaje: el text-to-SQL si tus datos están en una base de datos, las salidas estructuradas para el parámetro format y los riesgos de las instrucciones ocultas en archivos procedentes del exterior.
¿Un comentario, un error, una precisión? Avísanos, eso mejora la guía para todos.