Saltar al contenido

lección 3

Día 2 (mañana) — Antes de calcular, limpiar (y decidir qué es el valor)

Con el mapa en la cabeza, hoy tocas los datos: fechas en tres formatos (una con el mes en inglés), importes con «€», avance con «%», canal y plan y categoría en muchas grafías, pagos duplicados por el reintento de Stripe, y los dos nulos con significado. Y la decisión que no es de limpieza sino de criterio: qué es el «valor» de un canal, que Nuria no te va a dar.

60 min

### Un dato español que viene en inglés

Empiezas el día por lo que más despista a quien nunca ha limpiado datos de varias fuentes: una de las tres formas en que vienen las fechas trae el mes en inglés abreviado, «12 Mar 2024» en lugar de «12 mar 2024» o «12/03/2024». No es un error del que exportó: es que Stripe, el LMS y las plataformas de anuncios son herramientas internacionales, y por dentro trabajan en inglés aunque la empresa sea de Valencia y sus alumnos escriban en español. Es una lección real del oficio: los datos vienen en el idioma de la herramienta que los generó, no en el idioma del país. Y tiene una consecuencia práctica que hay que conocer: las funciones que convierten texto en fecha —el pd.to_datetime de Pandas y el parser de DuckDB— entienden los meses en inglés («Mar», «Dec»), no en español. Un «12 Mar 2024» se parsea sin problema; un hipotético «12 Dic 2024» daría un vacío. Por suerte, aquí el mes viene en inglés, así que la conversión funciona.

Ya sabes de tus encargos anteriores que una fecha guardada como texto no sirve para nada: no puedes ordenar por ella, ni restar dos para saber cuánto duró una suscripción, ni agrupar por mes. El primer paso de la limpieza es siempre convertir el texto en fechas de verdad. La forma robusta en Pandas es pd.to_datetime con format='mixed' (que le dice «cada fila puede venir en un formato distinto, apáñatelas») y dayfirst=True (que aclara que «03/12/2024» es 3 de diciembre, formato español, no 12 de marzo, formato americano). Ese dayfirst importa: sin él, medio dataset se interpretaría del revés.

Tres formatos de fecha en la misma columna, una sola función para unificarlos. El mes en inglés se parsea; conviene comprobar cuántas quedaron sin convertir

Vale la pena entender por qué tus datos, siendo de una empresa valenciana con clientes españoles, hablan inglés. No es un descuido: es la historia de cómo se construyó el software del mundo. Casi todas las herramientas que usa AulaViva —Stripe, el LMS, las plataformas de anuncios— se crearon en Estados Unidos o pensadas para un mercado global, y por dentro trabajan en inglés porque es la lengua franca de la programación. Un desarrollador de Stripe en San Francisco no va a guardar los meses en español, en alemán y en japonés: los guarda en inglés y ya localizará la interfaz cada país. Por eso, cuando exportas datos crudos de una de estas herramientas, salen en el idioma de la máquina, no en el del usuario. Es una capa que casi nunca ves —la interfaz te habla en español— hasta que bajas a los datos en bruto y te encuentras «Mar» en lugar de «mar».

La consecuencia práctica la vas a vivir toda tu carrera: las funciones que convierten texto en fecha entienden los meses en inglés por defecto, porque las escribió gente que trabajaba en inglés. pd.to_datetime parsea «12 Mar 2024» sin problema y se atraganta con «12 Mar» si viniera de un locale español mal configurado. Por eso, cuando una columna de fechas no parsea, una de las primeras sospechas es el idioma: ¿vendrán los meses en un idioma que la función no reconoce? Aquí tienes suerte —vienen en inglés, que es justo lo que la función espera—, pero es una lección que conviene aprender ahora: el idioma de los datos es el de la herramienta que los generó, y a menudo no es el tuyo.

Cada herramienta del stack guarda las fechas a su manera y en el idioma en que se programó. Por eso una empresa española acaba con fechas en inglés en sus exportaciones

### El dinero y los porcentajes que llegan como texto

El segundo frente son los números que no son números. El importe de un pago viene como «14,99 €», el precio como «119,00 €», el coste de una campaña como «5.397,33 €» y el avance de una matrícula como «87 %». Todos son texto, y con texto no se suma. Limpiarlos es una cadena de reemplazos: quitar el símbolo («€» o «%»), quitar el espacio, quitar el punto de los miles (que en España separa millares, no decimales), cambiar la coma decimal por punto (que es lo que entiende el ordenador) y, al final, convertir a número. El orden importa: si cambias la coma por punto antes de quitar el punto de los miles, «5.397,33» se convierte en un desastre. Primero fuera los puntos de miles, luego la coma a punto.

