1. Faro

Nivel 6 · Encuentra y rellena los huecos de seguimiento

La solicitud

De Jordan Reyes, Director de Marketing

“Nuestro registro de gasto tuvo algunas caídas, así que algunos días no tienen fila para un canal. El dinero se gastó igualmente. ¿Cuántos días faltan por canal, y cuál es el total si trasladamos el gasto del día anterior a cada hueco?”

Tu objetivo

marketing_spend debería tener una fila por día y canal de 2023-01-01 a 2025-12-31. Asigna a result un DataFrame con las columnas channel, missing_days (días de ese rango sin fila para el canal), recorded_total (suma de amount tal como se registró, redondeada a 2) y filled_total (suma tras rellenar cada día ausente con el amount del día anterior de ese canal, redondeada a 2), una fila por canal, ordenado por channel de la A a la Z, con el índice reiniciado.

  • Usa el DataFrame marketing_spendpendiente
  • Muestra exactamente channel missing_days recorded_total filled_totalpendiente
  • 3 filas, ordenadas como se pidependiente

Tu código

Python

Cargando el editor…

    ResultadoVista previa de marketing_spend · presiona Ejecutar para ver el tuyo
    Vista previa de marketing_spend
    spend_datechannelamount
    2023-01-01paid492.99
    2023-01-01email37.38
    2023-01-01social200.53
    2023-01-02paid709.13

    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.

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

    La lección

    Las filas ausentes son invisibles

    Un valor ausente que puedes ver es fácil: es NaN, y isna() lo encuentra. Una fila ausente es más difícil. Si el registro tuvo una caída el 28 de enero de 2023, simplemente no hay fila de paid para ese día, y nada en la tabla te lo dice. resample y rolling pasan alegremente sobre el agujero, y una ventana rolling(7) cubre en silencio 8 días del calendario.

    La solución es colocar los datos en un calendario completo, de modo que cada día que debería existir tenga una fila, y los ausentes aparezcan como NaN.

    asfreq para una serie

    Para una sola serie con un DatetimeIndex, asfreq("D") lo hace en una llamada:

    paid = marketing_spend[marketing_spend["channel"] == "paid"].set_index("spend_date")["amount"]
    len(paid)                 # 1091
    filled = paid.asfreq("D")
    len(filled)               # 1096
    filled.isna().sum()       # 5

    asfreq construye un índice diario regular desde la primera hasta la última fecha e inserta NaN donde no había fila. Tres años son 1.096 días (2024 es bisiesto), así que al canal paid le faltan 5 días.

    reindex con date_range para muchas columnas

    asfreq solo rellena entre la primera y la última fecha presentes. Si faltara toda la primera semana, no podría saberlo. pd.date_range te permite indicar explícitamente el calendario esperado, y reindex coloca la tabla en él:

    days = pd.date_range("2023-01-01", "2025-12-31", freq="D")
    wide = marketing_spend.pivot(index="spend_date", columns="channel", values="amount").reindex(days)
    wide.isna().sum()
    # email 4, paid 5, social 3

    pivot convierte la tabla larga en una columna por canal (el capítulo 9 lo cubre en profundidad), así que los tres canales se comprueban a la vez contra el mismo calendario.

    Elegir un relleno

    Cuando los huecos son visibles, tú decides qué significan. Para el gasto de paid, la media diaria sale distinta según esa elección:

    • Omitirlos (el valor por defecto de mean() y sum()): media de $814.64 sobre los 1.091 días registrados.
    • fillna(0): “no se gastó nada”. Media de $810.93 sobre 1.096 días. Incorrecto aquí: el dinero se gastó, solo falló el registro.
    • ffill(): traslada el último valor conocido hacia delante. El total sube de $888,774.13 a $892,327.94.
    • interpolate(): una línea recta entre los vecinos, total $892,420.97.

    Cero es correcto cuando un día ausente significa realmente cero (sin pedidos en un día de cierre). El relleno hacia delante o la interpolación es correcto cuando el valor existió pero no se registró. Di cuál usaste.

    Errores comunes

    • Ejecutar rolling(7) en una serie con días ausentes, de modo que la ventana es más larga que una semana.
    • Usar fillna(0) para una caída, lo que subestima el gasto y sobrestima el retorno de la inversión publicitaria.
    • Usar asfreq cuando los huecos pueden estar justo al principio o al final del rango; reindex con un date_range explícito los detecta.
    • Olvidar que sum() y mean() omiten los NaN, así que una tabla con huecos igualmente “suma”, pero a una cifra equivocada.

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