La solicitud

De Catherine Hale, Directora General
Tu objetivo
Paso 1 de 4. Asigna a result un DataFrame con una fila por canal y las columnas channel, business y consumer: el valor de pedido mediano de ese canal y segmento, redondeado a 2, ordenado por channel de la A a la Z. Dibújalo como un heatmap anotado.
- Usa el DataFrame
customerspendiente - Usa el DataFrame
orderspendiente - Muestra exactamente
channelbusinessconsumerpendiente
Paso 2 de 4. Asigna a result un DataFrame con las columnas channel, median_value, q1 y q3 (la mediana, el percentil 25 y el percentil 75 del valor de pedido por canal, todos los segmentos juntos, redondeados a 2), ordenado por median_value de mayor a menor, con el índice reiniciado. Dibuja boxplots del valor de pedido por canal en ese orden, divididos por segmento con hue.
- Usa el DataFrame
customerspendiente - Usa el DataFrame
orderspendiente - Muestra exactamente
channelmedian_valueq1q3pendiente
Paso 3 de 4. Exporta la tabla del paso 1 (columnas channel, business, consumer, redondeadas a 2, ordenadas por channel) como texto CSV: asigna a result la cadena que devuelve to_csv(index=False).
- Usa el DataFrame
customerspendiente - Usa el DataFrame
orderspendiente - Guarda un texto (str) en
resultpendiente
Paso 4 de 4. Asigna a result esta frase (se escribe en inglés tal cual, porque es lo que comprueba el juego), con las cifras calculadas en código: "In 2025 the median order barely depended on the channel (${LOW} on {LOW_CH} to ${HIGH} on {HIGH_CH}), but a business order was {RATIO} times a consumer order, so target big baskets by customer segment, not by channel." LOW/HIGH son las medianas de canal más baja y más alta (todos los segmentos) con formato :,.0f, LOW_CH/HIGH_CH sus nombres de canal, y RATIO es la mediana de business dividida entre la mediana de consumer (todos los canales) con formato :.1f.
- Usa el DataFrame
customerspendiente - Usa el DataFrame
orderspendiente - Guarda un texto (str) en
resultpendiente
Paso 1 · tu código
Cargando el editor…
Solución de referencia
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
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
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
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
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
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
Cargando el editor…
Solución de referencia
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Catherine, y por qué
DataFrames
Cargados como DataFrames de pandas, junto con pd y np.
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 |
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 |
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 |
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 |
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 |
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 |
La lección
Dividir por el segundo factor
La junta compara canales. Pero la cesta media de un canal depende de quién compra allí. Si los clientes business prefirieran un canal, ese canal parecería mejor por una razón que no tiene nada que ver con el canal en sí. La comprobación es dividir por el segundo factor y ver dónde están realmente las diferencias.
Un pivot con canales en vertical y segmentos en horizontal hace exactamente eso, y un mapa de calor lo hace legible:
grid = per_order.pivot_table(index="channel", columns="segment", values="value", aggfunc="median")
sns.heatmap(grid, annot=True, fmt=",.0f", cmap="Blues", cbar_kws={"label": "Median order (USD)"})
Usa una paleta secuencial como Blues para valores todos positivos, clara para los bajos y
oscura para los altos. Reserva la divergente coolwarm para números con signo, como las correlaciones.
Dispersión, no solo el centro
Una mediana por celda puede ocultar dispersiones muy distintas, así que dibuja también las cajas.
hue="segment" divide en dos la caja de cada canal:
sns.boxplot(data=per_order, x="channel", y="value", hue="segment", order=order, showfliers=False)
showfliers=False oculta los puntos atípicos para que las cajas no queden aplastadas por unos pocos
pedidos enormes. Dilo en la etiqueta del eje, ya que estás ocultando datos de la imagen (no de las cifras).
Un panel en seaborn
Las funciones de seaborn aceptan un argumento ax=, así que una cuadrícula de plt.subplots
contiene gráficos de seaborn con tanta facilidad como los de matplotlib:
fig, axs = plt.subplots(1, 2, figsize=(13, 4.5))
sns.heatmap(grid, annot=True, fmt=",.0f", cmap="Blues", ax=axs[0])
sns.boxplot(data=per_order, x="channel", y="value", hue="segment", showfliers=False, ax=axs[1])
plt.tight_layout()
Exportar y redactar
Tus compañeros reciben la tabla como un archivo: to_csv(path, index=False) escribe CSV,
to_excel una hoja de Excel (necesita el paquete openpyxl), to_parquet un archivo compacto y
tipado para datos grandes. Sin ruta, to_csv devuelve el texto, lo cual es práctico para comprobar lo que escribirías.
Luego la frase. Las medianas por canal van de $249 en marketplace a $263 en web, una diferencia de aproximadamente el 5 %. La mediana de un pedido business es unas 3,8 veces la de un pedido consumer. Qué: el canal casi no importa. Cuánto: $249 a $263, frente a 3,8 veces. Para qué: segmenta por segmento.
Errores comunes
- Comparar canales sin dividir por segmento, y atribuir al canal el mérito de sus clientes.
- Una paleta divergente para valores todos positivos, que sugiere un punto medio con significado que no existe.
- Escribir las cifras en la conclusión a mano en lugar de darles formato desde los datos.
¡Linterna encendida!
Practicaste: heatmappivot tableboxplotto csvtakeaway
- Resuelto
- Sin pistas
- Al primer intento
