Ir al contenido
wannacode

Fechas y series temporales

En resumen: Una serie temporal son datos ordenados por fecha; en pandas el texto pasa a fecha con to_datetime, resample los agrupa por día, semana y mes, y rolling da una media móvil.

Problema

«¿Cómo va el año?»

La tienda tiene los pedidos de un año entero: de noviembre de 2025 a finales de octubre de 2026. El gerente pregunta qué mes es el más fuerte, qué día de la semana vende más y cómo cambian los ingresos de un mes a otro.

Pythondatos: las tablas de la tienda

Hay 11 116 pedidos. Pero la columna ordered_at es str: para pandas, «2025-11-01 07:20» es solo texto. De ahí no puedes sacar el mes:

Pythondatos: las tablas de la tienda

La idea

El texto pasa a fecha

parse_dates le dice a read_csv qué columnas leer como fechas. pd.to_datetime(orders['ordered_at']) hace lo mismo con una columna existente, como viste en la lección sobre tipos:

Pythondatos: las tablas de la tienda

El tipo es datetime64: un instante en el tiempo, con fecha y hora. Con él puedes comparar, restar y tomar partes. La diferencia entre el último y el primer pedido es de 364 días, 15 horas y 41 minutos. Es una diferencia de tiempo (Timedelta), no un número.

Una tabla en la que cada fila es un instante o un período, y las filas siguen el tiempo, se llama serie temporal.

La idea

Partes de la fecha: .dt

.dt da las partes de cada fecha de la columna: year, month, day, hour, dayofweek (0 es lunes), day_name(). ¿Cuándo durante el día se pide más?

Pythondatos: las tablas de la tienda

Hay dos picos: a mediodía (entre las 12 y las 14 h, unos 800 pedidos por hora) y por la noche (entre las 19 y las 21 h, unos 1200 por hora). Por la mañana y muy tarde por la noche hay menos de la mitad.

day_name() da los nombres en inglés («Saturday»). Los nombres en español los pondrás tú mismo con un diccionario, un poco más adelante.

La idea

Filtrar por fecha

Una columna de fechas se puede comparar con texto como «2025-12-01»: pandas lo convierte en fecha. Los pedidos de diciembre:

Pythondatos: las tablas de la tienda

La respuesta correcta es 1285. Con <= '2025-12-31' obtienes 1250, y el último pedido entre ellos es del 30 de diciembre. El motivo es la hora: «2025-12-31» es el 31 de diciembre a las 00:00, y todos los pedidos del 31 llegan después de la medianoche.

Por eso, para un período escribes «desde el primer día, incluido, hasta el primer día del período siguiente, excluido»: >= '2025-12-01' y < '2026-01-01'.

Pruébalo

La semana antes de Navidad

¿Cuántos pedidos hay del 22 al 28 de diciembre de 2025, ambos incluidos? Guarda esos pedidos en week.

Pythondatos: las tablas de la tienda

La idea

Por mes: resample

Para los ingresos por mes necesitas primero los ingresos de cada pedido. Son la suma de sus líneas: groupby sobre order_id, y después merge con los pedidos. Los pedidos cancelados no son ingresos, así que sold los deja fuera.

Después resample agrupa las filas en períodos de tiempo. Es un groupby cuyos grupos son períodos: días ('D'), semanas ('W'), meses ('MS'). Trabaja sobre un índice de fechas, así que primero set_index('ordered_at'):

Pythondatos: las tablas de la tienda

Diciembre es el mes más fuerte: 15 915,90 €. Enero (7228,20 €) y febrero (7622,30 €) son flojos, como suele pasar después de las fiestas. El más flojo, sin embargo, es septiembre: 7128,80 €. Por qué, lo descubriremos en el proyecto del final del curso.

Más precisamente, para curiosos

'MS' (month start) etiqueta cada mes con su primer día, y 'ME' (month end) con el último. Las sumas son las mismas.

'W' etiqueta cada semana con el domingo en que termina. La primera semana aquí es solo el 1 y el 2 de noviembre (sábado y domingo), así que es mucho más pequeña que las demás. El primer y el último período suelen estar incompletos: compruébalos antes de compararlos.

Si un día no hay pedidos, resample('D').sum() da igualmente la fila, con 0. En estos datos todos los días tienen pedidos.

Pruébalo

La semana más fuerte

¿Qué semana aportó más ingresos? Guarda los ingresos por semana (sin los pedidos cancelados) en weekly, y la fecha de la semana más fuerte en best_week.

Pythondatos: las tablas de la tienda

La idea

Media móvil: rolling

Los ingresos diarios suben y bajan: altos los viernes, bajos los domingos. Detrás de ese ruido es difícil ver si las cosas van hacia arriba. Una media móvil calcula, para cada día, el promedio de los últimos 7 días, incluido ese día:

Pythondatos: las tablas de la tienda

rolling(7) es una ventana de 7 filas que se desliza hacia abajo una fila cada vez. Los primeros 6 valores son NaN: antes del 7 de noviembre no hay 7 días hacia atrás. El 7 de noviembre el promedio de los primeros siete días es 374,23 €. Después, cada día entra un día nuevo y sale el más antiguo, así que la línea cambia con suavidad.

La idea

Día de la semana

¿Cuáles son los ingresos medios un lunes, un martes y así sucesivamente? Agrupas los ingresos diarios por el número del día del índice, daily.index.dayofweek, y tomas la media. Agrupas por el número y no por day_name(), porque los nombres se ordenan alfabéticamente y el viernes saldría primero. Después un diccionario (y map) da a los números sus nombres:

Pythondatos: las tablas de la tienda

El viernes es el más fuerte: 350,79 € de media. El domingo es el más flojo: 250,85 €. Este es el ritmo semanal que rolling(7) suaviza: una ventana de 7 días contiene cada día de la semana exactamente una vez.

Aquí el índice ya está hecho de fechas, así que dayofweek va directamente sobre el índice. Para una columna escribes .dt.dayofweek.

1. ¿Por qué la media móvil de los ingresos diarios usa una ventana de 7, y no de 5 o de 10?

La idea

Mes a mes: pct_change

El gerente no pregunta «cuánto», sino «cuánto más o menos que el mes pasado». pct_change() divide cada valor entre el anterior y resta 1: da el cambio como proporción. Multiplicado por 100, es un porcentaje:

Pythondatos: las tablas de la tienda

Noviembre es NaN: no hay ningún mes antes. Diciembre está un 71,2 % por encima de noviembre, y enero está un 54,6 % por debajo de diciembre. Septiembre está un 19,1 % por debajo de agosto, y octubre vuelve a subir un 39,2 %.

Si la caída de septiembre es real o solo ruido, y qué la causó, es la pregunta del proyecto. Por ahora sabes que está ahí y cuánto es.

Ejercicio

¿Cuándo se encareció el café?

El café en grano (producto 17) se encareció en algún momento del año. Guarda en price_by_month el precio medio del café de cada mes (en el orden de los meses en el tiempo), y en first_new la fecha y hora de la primera venta al precio nuevo de 14.9.

Pythondatos: las tablas de la tienda

Test

Ponte a prueba

1. La columna ordered_at tiene una fecha y una hora. ¿Por qué para los pedidos de diciembre escribes < "2026-01-01" y no <= "2025-12-31"?
2. ¿Qué necesita la tabla para que resample("MS") funcione?
3. ¿Por qué los primeros 6 valores de daily.rolling(7).mean() son NaN?
4. Los ingresos son 8812,70 € en agosto y 7128,80 € en septiembre. ¿Qué da pct_change() para septiembre, por 100 y redondeado?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·