1. Faro

Nivel 2 · Construye la revisión mensual en pandas

La solicitud

De Laura Bennett, Directora de Finanzas

“Acordamos noviembre de 2025, junto a octubre y a noviembre del año pasado. Antes de construir la tabla, muéstrame en números que noviembre se ha asentado y diciembre no, para poder explicar por qué nos saltamos el último mes.”

Tu objetivo

Paso 1 de 3. Verifica los meses. Para los pedidos hechos del 1 de septiembre al 31 de diciembre de 2025, asigna a result un DataFrame con las columnas month, orders (todos los pedidos), completed, cancelled, refunded y pending (pedidos con cada estado), ordenado por month, con índice por defecto.

  • Usa el DataFrame orderspendiente
  • Muestra exactamente month orders completed cancelled refunded pendingpendiente
  • 4 filas, ordenadas como se pidependiente

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 order_items · presiona Ejecutar para ver el tuyo
      Vista previa de order_items
      order_item_idorder_idproduct_idquantityunit_price
      11001121931.99
      21001154311.99
      31002154411.99
      410021941149.00

      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 order_items · presiona Ejecutar para ver el tuyo
        Vista previa de order_items
        order_item_idorder_idproduct_idquantityunit_price
        11001121931.99
        21001154311.99
        31002154411.99
        410021941149.00

        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
        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
        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
        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
        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
        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

        Qué estás verificando y por qué

        Un mes está listo para informarse solo cuando sus pedidos se han asentado. Los pedidos llegan como pending y pasan a completed, cancelled o refunded en los días siguientes. Una tabulación cruzada de mes contra estado muestra dónde están los pedidos abiertos:

        counts = pd.crosstab(o["month"], o["status"])

        Noviembre tiene 2 pedidos pendientes de 715; diciembre tiene 94 de 777. Esa es la evidencia detrás de informar de noviembre.

        Una tabla por fuente

        Los KPI vienen de tres tablas con tres granularidades: líneas de pedido, devoluciones y sesiones web. El patrón seguro es llevar cada una a una fila por mes, indexada por mes, y luego aplicar join:

        sales = lines.groupby("month").agg(revenue=("revenue", "sum"), orders=("order_id", "nunique"), ...)
        refunds = returns.groupby(returns["returned_on"].dt.strftime("%Y-%m"))["refund_amount"].sum()
        kpi = sales.join(refunds.rename("refunds")).join(web)

        Los compradores nuevos necesitan un paso más. “Nuevo” significa que el primer pedido completado del cliente cae en el mes. transform("min") pone la fecha del primer pedido de cada cliente en cada una de sus líneas, y .where() conserva el customer_id solo en las líneas de ese primer mes, así que nunique() del resultado cuenta los compradores nuevos.

        Cómo leer el resultado

        month net_revenue orders avg_order_value buyers web_conversion_pct
        2024-11 319,297.22 564 566.13 357 3.50
        2025-10 174,599.43 333 524.32 261 2.33
        2025-11 292,364.40 651 449.10 442 4.45

        Frente a octubre todo sube, como cada noviembre. Frente al año pasado, el volumen creció y los ingresos cayeron, así que la pregunta pasa a ser el valor medio del pedido. El paso 3 la responde: siete pedidos voluminosos el noviembre pasado, uno este noviembre.

        Explicar el cambio

        El paso 3 trabaja a nivel de pedido, porque el tamaño de un pedido solo se conoce una vez que sus líneas se han sumado. Agrupa las líneas por mes y pedido, etiqueta cada pedido con np.where y luego agrupa los pedidos por mes y banda. El resultado divide cada noviembre en unos pocos pedidos grandes y muchos regulares, que es el desglose que convierte “los ingresos cayeron” en una razón sobre la que la dirección puede actuar.

        Trampas

        • groupby sobre una Series calculada (returns["returned_on"].dt.strftime(...)) funciona sin añadir antes una columna; el resultado queda indexado por las etiquetas de mes.
        • Sumar buyers entre meses cuenta dos veces a las personas que compraron en ambos.
        • .loc[["2024-11", ...]] lanza un KeyError si falta un mes en una fuente; join conserva los meses de ventas y deja NaN donde otra fuente no tiene ninguno.

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