La solicitud

De Jordan Reyes, Director de Marketing
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
monthemailpaidsocialpendiente - 12 filas, ordenadas como se pidependiente
Paso 2 de 3. Usando las sesiones web iniciadas en 2025, asigna a result un DataFrame con las columnas source, sessions (número de sesiones), conversions (número de sesiones convertidas) y conv_rate (conversions / sessions, redondeada a 3), una fila por fuente, ordenado por conv_rate de mayor a menor, con el índice reiniciado. Dibuja conv_rate como un gráfico de barras horizontal con la mejor fuente arriba.
- Usa el DataFrame
web_sessionspendiente - Muestra exactamente
sourcesessionsconversionsconv_ratependiente - 5 filas, ordenadas como se pidependiente
Paso 3 de 3. Para 2025, asigna a result un DataFrame con las columnas channel (email, paid, social), spend (suma del amount de marketing_spend, redondeada a 2), conversions (sesiones web convertidas cuya source es igual al canal) y cost_per_conversion (spend / conversions, redondeada a 2), ordenado por cost_per_conversion de menor a mayor, con el índice reiniciado. Luego dibuja el panel 2×2: gasto por mes, tasa de conversión por fuente, coste por conversión por canal, y un cuarto gráfico a tu elección.
- Usa el DataFrame
web_sessionspendiente - Usa el DataFrame
marketing_spendpendiente - Muestra exactamente
channelspendconversionscost_per_conversionpendiente
Paso 1 · tu código
Cargando el editor…
Solución de referencia
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.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
Cargando el editor…
Solución de referencia
| session_id | customer_id | started_at | device | source |
|---|---|---|---|---|
| 1 | NaN | 2023-01-01 23:02:24 | mobile | paid |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid |
| 3 | NaN | 2023-01-01 16:55:46 | desktop | direct |
| 4 | NaN | 2023-01-01 12:43:28 | mobile | organic |
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
Cargando el editor…
Solución de referencia
| session_id | customer_id | started_at | device | source |
|---|---|---|---|---|
| 1 | NaN | 2023-01-01 23:02:24 | mobile | paid |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid |
| 3 | NaN | 2023-01-01 16:55:46 | desktop | direct |
| 4 | NaN | 2023-01-01 12:43:28 | mobile | organic |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Jordan, y por qué
DataFrames
Cargados como DataFrames de pandas, junto con pd y np.
marketing_spend3,276 filas · 3 columnas
spend_datedatechannelvarcharamountdecimal
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.13 |
| 2023-01-02 | 64.13 |
web_sessions40,000 filas · 7 columnas
session_idintegercustomer_idintegerstarted_attimestampdevicevarcharsourcevarcharpages_viewedintegerconvertedboolean
| session_id | customer_id | started_at | device | source | pages_viewed | converted |
|---|---|---|---|---|---|---|
| 1 | NaN | 2023-01-01 23:02:24 | mobile | paid | 1 | false |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid | 1 | false |
| 3 | NaN | 2023-01-01 16:55:46 | desktop | direct | 7 | false |
| 4 | NaN | 2023-01-01 12:43:28 | mobile | organic | 3 | false |
| 5 | NaN | 2023-01-01 13:06:21 | mobile | social | 2 | false |
customers2,018 filas · 9 columnas
customer_idintegerfirst_namevarcharlast_namevarcharemailvarcharcityvarcharstatevarcharsignup_datedatesegmentvarcharreferral_sourcevarchar
| customer_id | first_name | last_name | city | state | signup_date | segment | referral_source | |
|---|---|---|---|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco | CA | 2022-06-02 | consumer | search |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta | GA | 2022-06-02 | consumer | NaN |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles | CA | 2022-06-04 | business | NaN |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle | WA | 2022-06-06 | business | |
| 5 | Kyle | Jimenez | kjimenez27@yahoo.com | Indianapolis | IN | 2022-06-07 | consumer | NaN |
products120 filas · 8 columnas
product_idintegernamevarcharcategoryvarcharsubcategoryvarcharunit_pricedecimalunit_costdecimallaunched_ondateis_activeboolean
| product_id | name | category | subcategory | unit_price | unit_cost | launched_on | is_active |
|---|---|---|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 | NaN | 2023-09-11 | true |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 | 503.50 | 2024-05-16 | true |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 | 429.87 | 2023-05-27 | true |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 | 214.70 | 2022-12-20 | true |
| 105 | Avery Leather Bed Frame | Furniture | Beds | 449.00 | 232.70 | 2021-08-31 | true |
orders12,000 filas · 7 columnas
order_idintegercustomer_idintegerorder_datetimestampstatusvarcharchannelvarcharshipping_feedecimalcoupon_codevarchar
| order_id | customer_id | order_date | status | channel | shipping_fee | coupon_code |
|---|---|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web | 0.00 | NaN |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web | 0.00 | NaN |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace | 4.99 | WELCOME10 |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace | 4.99 | WELCOME10 |
| 1005 | 82 | 2023-01-02 11:43:36 | completed | web | 0.00 | WELCOME10 |
order_items30,338 filas · 6 columnas
order_item_idintegerorder_idintegerproduct_idintegerquantityintegerunit_pricedecimaldiscount_pctdecimal
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct |
|---|---|---|---|---|---|
| 1 | 1001 | 121 | 9 | 31.99 | 0.00 |
| 2 | 1001 | 154 | 3 | 11.99 | 0.00 |
| 3 | 1002 | 154 | 4 | 11.99 | 0.00 |
| 4 | 1002 | 194 | 1 | 149.00 | 0.00 |
| 5 | 1002 | 193 | 2 | 19.99 | 0.00 |
returns1,673 filas · 5 columnas
return_idintegerorder_item_idintegerreturned_ondatereasonvarcharrefund_amountdecimal
| return_id | order_item_id | returned_on | reason | refund_amount |
|---|---|---|---|---|
| 1 | 14 | 2023-01-10 | damaged | 83.69 |
| 2 | 42 | 2023-01-10 | wrong_item | 19.99 |
| 3 | 105 | 2023-01-14 | wrong_item | 10.99 |
| 4 | 24 | 2023-01-16 | changed_mind | 26.99 |
| 5 | 126 | 2023-01-16 | late | 20.99 |
employees60 filas · 8 columnas
employee_idintegerfirst_namevarcharlast_namevarchardepartmentvarchartitlevarcharmanager_idintegerhire_datedatesalaryinteger
| employee_id | first_name | last_name | department | title | manager_id | hire_date | salary |
|---|---|---|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer | NaN | 2016-03-01 | 285000 |
| 2 | Robert | Kim | Executive | Chief Operating Officer | 1 | 2017-01-09 | 235000 |
| 3 | Megan | Collins | Sales | Head of Sales | 1 | 2018-04-16 | 172000 |
| 4 | Chloe | Gutierrez | Sales | Account Executive | 3 | 2020-01-21 | 72000 |
| 5 | Frank | Bell | Sales | Account Executive | 3 | 2023-05-21 | 73000 |
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]yaxs[0, 0]indistintamente está bien, peroaxs[1]solo es una fila entera.
¡Linterna encendida!
Practicaste: subplotsdashboardline chartbar chartcost per conversion
- Resuelto
- Sin pistas
- Al primer intento
