En investigación cuantitativa, las preguntas abiertas son el ingrediente incómodo. Todo el resto del cuestionario produce números directamente: escalas de 1 a 10, opciones múltiples, net promoter scores. Pero las preguntas abiertas producen texto libre, y el texto libre no entra en una regresión ni en un crosstab.
Para convertirlas en datos, existe un proceso que se llama codificación: alguien lee todas las respuestas, agrupa las que dicen lo mismo, asigna un número a cada grupo, y reemplaza el texto por ese número en la base de datos. “Hellmanns”, “la de tapa amarilla” y “hellmans (sic)” se convierten todas en el código 5, que corresponde a Hellmann’s.
Es un trabajo tedioso, repetitivo y propenso a errores de consistencia. Y cuando se trata de miles de respuestas a múltiples preguntas para varios proyectos corriendo en paralelo, es también caro. Decidí automatizarlo.
El problema en toda su complejidad
Antes de escribir una sola línea de código, tuve que entender bien el problema. Hay dos situaciones fundamentalmente distintas:
Cuando ya existe un libro de códigos. En estudios longitudinales, paneles o proyectos con múltiples olas, alguien ya definió las categorías en una vuelta anterior. Hay un archivo Excel —el libro de códigos, o LDC— con una lista de claves numéricas y los valores canónicos que les corresponden. La tarea aquí es imputar: tomar cada respuesta nueva y mapearla a la clave correcta. El desafío principal es la variabilidad ortográfica. “Cocca-cola”, “coca cola”, “CocaCola” y “la negra” son todas la clave 7.
Cuando no existe ningún libro de códigos. En estudios nuevos o preguntas que nunca se habían hecho, hay que inventar las categorías desde cero. El analista no sabe de antemano qué va a encontrar. Primero hay que descubrir qué categorías emergen de los datos, luego asignar cada respuesta a alguna, y finalmente generar un LDC reutilizable para futuras olas.
Ambos flujos comparten infraestructura pero tienen lógicas completamente distintas.
Un problema que nadie menciona: la respuesta multi-valor
Hay un tercer problema que no está en los manuales pero aparece todo el tiempo.
Imaginá una pregunta: “¿Qué cualidades debería tener un buen jugador de fútbol?”. Un encuestado responde: “Velocidad, técnica y garra”. Otro: “La actitud y el compromiso con el equipo”.
El primero mencionó tres cosas. El segundo mencionó dos. Pero en el archivo de datos, ambas ocupan una sola celda. Si codificamos esa celda como una unidad, perdemos menciones. En un estudio de imagen de marca o de atributos de producto, esas menciones perdidas pueden cambiar los resultados.
La solución es la expansión ad-hoc: detectar cuándo una respuesta contiene múltiples menciones reales, dividirlas, y distribuirlas en columnas adicionales. La columna original (P23) se queda con la primera mención (top of mind), y se crean columnas nuevas (P23adhoc2, P23adhoc3, etc.) para las siguientes. La detección no puede ser solo por regex —una coma puede separar menciones o puede ser parte de una frase narrativa— por eso la decisión final la toma el LLM.
La arquitectura
El orquestador (main.py) coordina todo: carga el archivo, detecta las preguntas, presenta el menú y llama a los flujos. Los módulos de procesamiento implementan cada modo. La capa de I/O maneja todo lo que toca disco. Hay módulos de soporte para normalización de texto, comunicación con la API y la interfaz de terminal.
Multi-proyecto y configuración por proyecto
La herramienta no fue diseñada para un único estudio. El menú inicial lista todos los proyectos disponibles en una carpeta central. Cada proyecto tiene su propia estructura:
proyectos/
PROYECTO_A/
data/ ← archivos Excel de entrada
LDC/ ← libro(s) de códigos
REFUERZOS/ ← variaciones aprendidas
outputs/ ← resultados + checkpoints
PROYECTO_B/
APP/ ← subproyecto
SC/ ← otro subproyecto
Los subproyectos se detectan automáticamente. Si los archivos siguen el patrón PROYECTO1.xlsx, PROYECTO2.xlsx, también pregunta el número de ola. Cada proyecto puede tener sus propios códigos especiales (en algunos estudios “OTRO” es 99, en otros es 88) configurados en un JSON central.
El flujo de imputación
Los refuerzos son el mecanismo de aprendizaje incremental. Cada vez que el LLM mapea una variación nueva (“cocca-cola” → Coca-Cola), esa relación se guarda en un JSON. La próxima vez, esas variaciones conocidas se inyectan en el prompt. Con el tiempo, el sistema necesita cada vez menos llamadas a la API.
El flujo de codificación (sin LDC)
La separación en dos fases —primero definir qué categorías crear, después asignar— es deliberada. Si se hace en un solo paso, el LLM tiende a crear demasiadas categorías específicas o a agrupar de forma inconsistente entre batches. Al fijar primero la lista, el segundo paso tiene un espacio de respuesta constante y produce clasificaciones coherentes.
Las frecuencias como señal de calidad
El LLM solo no siempre detecta bien qué merece categoría propia. Si hay 500 respuestas distintas, “ICBC” puede aparecer 5 veces con 5 grafías diferentes. Cada una parece un caso raro; juntas son una categoría relevante.
La solución fue pasarle las frecuencias normalizadas junto con los valores. Antes de armar el prompt, normalizo todos los textos (minúsculas, sin acentos, sin puntuación), cuento cuántas veces aparece cada término normalizado, y los más frecuentes van explícitamente al LLM. Esto también ayuda en la revisión interactiva, donde el analista ve el número de ocurrencias y el porcentaje que representa cada categoría. Saber que “OTRO” tiene el 23% de las respuestas es una señal para revisarlo con cuidado.
Resiliencia: checkpoints
Procesar mil respuestas implica docenas de llamadas a la API. Si la conexión falla a mitad, no querés empezar desde cero. Después de procesar cada pregunta, el estado completo del DataFrame se guarda en un archivo Parquet junto con un JSON de caché de los valores ya clasificados. Al iniciar, la herramienta busca checkpoints existentes y pregunta si continuar desde donde quedó.
La interactividad no es un defecto, es el producto
Una decisión de diseño que fui entendiendo con el tiempo: la automatización total no es el objetivo. El objetivo es que el analista confíe en el resultado para defenderlo ante el cliente.
Antes de clasificar, el analista puede editar las categorías propuestas. Después de clasificar, puede revisar cada categoría y mover los valores mal asignados. Antes de guardar, ve una distribución completa con frecuencias y porcentajes.
Lo que el LLM hace es eliminar el trabajo mecánico. Lo que el analista hace es tomar las decisiones que requieren criterio de dominio: si “Light” y “Light & Fit” deben ser la misma categoría o categorías separadas, qué hacer con las respuestas que critican el estudio en vez de responder la pregunta.
Resultado en producción
Una base con 1.500 respuestas a 4 preguntas abiertas que antes tomaba entre 4 y 6 horas de trabajo manual ahora toma entre 25 y 45 minutos: 15-25 de procesamiento automático y 10-20 de revisión interactiva. La detección de variantes ortográficas es más robusta que la humana en casos de errores de tipeo poco obvios, y no hay deriva de consistencia a lo largo de sesiones largas.
El código está en mi GitHub.