1# El orden importa: "5.397,33 €" hay que desmontarlo en el orden correcto
2texto = "5.397,33 €"
3paso1 = texto.replace("€", "") # "5.397,33 " <- fuera el simbolo
4paso2 = paso1.replace(" ", "") # "5.397,33" <- fuera los espacios
5paso3 = paso2.replace(".", "") # "5397,33" <- fuera el punto de los MILES
6paso4 = paso3.replace(",", ".") # "5397.33" <- la coma decimal pasa a punto
7numero = float(paso4) # 5397.33 <- ahora si es un numero
8print(numero)

El orden de los reemplazos al limpiar dinero europeo: primero fuera el punto de los miles, luego la coma decimal a punto. Al revés, «5.397,33» se convertiría en un número imposible

Cuidado con los importes fuera de rango, que aquí los hay a propósito. Entre los pagos aparece algún importe negativo (un reembolso) y algún cero. Un reembolso de −119 € metido en la suma del LTV lo hunde sin motivo, y un cero infla el número de pagos sin aportar valor. La regla del caso: para las métricas de valor, quédate con los importes positivos y razonables (entre 0 y el precio anual, 119 €). No los borres del fichero —son hechos reales—, pero exclúyelos del cálculo que no deben tocar. Lo mismo con el avance mayor que 100 %: es un dato imposible que hay que marcar.

### Por qué los datos llegan sucios (y por qué siempre llegarán así)

Vale la pena entender de dónde sale toda esta suciedad, porque no es mala suerte ni descuido: es la consecuencia inevitable de cómo funcionan las empresas. AulaViva no tiene un único sistema que lo guarde todo con el mismo formato; tiene cinco fuentes distintas —Stripe para los cobros, el LMS para el aprendizaje, Google Ads y Meta para los anuncios, un programa propio para los referidos— y cada una fue construida por gente distinta, en momentos distintos, con criterios distintos. Stripe exporta las fechas en formato internacional con el mes en inglés; el LMS las guarda a la española; la herramienta de anuncios usa otro más. Nadie se puso de acuerdo, porque nadie previó que un día habría que juntarlo todo. La suciedad no es un fallo del dato: es la huella de que el dato nació en muchos sitios.

Piénsalo como una reunión de familia donde cada uno trae un plato: uno lo trae en fuente de cristal, otro en tupper, otro en papel de aluminio, y las cantidades no cuadran porque cada uno cocinó «para los que seamos». Nadie lo hizo mal; simplemente cocinaron por separado. Cuando toca poner la mesa —juntar los datos para un análisis— alguien tiene que pasar todo a la misma vajilla y cuadrar las raciones. Ese alguien eres tú, y ese trabajo, la limpieza, es la mitad invisible del oficio: nadie te lo agradece cuando está bien hecho, pero si te lo saltas, todo lo que viene después está mal. Un dato mal limpiado no da un error rojo; da un número creíble y equivocado, que es mucho peor.

La consecuencia práctica: esto no se acaba nunca. No esperes un futuro en el que los datos lleguen limpios y puedas dedicarte «solo a analizar». Mientras haya varias fuentes —y siempre las hay—, habrá que reconciliarlas. Los analistas que odian limpiar y lo hacen deprisa y mal producen análisis que se derrumban a la primera pregunta incómoda; los que entienden que limpiar ES analizar (porque cada decisión de limpieza es una decisión sobre qué cuenta y qué no) producen números que aguantan. Dedícale a la limpieza el tiempo que merece: es donde se gana o se pierde la fiabilidad de todo lo demás.

### Las grafías: cinco canales, no diecinueve

Ayer viste que el canal viene en casi veinte formas. Hoy lo arreglas, y es el paso más importante de toda la limpieza, porque el canal es la dimensión sobre la que gira el encargo entero. La técnica es normalizar y mapear: primero pones todo en minúsculas y sin espacios sobrantes (.str.strip().str.lower()), lo que reduce «Cupón», «CUPON» y «cupon» a la misma cosa; luego mapeas las variantes que significan lo mismo a un nombre canónico («descuento» → «cupon», «ads» y «publicidad» → «anuncios», «organico» y «buscador» → «seo», «amigo» y «recomendacion» → «referido», «b2b» y «corporativo» → «empresas»). Al terminar, cinco canales limpios. La misma técnica sirve para el plan (mensual/anual) y para la categoría de curso (las seis canónicas).

