Saltar al contenido

Indice / Practicas / EJ-5.3

EJ-5.3 · Dos pasadas de to_datetime

Practica de: 5.3 FechasDificultad: M

180 ventas con la fecha escrita de dos formas distintas. Una sola pasada de to_datetime pierde datos o los interpreta mal; dos pasadas bien puestas no pierden ninguno de los que se pueden salvar.

Qué hay que hacer

A partir de ventas_mensuales.csv, producir dos archivos:

ELI5Explicado facil

Te dan 180 recibos. Casi todos tienen la fecha escrita 2026-03-15, pero uno la tiene 15/03/2026 y otro dice 30 de febrero, que no existe.

Si leés todos con la misma regla, el que está al revés se pierde. Y si cambiás la regla para todos, corrés el riesgo de leer mal los que estaban bien. La solución es leer primero los que entran con la regla común, y después volver solo sobre los que sobraron con la otra regla.

Archivos

Por qué dos pasadas y no una

La tentación es dejar que to_datetime adivine el formato fila por fila. El problema es una fecha como 03/04/2026: puede ser el 3 de abril o el 4 de marzo, y las dos lecturas son válidas. Si pandas elige por vos, elige en silencio, y no hay forma de darse cuenta después.

Declarar el formato mayoritario en la primera pasada es la decisión que evita eso. La segunda pasada corre solo sobre lo que quedó, así que no puede tocar nada que ya se había interpretado bien.

Cómo saber si te salió

python comparar.py mi_fechadas.csv ventas_fechadas.csv
python comparar.py mi_rechazadas.csv ventas_rechazadas.csv

Antes de arrancar, mirá los datos

ventas_mensuales.csv (entrada) · 180 filas, se muestran 5
fechavendedorproductounidadesprecio_unitario
2026-03-02Carlos RuizAuriculares157.24
2026-03-26Carlos RuizAuriculares557.73
2026-03-31Beatriz MolinaAuriculares159.37
2026-02-09Lucía VegaWebcam645.42
2026-03-27Carlos RuizLaptop7914.44

El contrato de salida

ventas_fechadas.csv · 175 filas

ColumnaTipoQue lleva
fila_origenenteroPosicion de la fila en el archivo de entrada, empezando en 0
fechatextoLa fecha ya interpretada, escrita como AAAA-MM-DD
anioenteroEl anio, con .dt.year
mesenteroEl mes 1 a 12, con .dt.month
vendedortextoTal cual vino, solo sin espacios en los extremos
productotextoTal cual vino, solo sin espacios en los extremos
unidadesenteroConvertido con to_numeric(errors='coerce'). NO se valida: puede quedar vacio o negativo
precio_unitariodecimalConvertido con to_numeric(errors='coerce') y redondeado a 2 decimales. NO se valida

Orden de las filas: fila_origen ascendente. Es unico por construccion, asi que no hace falta desempate. Indice: no se escribe: to_csv(index=False)

ventas_rechazadas.csv · 5 filas

ColumnaTipoQue lleva
fila_origenenteroPosicion de la fila descartada en el archivo de entrada
fecha_originaltextoEl valor de fecha tal cual venia, sin limpiar
motivotextoausente o fecha_invalida

Orden de las filas: fila_origen ascendente. Indice: no se escribe: to_csv(index=False)

Que hacer con cada defecto

