Saltar al contenido

lección 3

Día 2 (mañana) — Antes de calcular, limpiar

Ayer mediste el desorden; hoy lo arreglas. Fechas en tres formatos, importes con «€», el canal escrito de cinco maneras, plataformas y países inconsistentes, eventos duplicados, outliers y nulos con significado. La limpieza no es cosmética: sin ella, el cruce por canal falla en silencio.

55 min

### Un dato sucio no da error: da un número equivocado

Ayer hiciste el inventario del desorden: 23 grafías para seis canales, fechas que Pandas ve como texto, un importe con el euro pegado, 40 jugadores duplicados y 312 sesiones contadas dos veces. Hoy toca arreglarlo. Y conviene empezar con una idea que asusta un poco al principio: un dato sucio casi nunca da un error rojo que te avise. Da algo peor: un número tranquilo, con pinta de correcto, que está mal. Si sumas una columna de importes que en realidad es texto, Pandas no se queja: te concatena o falla a medias. Si agrupas por un canal escrito de cinco formas, no salta ninguna alarma: simplemente te salen cinco canales donde había uno. El error silencioso es el más peligroso, porque llega hasta la demo sin que nadie lo pare.

Por eso la limpieza va antes que el cálculo, siempre, y no es un paso menor ni aburrido: es donde se decide si todo lo que viene después es verdad o basura bien maquetada. Vamos a resolver los problemas de ayer uno a uno, en Pandas, y en cada uno vas a ver qué cifra habría salido mal si no lo arreglaras. Al final del día tendrás las tablas listas para que el análisis en SQL de mañana trabaje sobre datos en los que se puede confiar.

Y una advertencia antes de empezar, para que no te obsesiones: limpiar no es dejar los datos perfectos, es dejarlos suficientemente buenos para la pregunta que tienes que responder. No hay dataset impecable, y perseguir la perfección es una forma elegante de no entregar nunca. Lo que haces hoy es quitar de en medio lo que estropearía las cifras del encargo —los canales sin normalizar, los importes en texto, los duplicados, los imposibles— y dejar constancia de lo que no toques. Un campo secundario con algún hueco que no afecta a tu análisis puede quedarse como está; no todo lo imperfecto hay que arreglarlo, solo lo que ensucia la respuesta.

### Basura entra, basura sale: por qué esto es la mitad del trabajo

Hay una frase de los primeros tiempos de la informática que resume esto mejor que ningún manual: «garbage in, garbage out», basura entra, basura sale. Se popularizó a finales de los años cincuenta, cuando los primeros ordenadores empezaron a hacer cálculos para empresas y alguien tuvo que explicar a los jefes que la máquina no hacía magia: si le dabas datos malos, te devolvía resultados malos, por muy impresionante que fuera el aparato. La máquina no corrige lo que le metes; lo procesa tal cual. Sesenta años después sigue siendo la ley número uno del análisis, y en tu oficio tiene un agravante: la basura no da error, da un número con buena cara. Un ordenador de los años cincuenta al menos escupía un resultado obviamente absurdo; tu consulta te devuelve un CPI de 0,45 € con toda tranquilidad, esté bien o mal el dato de detrás.

Aquí va una verdad que a los junior les sorprende y que conviene aceptar cuanto antes: la mayor parte del tiempo de un analista se va en esto, en encontrar, entender y arreglar datos, no en la parte lucida de sacar conclusiones. Cuando preguntas a analistas con años de oficio, la respuesta ronda siempre lo mismo: la limpieza y la preparación se llevan la mayor parte de la jornada. No es un fallo de organización ni una fase que con experiencia desaparezca; es el trabajo. Si entras pensando que limpiar datos es una tarea menor que hacen «los junior» mientras los senior piensan, vas a entregar números equivocados muy deprisa. Los senior de verdad limpian con más cuidado, no con menos, porque han visto lo que cuesta un dato sucio que llegó hasta la reunión.

La imagen que mejor lo captura es la cocina de un restaurante. Antes de que se encienda un solo fuego, el cocinero hace lo que en los fogones llaman el «mise en place»: lava, pela, corta y mide cada ingrediente, y lo deja colocado en su cuenco. Parece tiempo perdido —el comensal no ve nada de eso— pero es lo que hace que, cuando llega el pedido, cocinar sea rápido y sin sustos. Un cocinero que se salta el mise en place y empieza a cortar cebolla con la sartén ya humeando acaba con la salsa quemada. La limpieza de datos es tu mise en place: la media hora de hoy, aparentemente lenta, es lo que hace que el análisis de mañana salga rápido y sin cifras quemadas.