Hay dos formas de normalizar y conviene saber cuándo usar cada una. La primera es el mapa explícito: un diccionario que dice «descuento → cupon, ads → anuncios», donde tú enumeras cada variante y su destino. Es la más segura cuando el conjunto de valores es cerrado y conocido —cinco canales, seis categorías, dos planes—, porque cualquier grafía que no esté en el mapa se queda como vacío y salta a la vista: te avisa de que se te escapó una forma. La segunda son las reglas por patrón: «todo lo que empiece por cupon o contenga descuento va a cupón», útil cuando las variantes son demasiadas para listarlas. Aquí, con conjuntos pequeños y cerrados, el mapa explícito es la mejor opción: es más trabajo de escribir, pero no deja pasar nada sin que te enteres.

Cuidado con normalizar con reglas demasiado ansiosas, que es un error sutil y peligroso. Si escribes «todo lo que contenga "a" va a anuncios», barrerás también «amigo» (que es referido) y «marketing». Una regla que captura de más ensucia en silencio: no da error, simplemente clasifica mal, y lo descubres —si lo descubres— cuando los números no cuadran. Por eso, cuando el conjunto de valores es pequeño y conocido, el mapa explícito gana al patrón: prefiere enumerar de más a capturar de más. Y siempre, siempre, comprueba después de normalizar que el número de categorías es el que esperabas (5 canales, no 4 ni 6): ese recuento es tu red de seguridad.

Consejo de senior: para las tablas del análisis SQL de los próximos días, esta limpieza ya está hecha por ti en las tablas del caso: el canal ya viene mapeado a los cinco nombres, los importes ya son números y las fechas ya son fechas. Pero tienes que saber hacerla en Pandas igual, porque en el trabajo real nadie te da las tablas limpias: te dan los CSV crudos y la limpieza es tuya. Hoy limpias a mano en Pandas para entender qué hay debajo; a partir de mañana trabajas en SQL sobre las tablas ya saneadas, que es como trabaja el equipo. Saber limpiar y saber que alguien lo limpió son dos cosas distintas, y un buen analista sabe las dos.

### Los duplicados: el reintento de Stripe y el doble clic

El tercer frente son los duplicados, y son traicioneros porque no ensucian una celda, sino que meten filas de más que parecen legítimas. Los pagos vienen duplicados porque el webhook de Stripe —el aviso que la pasarela envía cuando cobra— a veces se dispara dos veces en segundos, y el mismo pago entra dos veces con el mismo pago_id. Las matrículas vienen duplicadas por el doble clic del alumno al apuntarse. Y las suscripciones, por reintentos de cobro. Si sumas importes sin quitar los pagos repetidos, el LTV sale inflado; si cuentas matrículas sin deduplicar, la tasa de finalización sale mal. La herramienta es drop_duplicates sobre la columna que identifica la fila: pago_id para los pagos, matricula_id para las matrículas, suscripcion_id para las suscripciones.

El reintento del webhook mete el mismo pago dos veces. Deduplicar por pago_id antes de sumar es lo que evita un LTV inflado; igual con matrículas y suscripciones

### El plan de limpieza, tabla por tabla

Con las técnicas claras, conviene tener un plan antes de lanzarse, porque limpiar sin orden es la forma más fácil de dejarse una mancha. El plan sale de cruzar lo que sabes de cada tabla con las cuatro clases de suciedad. No hace falta memorizarlo: se construye mirando la tabla y preguntándose, columna a columna, qué le pasa. Pero tenerlo escrito antes de empezar te evita descubrir a media semana que el precio seguía siendo texto o que las matrículas seguían duplicadas.

  • usuarios: normalizar el canal (19 grafías a 5, lo más importante), la ciudad y el plan; parsear fecha_registro; marcar el campana_id vacío como sin_campana (nulo con significado, no tirar).
  • suscripciones: deduplicar por suscripcion_id; parsear fecha_inicio; tratar fecha_fin vacía como «activa» (nulo con significado); convertir el precio a número; normalizar plan y estado.
  • pagos: deduplicar por pago_id (antes de sumar nada); convertir el importe a número y excluir los negativos y ceros del cálculo de valor; normalizar el tipo (alta/renovacion), que es crítico.
  • matriculas: deduplicar por matricula_id; normalizar completado a booleano (clave para la finalización); convertir pct_completado a número y marcar los mayores que 100; validar minutos_vistos.
  • cursos: normalizar categoria (18 a 6, para el control del jueves) y nivel; convertir duracion_horas a número; validar n_lecciones.
  • campanas: convertir el coste a número; normalizar el canal (para el CAC); parsear las fechas.
  • canales: casi limpia; solo normalizar el tipo.

