La solicitud

De Andrew Ramos, Responsable de Marketing
Tu objetivo
Usando los pedidos que tienen coupon_code, asigna a result un DataFrame con las columnas coupon_code, cancelled, completed, pending, refunded: el número de pedidos de cada código de cupón y estado, como ints, con 0 donde un cupón no tiene pedidos en ese estado. Una fila por código de cupón, ordenada de la A a la Z.
- Usa el DataFrame
orderspendiente - Muestra exactamente
coupon_codecancelledcompletedpendingrefundedpendiente - 6 filas, ordenadas como se pidependiente
Tu código
Cargando el editor…
Solución de referencia
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Andrew, y por qué
DataFrames
Cargados como DataFrames de pandas, junto con pd y np.
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 |
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 |
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 |
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
Un índice de dos niveles
Agrupa por dos columnas y cuenta, y pandas devuelve una Series cuyo índice tiene dos niveles:
counts = orders.groupby(["channel", "status"]).size()
# channel status
# app cancelled 265
# completed 3885
# pending 50
# refunded 120
# marketplace cancelled 108
# ...
Ese índice es un MultiIndex: cada entrada es un par como ("app", "completed"). Es una tabla
larga disfrazada, una fila por par.
unstack: de filas a columnas
.unstack() toma el nivel más interno del índice y convierte sus valores en columnas:
counts.unstack()
# status cancelled completed pending refunded
# channel
# app 265 3885 50 120
# marketplace 108 1597 19 43
# web 353 5367 52 141
Es la misma cuadrícula que construye pivot_table; groupby más unstack es simplemente otro camino
hasta ella, práctico cuando ya tienes la Series agrupada. Para mover un nivel distinto, nómbralo:
counts.unstack("channel") pone los canales arriba y los estados en el lateral.
Combinaciones ausentes
Un groupby de dos claves solo lista los pares que ocurren realmente. Cuando aplicas unstack, cualquier par que nunca ocurrió deja un hueco, rellenado con NaN:
orders.groupby(["coupon_code", "status"]).size().unstack()
# status cancelled completed pending refunded
# HOLIDAY20 12.0 174.0 NaN 7.0
Ninguno de los pedidos de HOLIDAY20, SPRING15 o SUMMER15 está pendiente, porque casi todos los
pedidos pendientes se hicieron en los últimos días de 2025, después de que terminaran esas campañas.
Para un recuento, una celda vacía es realmente cero, así que pasa fill_value=0. Rellena los huecos
y mantiene los recuentos como enteros.
Fíjate en que los pedidos sin cupón (10.277) no aparecen en absoluto: groupby descarta las claves
NaN por defecto. Pasa dropna=False a groupby si los quieres como una fila propia.
stack: de vuelta a una fila por par
.stack() es lo inverso: mueve las columnas de vuelta al nivel más interno del índice.
grid = counts.unstack()
grid.stack() # the long Series again, one entry per channel and status
stack descarta por defecto las celdas NaN, así que tras un unstack y un stack recuperas los pares originales.
Gestionar el índice
Las cuadrículas y los resultados agrupados guardan sus claves en el índice. Tres métodos las mueven:
long = grid.stack().reset_index(name="n_orders") # index levels → ordinary columns
by_status = long.set_index("status") # a column → the index
by_status.sort_index() # sort rows by their index labels
reset_index() es lo que llamas antes de unir, aplicar melt o exportar, para que las claves sean
columnas reales. set_index() va en el otro sentido cuando quieres buscar filas con
.loc["completed"]. sort_index() ordena las filas por etiqueta, como ya hacen groupby y pivot_table.
Errores comunes
- Aplicar unstack sin
fill_value=0sobre recuentos, dejando NaN y columnas float como 174.0. - Aplicar unstack al nivel equivocado. Sin argumento es la última clave por la que agrupaste; nombra el nivel para estar seguro.
- Rellenar con 0 cuando la celda es una media. Una media vacía es desconocida, no cero.
- Olvidar que
groupbydescarta las claves ausentes, y luego preguntarse adónde fueron los pedidos sin cupón.
¡Linterna encendida!
Practicaste: unstackstackmultiindexfill valuegroupby multiple keys
- Resuelto
- Sin pistas
- Al primer intento