Consejo de senior: apunta cada decisión de limpieza según la tomas: cuántas filas apartaste, por qué, y qué criterio usaste. «Quité 14 compras en pesos y 9 reembolsos; me quedo con ventas en euros» es una línea que te salvará dentro de un mes, cuando alguien pregunte por qué tu total no cuadra con el suyo. Un análisis sin registro de lo que se limpió es imposible de defender y de reproducir: cuando te pregunten «¿y esto de dónde sale?», la respuesta no puede ser «creo que quité unas filas raras».

### Fechas: tres formatos, una sola verdad

La fecha de instalación llega en tres formatos mezclados en la misma columna: "2024-06-19" (año-mes-día), "12/07/2024" (día/mes/año) y "9 jul 2024" (con el mes en palabra). Los tres son fechas para un humano, pero para Pandas son texto, y con texto no puedes restar días ni ordenar cronológicamente ni definir una cohorte. Necesitas convertirlos todos a un tipo fecha de verdad.

De tres textos a una sola fecha real: pd.to_datetime con format="mixed" y dayfirst=True
1fecha = pd.to_datetime(usuarios['fecha_instalacion'],
2 format='mixed', dayfirst=True, errors='coerce')

La conversión robusta de fechas: un solo tipo fecha a partir de tres formatos de texto.

Consejo de senior: después de convertir fechas, cuenta siempre los NaT (los que no se pudieron reconocer) y mira el rango mínimo y máximo. Si aparece una fecha de 1970 o de 2099, hay un formato mal interpretado. Una conversión de fechas que no compruebas es una fuente de errores que no salen a la luz hasta que una cohorte tiene un tamaño imposible.

### Importes: quitarle el disfraz de texto al dinero

El importe de las compras llega como "4,99 €": el símbolo del euro pegado, la coma como separador decimal (a la europea), y todo ello texto. Antes de convertirlo a número hay que quitarle el disfraz: fuera el euro, la coma pasa a punto (Python usa el punto decimal), fuera los espacios, y entonces sí, a decimal. Pero hay dos trampas de negocio antes de eso, y son más importantes que la limpieza de formato.

La primera: algunas filas son reembolsos (la columna reembolso vale 1, o el importe es negativo). Un reembolso no es una venta; es dinero que se devuelve. Si lo cuentas como ingreso, inflas las ventas. La segunda: hay un puñado de compras en otra moneda (MXN, pesos mexicanos, escritos como "19,30 MXN"). Mezclar euros y pesos en una misma suma da un número sin sentido. Antes de limpiar el formato, decides qué filas cuentan: solo ventas reales (reembolso 0) y solo en euros. El resto se aparta. Esa decisión —qué entra en el cálculo— es de negocio, y va primero.

No conviertas una columna de dinero a número sin haber apartado antes los reembolsos y las monedas distintas. Si lo haces al revés, o bien el código peta al toparse con "19,30 MXN", o bien —peor— cuela pesos como si fueran euros y los reembolsos como si fueran ventas. El orden correcto es: primero decides qué filas son ventas de verdad, después limpias el formato del importe.

Fíjate en el orden que acabas de aplicar con el importe, porque es una regla general que vale para toda la limpieza: la decisión de negocio va antes que la limpieza técnica. Primero decides qué filas cuentan (ventas reales, en euros) y solo después conviertes el formato. Es tentador hacerlo al revés —limpiar todo lo que hay y filtrar luego— pero así arrastras reembolsos y monedas ajenas hasta el final, donde es más fácil que se cuelen en una suma. La pregunta «¿qué entra en este cálculo?» es de negocio, no de código, y se responde antes de tocar el formato de una sola columna. Cuando dudes por dónde empezar a limpiar algo, empieza por decidir qué filas son las buenas.

### El canal: la limpieza que sostiene todo el caso

Y llegamos a la reina de las limpiezas de esta semana. Ayer viste que el canal tiene 23 grafías para seis canales reales. "coinrush", "CoinRush", "Coinrush" y "coin_rush" son todos CoinRush. "meta" y "facebook" son Meta. "apple_search", "ASA" y "Apple Search" son el mismo. Normalizar esto no es una manía de orden: es lo que hace que agrupar por canal dé seis canales en vez de veintitrés, y que el cruce con el gasto de publicidad funcione. Si no lo haces, todo el análisis por canal —el corazón del encargo— sale roto y repartido en fantasmas.