Fíjate en que el plan no trata todas las columnas por igual: hay unas pocas críticas —el canal (de él cuelga toda la segmentación), el tipo de pago (separa alta de renovación), el completado (define la finalización) y los dos nulos con significado— y muchas de contexto que, si se quedan un poco sucias, no cambian el hallazgo. Un analista con oficio pone el esfuerzo donde importa: limpia con mimo las columnas de las que depende la conclusión y no se obsesiona con las que solo decoran. Saber qué mancha hunde el análisis y cuál es cosmética es parte del criterio, y se aprende mirando hacia dónde va el encargo antes de limpiar.

### Dos «valores» que no cuadran

A media mañana, con los datos ya limpios, haces una prueba rápida antes de formalizar nada, y te llevas un susto útil. Calculas un «valor» del canal de dos formas distintas y te salen dos historias opuestas. Si miras las altas y el CAC —la foto de Growth—, el cupón es la mina de oro. Pero si miras, así por encima, el ingreso medio acumulado por alumno hasta hoy, el cupón se desinfla y el referido despunta. El mismo canal, dos «valores», dos conclusiones contrarias. Esto no es un error de tus cálculos: es la prueba de que «valor» sin definir no significa nada, porque cada forma de medirlo cuenta una película distinta. Se lo llevas a Nuria.

1Tu 11:48
2Nuria, una cosa rara. Por altas y CAC el cupon arrasa. Pero si miro el ingreso medio acumulado
3por alumno, el cupon esta por los suelos y el referido dispara. Cual es el "valor de verdad"?
4Nuria 11:55
5Bienvenido al problema. Depende de que midas, y por eso hay que ESCRIBIRLO antes de calcular.
6Las altas y el CAC son lo que enamora a Diego: cuanta gente entra y a que precio. Pero a
7nosotros nos importa lo que esa gente DEJA despues: si aprende, si se queda, si renueva.
8No lo cierres hoy del todo, pero fijate ya en si el cupon trae alumnos que abren pocos cursos.
9Ahi hay algo, y sera el hilo de manana.

La conversación con Nuria: dos formas de medir el «valor» dan dos respuestas opuestas. Por eso la métrica se define antes de calcular, no después

La lección de fondo, la que ordena toda la semana, cabe en una frase: una métrica sin definir no es un número, es una excusa para el número que te convenga. Si Diego quiere que el cupón gane, mira las altas; si tú sospechas que pierde, miras el ingreso por alumno. Sin una definición acordada de antemano, cada uno «demuestra» lo que ya creía, y el análisis se convierte en una discusión de opiniones con decorado de datos. Por eso el paso más importante de hoy no es un reemplazo de Pandas ni un JOIN: es escribir, en una frase que Elena entienda, qué vas a llamar «valor» y defenderlo antes de calcularlo. Lo demás es ejecución.

### La decisión que no es de limpieza: qué es el «valor» de un canal

Y aquí llega lo que separa este encargo de los anteriores. Terminada la limpieza, Nuria espera de ti algo que no se resuelve con una función: la definición de la métrica central. «Decide tú qué es el valor de un canal», te dijo, «y defiéndemelo». No hay una única respuesta correcta, hay una defendible. Podrías medir el valor por altas (lo que hace Diego), por ingresos del mes (Finanzas), por horas de vídeo (Producto)… y cada opción te llevaría a una conclusión distinta. La que aguanta combina tres señales encadenadas: si el alumno aprende (finalización), si se queda (renovación) y cuánto deja (LTV), y se cierra con la cuota de valor —qué parte del valor total de AulaViva aporta cada canal—. Esa definición la escribes hoy, antes de calcular nada, porque una métrica sin definir no es un número, es una excusa para el número que te convenga.

