1. Faro

Nivel 8 · Desafío final: la revisión de la temporada de fiestas

La solicitud

De Catherine Hale, Directora General

“Antes de planificar el próximo noviembre quiero la temporada de fiestas en cifras: nuestra mejor semana de 2025, cómo se compara un mes típico a lo largo del año, cómo le fue a este T4 frente al del año pasado, y qué parte de los ingresos de cada año cae en cada trimestre.”

Tu objetivo

Paso 1 de 4. Construye los ingresos diarios (cada día del calendario) y su suma móvil de 7 días (el día y los 6 días anteriores), calculada sobre todo el historial. Asigna a result un DataFrame con los 3 días de 2025 con la suma móvil de 7 días más alta: columnas order_date (el último día de la ventana), weekday (su nombre de día en inglés, p. ej. 'Thursday') y revenue_7d (redondeada a 2), ordenado por revenue_7d descendente, con el índice reiniciado.

  • Usa el DataFrame orderspendiente
  • Usa el DataFrame order_itemspendiente
  • Muestra exactamente order_date weekday revenue_7dpendiente

Paso 1 · tu código

Python

Cargando el editor…

    ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
    Vista previa de orders
    order_idcustomer_idorder_datestatuschannel
    10011252023-01-01 20:51:19completedweb
    10021562023-01-02 07:58:46completedweb
    1003222023-01-02 10:25:27completedmarketplace
    1004482023-01-02 11:21:51completedmarketplace

    Mote revisa tu resultado

    Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

    Paso 2 · tu código

    Python

    Cargando el editor…

      ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
      Vista previa de orders
      order_idcustomer_idorder_datestatuschannel
      10011252023-01-01 20:51:19completedweb
      10021562023-01-02 07:58:46completedweb
      1003222023-01-02 10:25:27completedmarketplace
      1004482023-01-02 11:21:51completedmarketplace

      Mote revisa tu resultado

      Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

      Paso 3 · tu código

      Python

      Cargando el editor…

        ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
        Vista previa de orders
        order_idcustomer_idorder_datestatuschannel
        10011252023-01-01 20:51:19completedweb
        10021562023-01-02 07:58:46completedweb
        1003222023-01-02 10:25:27completedmarketplace
        1004482023-01-02 11:21:51completedmarketplace

        Mote revisa tu resultado

        Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

        Paso 4 · tu código

        Python

        Cargando el editor…

          ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
          Vista previa de orders
          order_idcustomer_idorder_datestatuschannel
          10011252023-01-01 20:51:19completedweb
          10021562023-01-02 07:58:46completedweb
          1003222023-01-02 10:25:27completedmarketplace
          1004482023-01-02 11:21:51completedmarketplace

          Mote revisa tu resultado

          Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

          DataFrames

          Cargados como DataFrames de pandas, junto con pd y np.

          orders12,000 filas · 7 columnas
          • order_idinteger
          • customer_idinteger
          • order_datetimestamp
          • statusvarchar
          • channelvarchar
          • shipping_feedecimal
          • coupon_codevarchar
          Primeras 5 filas de orders
          order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
          10011252023-01-01 20:51:19completedweb0.00NaN
          10021562023-01-02 07:58:46completedweb0.00NaN
          1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
          1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
          1005822023-01-02 11:43:36completedweb0.00WELCOME10
          order_items30,338 filas · 6 columnas
          • order_item_idinteger
          • order_idinteger
          • product_idinteger
          • quantityinteger
          • unit_pricedecimal
          • discount_pctdecimal
          Primeras 5 filas de order_items
          order_item_idorder_idproduct_idquantityunit_pricediscount_pct
          11001121931.990.00
          21001154311.990.00
          31002154411.990.00
          410021941149.000.00
          51002193219.990.00
          customers2,018 filas · 9 columnas
          • customer_idinteger
          • first_namevarchar
          • last_namevarchar
          • emailvarchar
          • cityvarchar
          • statevarchar
          • signup_datedate
          • segmentvarchar
          • referral_sourcevarchar
          Primeras 5 filas de customers
          customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
          1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
          2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNaN
          3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNaN
          4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
          5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNaN
          products120 filas · 8 columnas
          • product_idinteger
          • namevarchar
          • categoryvarchar
          • subcategoryvarchar
          • unit_pricedecimal
          • unit_costdecimal
          • launched_ondate
          • is_activeboolean
          Primeras 5 filas de products
          product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
          101Vale Velvet LoveseatFurnitureSofas1659.00NaN2023-09-11true
          102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
          103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
          104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
          105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
          returns1,673 filas · 5 columnas
          • return_idinteger
          • order_item_idinteger
          • returned_ondate
          • reasonvarchar
          • refund_amountdecimal
          Primeras 5 filas de returns
          return_idorder_item_idreturned_onreasonrefund_amount
          1142023-01-10damaged83.69
          2422023-01-10wrong_item19.99
          31052023-01-14wrong_item10.99
          4242023-01-16changed_mind26.99
          51262023-01-16late20.99
          employees60 filas · 8 columnas
          • employee_idinteger
          • first_namevarchar
          • last_namevarchar
          • departmentvarchar
          • titlevarchar
          • manager_idinteger
          • hire_datedate
          • salaryinteger
          Primeras 5 filas de employees
          employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
          1CatherineHaleExecutiveChief Executive OfficerNaN2016-03-01285000
          2RobertKimExecutiveChief Operating Officer12017-01-09235000
          3MeganCollinsSalesHead of Sales12018-04-16172000
          4ChloeGutierrezSalesAccount Executive32020-01-2172000
          5FrankBellSalesAccount Executive32023-05-2173000
          web_sessions40,000 filas · 7 columnas
          • session_idinteger
          • customer_idinteger
          • started_attimestamp
          • devicevarchar
          • sourcevarchar
          • pages_viewedinteger
          • convertedboolean
          Primeras 5 filas de web_sessions
          session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
          1NaN2023-01-01 23:02:24mobilepaid1false
          2182023-01-01 15:07:49desktoppaid1false
          3NaN2023-01-01 16:55:46desktopdirect7false
          4NaN2023-01-01 12:43:28mobileorganic3false
          5NaN2023-01-01 13:06:21mobilesocial2false
          marketing_spend3,276 filas · 3 columnas
          • spend_datedate
          • channelvarchar
          • amountdecimal
          Primeras 5 filas de marketing_spend
          spend_datechannelamount
          2023-01-01paid492.99
          2023-01-01email37.38
          2023-01-01social200.53
          2023-01-02paid709.13
          2023-01-02email64.13

          La lección

          Una tabla, cuatro vistas del tiempo

          Cada paso parte de lines: una fila por línea de pedido de un pedido completado, con su line_revenue y el order_date del pedido. A partir de ahí, el tiempo se puede cortar de dos maneras. Resampling mete las filas en periodos consecutivos de una línea temporal (2 de diciembre de 2025, la semana que termina en él, noviembre de 2025). Las partes de fecha extraen una pieza de cada fecha (su día de la semana, su mes del año, su trimestre) para poder agrupar filas de años distintos. El desafío necesita ambas.

          Partes de fecha con .dt

          El accesor .dt extrae partes de una columna datetime:

          d = lines["order_date"]
          d.dt.year           # 2025
          d.dt.quarter        # 1 to 4
          d.dt.month          # 1 to 12
          d.dt.month_name()   # 'November'
          d.dt.day_name()     # 'Friday'

          year, quarter y month son atributos (sin paréntesis) y devuelven números; month_name() y day_name() son métodos y devuelven texto. Para cualquier otra etiqueta, strftime da formato a una fecha con códigos: "%Y-%m" da '2025-11', "%b" da 'Nov', "%B" el nombre completo, "%a" un día de la semana abreviado. En un DatetimeIndex los mismos métodos están disponibles directamente, sin .dt: table.index.strftime("%b").

          Meses en orden de calendario

          Los nombres de mes son texto, y el texto se ordena alfabéticamente: April, August, December… Para mantener el orden de calendario, lleva el número del mes junto al nombre y ordena por el número:

          parts = lines.assign(month_num=lines["order_date"].dt.month, month=lines["order_date"].dt.month_name())
          parts.groupby(["month_num", "month"], as_index=False)["line_revenue"].sum().sort_values("month_num")

          Agrupar por ambas claves no cuesta nada (cada número tiene un nombre) y te da una columna por la que ordenar. Otra opción es una categórica ordenada, pd.Categorical(names, categories=[...], ordered=True), pero un número de mes es más simple y sobrevive a cualquier merge.

          Promediar un mes a lo largo de tres años necesita dos pasos: primero sumar por año y mes, y luego promediar esos totales. Promediar las líneas directamente daría la línea de pedido media, no el mes medio.

          Ventanas móviles y crecimiento, primero el historial

          La mejor semana de 2025 es una suma móvil de 7 días sobre una serie diaria, construida sobre todo el historial y filtrada a 2025 después. Termina el jueves 4 de diciembre de 2025 con $104,267.39, cuando la ventana contiene todo el tramo del Black Friday al Cyber Monday. En 2024 la mejor ventana fue mayor, $117,208.44.

          La misma regla se aplica al crecimiento interanual: pct_change(12) necesita los meses de 2024 en la serie, así que selecciona el T4 de 2025 solo al final. La respuesta es incómoda: los ingresos de noviembre de 2025 cayeron un 8,4 % respecto a noviembre de 2024 aunque el número de pedidos creció un 13,7 %, el tipo de resultado que se informa con franqueza, con el recuento de pedidos al lado.

          Cuotas de cada año

          transform("sum") devuelve el total del grupo en cada fila del grupo, así que la cuota de un trimestre en su año es una división. El T4 aportó 0.375 de los ingresos de 2023, 0.381 de los de 2024 y 0.328 de los de 2025.

          Errores comunes

          • Ordenar los nombres de los meses alfabéticamente en lugar de por número de mes.
          • Escribir dt.month_name sin paréntesis, lo que da un método, no nombres.
          • Filtrar a 2025 antes de rolling o pct_change(12), lo que convierte el inicio del periodo en NaN.
          • Dividir entre el total general de todos los años en lugar del total propio de cada año.

          Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.