La técnica es un mapeo a valor canónico: pasas todo a minúsculas y sin espacios (para que "CoinRush" y "coinrush " colapsen), y luego un diccionario traduce cada grafía a su forma única. Es el mismo patrón para cualquier categoría escrita a mano por varias personas o varios sistemas.

De 23 grafías a 6 canales: el mapeo a valor canónico que sostiene todo el análisis por canal

### El mismo patrón, en todas partes

Lo bueno de aprender a normalizar el canal es que no vas a aprender un truco para el canal: vas a aprender el truco para cualquier columna escrita a mano o por varios sistemas, que son casi todas las que describen categorías. El mismo desorden que tiene el canal lo tienen el país ("es", "España", "ES", "spain"), la plataforma ("iOS", "ios", "IOS", "Android", "AND") y el tipo de producto. Y la receta es siempre la misma en tres pasos: primero minúsculas y sin espacios, para que las variantes tontas ("CoinRush" y "coinrush ") colapsen solas; después un diccionario que traduce cada grafía superviviente a su valor canónico; y por último —esto no lo saltes— vuelves a contar los valores distintos para comprobar que han bajado a los que esperabas. Si esperabas seis canales y salen siete, te quedó una grafía sin mapear.

Aprende este patrón una vez y lo aplicas el resto de tu carrera, en cualquier sector. El nombre de un producto escrito por veinte comerciales, la provincia tecleada por mil clientes, la categoría que cada sistema exporta a su manera: todo se normaliza igual. Lo único que cambia es el diccionario, que depende del negocio. Por eso no tiene sentido memorizar «cómo se limpia el canal de un juego»; tiene sentido interiorizar «cómo se lleva una categoría sucia a un conjunto pequeño de valores canónicos y se comprueba», que es una habilidad que viaja contigo a la siguiente empresa.

Consejo de senior: nunca construyas el diccionario de mapeo de memoria, «a ver, el canal será coinrush, meta, google...». Saca primero la lista de todos los valores distintos con su recuento y míralos con tus propios ojos. Siempre hay una grafía que no habrías adivinado: un "fb" que era Facebook, un "google ads " con espacio final, un canal nuevo que nadie te avisó que habían añadido. El diccionario se construye sobre lo que hay en el dato, no sobre lo que crees que hay. Suponer que conoces todas las grafías es la forma más habitual de dejarte una fuera.

### La trampa del cruce por canal: cuando el JOIN falla en silencio

Aquí está la lección que separa la limpieza cosmética de la limpieza que importa. El gasto de publicidad (gasto_ua) también trae el canal escrito de cualquier manera: "apple search", "Facebook", "organic". Para calcular el CPI tienes que cruzar el gasto de cada canal con las instalaciones de ese canal en usuarios. Pero un cruce empareja por coincidencia exacta de texto: "meta" no casa con "Facebook" aunque sean el mismo canal. Si cruzas sin normalizar los dos lados al mismo canónico, el cruce no da error: simplemente no encuentra pareja para media tabla, y te devuelve canales sin gasto o gastos sin canal. El resultado es un CPI roto, y lo peor es que sale un número, no un error.

Por eso la regla es: normaliza el canal en las DOS tablas al mismo valor canónico antes de cruzarlas. La misma función de mapeo que aplicas a usuarios se la aplicas a gasto_ua. Solo entonces "meta" casa con "meta" y el gasto de Meta se suma con las instalaciones de Meta. Esta es la razón de fondo de por qué normalizar categorías no es un adorno: es la condición para que un cruce diga la verdad.

Por qué la limpieza del canal no es cosmética: sin normalizar los dos lados, el cruce falla en silencio

Consejo de senior: después de un cruce del que dependen tus cifras, comprueba siempre cuántas filas quedaron sin pareja. Si esperabas seis canales y salen ocho, dos son fantasmas de una grafía sin normalizar. Un cruce que «casi» funciona es más peligroso que uno que falla del todo, porque el que falla te avisa y el que «casi» funciona te deja presentar una cifra rota con total tranquilidad.

### Duplicados: el mismo hecho contado dos veces

Los duplicados de estos datos son de dos tipos distintos, y conviene no tratarlos igual porque piden decisiones diferentes. El primero son sesiones contadas dos veces. El sistema que registra los eventos del juego —el SDK del que hablamos el lunes— reintenta el envío cuando se cae la conexión del móvil, y a veces la misma sesión llega dos veces al almacén, con el mismo evento_id. Son filas idénticas que describen un único hecho: hay que quedarse con una y tirar la copia. Se deduplica por evento_id, la clave que identifica cada evento, y listo. Es un duplicado técnico, un hipo del sistema.