DefectoDondeAccionAdonde va
fecha en formato dd/mm/aaaa (15/03/2026)1 fila, la 120recuperar recuperar con una SEGUNDA pasada de to_datetime, solo sobre lo que la primera no interpretoventas_fechadas.csv, con fecha 2026-03-15
fecha que no existe en el calendario (2026-02-30)1 fila, la 76descartar descartarventas_rechazadas.csv con motivo fecha_invalida
fecha vacia4 filas: 44, 89, 134 y 179descartar descartarventas_rechazadas.csv con motivo ausente
unidades vacia (1 fila) y negativas (2 filas)unidadesNO NO se validan en este ejercicio: se convierten y pasanventas_fechadas.csv, con el vacio como campo vacio
precio_unitario vacio y con el token N/A2 filasNO NO se valida en este ejercicio: to_numeric con coerce los deja ausentesventas_fechadas.csv, con el ausente como campo vacio
Orden de comprobacion

Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:

  1. primera pasada con format='%Y-%m-%d'
  2. segunda pasada con format='%d/%m/%Y', SOLO sobre las que quedaron sin interpretar y no estan vacias
  3. campo vacio -> ausente
  4. resto sin interpretar -> fecha_invalida

La segunda pasada tiene que correr solo sobre el resto. Si se aplicara al total, una fecha como 2026-03-02 podria reinterpretarse con el dia y el mes cambiados. Y el vacio se comprueba antes que fecha_invalida para que una fecha que falta no se informe como una fecha rota.

Conteos clave

Si estos numeros no te dan, algo se desvio antes de que llegues a comparar los archivos.

filas de entrada180
ventas_fechadas.csv175
ventas_rechazadas.csv5
recuperadas por la segunda pasada1
interpretadas en la primera pasada174
por motivoausente: 4, fecha_invalida: 1

Invariantes

Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:

len(fechadas) + len(rechazadas) == 180
fechadas['fila_origen'].is_unique
rechazadas['fila_origen'].is_unique
fechadas['anio'].eq(2026).all()
fechadas['mes'].between(1, 12).all()
(fechadas['fecha'].str.len() == 10).all()
set(rechazadas['motivo']) <= {'ausente', 'fecha_invalida'}
'2026-03-15' in set(fechadas['fecha'])
PISTASSi te trabas, abri esto
  • Sin format, to_datetime adivina. Con dos formatos mezclados eso es exactamente lo que no queres: declara el formato mayoritario y despues ocupate del resto.
  • errors='coerce' no levanta excepcion: deja NaT. Eso es lo que permite hacer la segunda pasada sobre lo que quedo.
  • 2026-02-30 no existe. Con coerce da NaT en silencio, y por eso hay que contarlo: nadie te va a avisar.
  • fillna sobre una Series de fechas rellena con la otra Series alineada por indice. Es la forma corta de juntar las dos pasadas.
  • fila_origen no esta en el archivo de entrada: hay que crearla. Sin ella no hay ninguna columna unica para ordenar.

Así tiene que quedar

ventas_fechadas.csv (objetivo) · 175 filas, se muestran 5
fila_origenfechaaniomesvendedorproductounidadesprecio_unitario
02026-03-0220263Carlos RuizAuriculares157.24
12026-03-2620263Carlos RuizAuriculares557.73
22026-03-3120263Beatriz MolinaAuriculares159.37
32026-02-0920262Lucía VegaWebcam645.42
42026-03-2720263Carlos RuizLaptop7914.44
ventas_rechazadas.csv (objetivo) · 5 filas, se muestran 5
fila_origenfecha_originalmotivo
44vacioausente
762026-02-30fecha_invalida
89vacioausente
134vacioausente
179vacioausente
Dos cosas que hay que decidir y que el contrato ya decidió por vos

Una. Una fecha vacía y una fecha que no existe son problemas distintos, y van con motivos distintos: ausente y fecha_invalida. Con errors="coerce" las dos terminan como NaT y se vuelven indistinguibles, así que hay que separarlas antes de convertir.

Dos. fila_origen no viene en el archivo: hay que crearla. Sin ella no hay ninguna columna única para ordenar, y dos soluciones correctas podrían entregar las filas en otro orden.

Lo que este ejercicio no hace

Hay unidades negativas y precios ausentes en el archivo, y pasan: se convierten y se escriben tal cual queden. No es un olvido, está en el contrato. Un ejercicio que decide sobre la fecha decide sobre la fecha; validar los importes es el trabajo de EJ-5.8.