1. Faro

Nivel 9 · Desafío final: el panel de marketing

La solicitud

De Jordan Reyes, Director de Marketing

“Es temporada de presupuestos. Necesito una figura para mi diapositiva: lo que gastamos por canal cada mes de 2025, qué fuentes de tráfico convierten, y cuánto nos cuesta una conversión por canal. Cuatro gráficos, una imagen.”

Tu objetivo

Paso 1 de 3. Asigna a result un DataFrame del gasto de marketing de 2025 con una fila por mes y las columnas month (primer día del mes, una fecha), email, paid y social (suma de amount, redondeada a 2), ordenado por month. Dibújalo como un gráfico de líneas.

  • Usa el DataFrame marketing_spendpendiente
  • Muestra exactamente month email paid socialpendiente
  • 12 filas, ordenadas como se pidependiente

Paso 1 · 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.

    Paso 2 · tu código

    Python

    Cargando el editor…

      ResultadoVista previa de web_sessions · presiona Ejecutar para ver el tuyo
      Vista previa de web_sessions
      session_idcustomer_idstarted_atdevicesource
      1NaN2023-01-01 23:02:24mobilepaid
      2182023-01-01 15:07:49desktoppaid
      3NaN2023-01-01 16:55:46desktopdirect
      4NaN2023-01-01 12:43:28mobileorganic

      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 web_sessions · presiona Ejecutar para ver el tuyo
        Vista previa de web_sessions
        session_idcustomer_idstarted_atdevicesource
        1NaN2023-01-01 23:02:24mobilepaid
        2182023-01-01 15:07:49desktoppaid
        3NaN2023-01-01 16:55:46desktopdirect
        4NaN2023-01-01 12:43:28mobileorganic

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

        La lección

        Un panel es una cuadrícula de Axes

        plt.subplots(rows, cols) crea una Figure con una cuadrícula de Axes y los devuelve como un array bidimensional:

        fig, axs = plt.subplots(2, 2, figsize=(12, 8))
        axs[0, 0].plot(...)     # top left
        axs[0, 1].barh(...)     # top right
        axs[1, 0].bar(...)      # bottom left
        axs[1, 1].hist(...)     # bottom right
        fig.suptitle("One title for the whole figure")
        plt.tight_layout()      # stops titles and labels from overlapping

        Las filas y las columnas se cuentan desde 0. Los gráficos de pandas pueden ir a una celda elegida con ax=: monthly.plot(ax=axs[0, 0]). Cuando dos gráficos deban compararse por altura, crea la cuadrícula con sharey=True para que usen la misma escala.

        Las tres tablas

        Gasto por mes. marketing_spend tiene una fila por día y canal. Una columna de mes y un pivot dan los meses en vertical y los canales en horizontal. En 2025 el gasto de paid rondó los $21,000 a $28,000 al mes de enero a octubre y saltó a $47,475.61 en noviembre.

        Conversión por fuente. Cada sesión tiene una source y un booleano converted. Sumar un booleano cuenta los valores True, y la media de un booleano es la proporción de True. En 2025 convirtió el 9,6 % de las sesiones de email, el 5,4 % de direct, el 1,8 % de organic, el 1,5 % de paid y el 0,7 % de social.

        Coste por conversión. Divide el gasto de cada canal entre las conversiones que produjeron sus sesiones. Los nombres de canal de marketing_spend (email, paid, social) coinciden con los valores de source de web_sessions, así que tras renombrar source a channel las dos tablas pequeñas se unen uno a uno. El tráfico organic y direct no tiene gasto, y el merge inner los deja fuera.

        cpc = spent.merge(conv, on="channel")
        cpc["cost_per_conversion"] = cpc["spend"] / cpc["conversions"]

        Email: $38,322.22 por 187 conversiones, $204.93 cada una. Paid: $340,778.33 por 55, $6,195.97 cada una. Social: $131,540.77 por 19, $6,923.20 cada una. Las sesiones no están enlazadas con pedidos en estos datos, así que una conversión aquí es una sesión convertida, no ingresos. Una diapositiva cuidadosa lo dice en una nota al pie.

        Guardar la figura

        En un notebook guardarías el panel para la diapositiva con fig.savefig("marketing_2025.png", dpi=150, bbox_inches="tight"). Llámalo antes de plt.show(): después de show, la figura se cierra y el archivo guardado sale en blanco. Aquí la página muestra tu figura automáticamente, así que no necesitas ninguna de las dos llamadas.

        Errores comunes

        • Comparar gasto y conversiones de periodos distintos (gasto de 2025 contra sesiones de todos los años).
        • Dividir el gasto entre todas las sesiones: eso es coste por visita, una cifra distinta y mucho menor.
        • Olvidar plt.tight_layout(), de modo que los títulos de los gráficos inferiores se solapan con las etiquetas de los ejes superiores.
        • Escribir axs[0][0] y axs[0, 0] indistintamente está bien, pero axs[1] solo es una fila entera.

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