El segundo tipo es más delicado: jugadores que aparecen dos veces en la tabla usuarios, con el mismo user_id pero datos ligeramente distintos (por ejemplo, dos fechas de instalación por una reinstalación, o un cruce de sistemas que duplicó la ficha). Aquí no puedes tirar una fila a ciegas, porque no son idénticas: tienes que decidir cuál te quedas. El criterio razonable suele ser quedarte con la más reciente —la última fecha de instalación—, y en SQL eso se hace numerando las filas de cada jugador y quedándote con la número uno. La diferencia con el caso anterior es de fondo: un duplicado técnico se colapsa; un duplicado con datos distintos obliga a una decisión de negocio (¿cuál es la buena?).

Dos tipos de duplicado: la sesión idéntica que se colapsa por evento_id y el jugador repetido donde hay que elegir fila

Consejo de senior: después de deduplicar, compara el número de filas antes y después, y comprueba que la diferencia es la que esperabas. Si esperabas quitar 40 jugadores repetidos y se van 4.000, has deduplicado por la clave equivocada y te estás cargando datos buenos. Si no se va ninguno, es que no había duplicados... o que la clave no era esa. El recuento antes/después es el chivato más simple de que la deduplicación hizo lo que creías.

### Por qué un solo valor imposible arruina una media

Antes de rematar con los duplicados y los outliers, conviene entender por qué un puñado de valores locos hace tanto daño, porque explica media estadística que vas a usar toda la semana. La media —sumar todo y dividir por el número de casos— tiene un talón de Aquiles: cualquier valor extremo tira de ella con toda su fuerza. Un solo 999.999 en la duración de sesión, sumado y repartido, puede subir la media de todo el grupo aunque sea una única fila entre miles. La media es democrática hasta el absurdo: deja votar igual a un valor real de 90 segundos y a un fallo de registro de once días.

La analogía clásica es la de una oficina pequeña donde el sueldo medio parece estupendo... hasta que te enteras de que en esa oficina está sentado el dueño de la empresa, que cobra cien veces más que el resto. La media de sueldos sale altísima y no describe a nadie: ni el dueño gana eso (gana mucho más) ni los empleados (ganan mucho menos). Una sola persona ha secuestrado la media. En tus datos, el 999.999 es el dueño sentado en la oficina: una cifra que no representa a nadie pero que arrastra el promedio hacia sí.

Hay dos formas de defenderse, y las dos las vas a usar. La primera es apartar lo imposible antes de promediar: una duración negativa, un cero o un 999.999 no son sesiones reales, son fallos de registro, y se quitan con criterio (no porque «molesten», sino porque no representan lo que dicen medir). La segunda es usar una medida que no se deje arrastrar: la mediana, que es el valor que queda justo en el medio cuando ordenas todos de menor a mayor. A la mediana le da igual que el más alto sea 90 segundos o 999.999: el del medio sigue siendo el mismo. Por eso, cuando un reparto tiene extremos, la mediana describe «lo normal» mucho mejor que la media. Esta pareja —limpiar lo imposible y, cuando haga falta, mirar la mediana además de la media— es una de las herramientas más útiles que te llevas de esta semana, y volverá el miércoles con el gasto de los pagadores.

No confundas «valor extremo» con «valor imposible». Una ballena que gasta 2.600 € es un valor extremo, pero es real y no se toca: describe a un jugador de verdad. Una sesión de 999.999 segundos es imposible y se aparta: nadie juega once días seguidos sin cerrar la app. La regla no es «fuera los grandes», es «fuera lo que no puede haber pasado». Borrar valores extremos reales por parecer raros es falsificar los datos; dejar valores imposibles por miedo a tocar es mentir con ellos.

Quedan los duplicados (deduplicar jugadores y eventos), los outliers (duraciones de sesión imposibles: negativas, cero, 999999 segundos) y los nulos con significado que ya interrogaste ayer. Los outliers merecen una nota: una duración de -30 segundos o de 999.999 segundos (más de once días seguidos jugando) no es una sesión real, es un fallo de registro. Si los dejas dentro, la duración media de sesión se dispara y miente. La estadística descriptiva tiene una regla sencilla aquí: antes de promediar, mira el mínimo y el máximo; si son imposibles, aparta los imposibles y promedia el resto. Vamos con todo ello.

Regístrate para guardar tu progreso.