Ligadas a esa definición van las dos decisiones sobre los nulos con significado, y son de criterio, no de sintaxis. El campana_id vacío obliga a un LEFT JOIN cuando cruces usuarios con campañas para el CAC: un INNER JOIN se quedaría solo con las altas que tienen campaña y borraría SEO y Referido enteros. Y la fecha_fin vacía obliga a tratar la suscripción como activa —«el alumno sigue»— y no como baja ni como dato ausente: si la descartas, pierdes justo a los alumnos que se quedan, que son los valiosos, y los canales que mejor retienen salen peor. Estas dos decisiones no las ves en la salida de hoy; las pagas o las cobras el jueves.

La misma decisión de limpieza, dos análisis opuestos: tratar bien los dos nulos da el ranking correcto; tratarlos como datos rotos lo invierte y haría recomendar lo contrario

Consejo de senior: escribe la definición del valor en una frase antes de tocar el editor, y compártela con Nuria antes de calcular. Adelantar la definición y validarla con quien decide te ahorra rehacer el análisis entero si resulta que ella esperaba otra cosa. Un analista senior no sorprende a su jefa con la métrica el viernes: se la enseña el martes, la discute, y llega al viernes con una definición ya acordada y unos números que la sostienen. La conversación barata es la del martes; la cara es la del viernes cuando ya no hay tiempo.

### Validar: los datos imposibles que no se limpian, se marcan

Hay una cuarta clase de suciedad que no es de formato ni de duplicados: los datos imposibles. Un avance del 130 %, un curso de −5 lecciones, una matrícula que se completó antes de empezar, un pago de importe negativo, unos minutos vistos de 999999. No son texto mal escrito ni filas repetidas: son valores que no pueden existir en la realidad y que, si entran en un cálculo, lo envenenan. Un solo minutos_vistos de 999999 dispara la media de horas de un canal; un par de importes negativos hunden un LTV. La diferencia con la limpieza de formato es importante: un «14,99 €» se arregla (se convierte en 14.99); un avance del 130 % no se arregla, se excluye del cálculo que no debe tocar.

La palabra clave es validar, y el criterio es quirúrgico: no se borra la fila del fichero —es un hecho real, aunque sea absurdo—, se excluye del cálculo concreto que distorsionaría. Un importe negativo (un reembolso) es un dato válido para contabilidad, pero no debe entrar en la suma del LTV. Unos minutos de 999999 son basura del registro y no deben entrar en la media de horas. Por eso los filtros del análisis llevan condiciones de rango razonable (importe entre 0 y 119, minutos entre 0 y un tope, avance entre 0 y 100): no para «limpiar», sino para que un outlier no decida el resultado. Marcar y excluir con criterio es tan importante como normalizar.

Cuatro clases de suciedad, cuatro tratamientos distintos. Confundirlos —borrar un imposible, sumar un duplicado, tirar un nulo con significado— es lo que tuerce un análisis

### Y de paso, el titular de Diego

Con el canal ya limpio, puedes hacer lo que Diego pide y confirmar su titular: contar las altas por canal. Y es verdad, el cupón es el número uno con diferencia —casi el 38 % de las altas—, seguido de anuncios, SEO, referido y empresas. Hay que decírselo tal cual, porque es cierto en la superficie y porque negar lo evidente te quita credibilidad para lo que viene. Lo que Diego aún no sabe —ni tú del todo— es si ese liderato sobrevive cuando dejas de contar quién entra y empiezas a medir quién se queda. Eso empieza mañana en SQL. Hoy cierras con los datos limpios, la definición del valor escrita, y una certeza incómoda: el número que más gusta a Growth es solo el principio de la historia.

Consejo de senior: cuando termines de limpiar, escribe en dos líneas qué decisiones tomaste y por qué (deduplicé pagos por pago_id, traté la fecha_fin vacía como activa, conservé las altas sin campaña). Ese pequeño registro es tu seguro para el viernes: cuando alguien cuestione una cifra, tendrás a mano por qué está bien calculada. Las decisiones de limpieza se olvidan en tres días si no se anotan, y no hay nada peor que defender un número sin recordar cómo lo construiste. Un analista que documenta sus decisiones de datos, aunque sea en un comentario del cuaderno, es un analista al que se le cuestiona menos y se le cree más.

Regístrate para guardar tu progreso.