La solicitud

De Thomas Whitaker, Director de Merchandising
Tu objetivo
Construye las unidades por producto (suma de quantity) de los pedidos hechos en el T1 de 2025 y en el T2 de 2025 (las tablas de pedidos q1 y q2 están dadas). Haz un outer merge de las dos por product_id y asigna a result un DataFrame con los productos que aparecen en un solo trimestre: columnas product_id, q1_units, q2_units (NaN donde el producto no se vendió ese trimestre), ordenado por product_id ascendente, con el índice reiniciado.
- Usa el DataFrame
orderspendiente - Usa el DataFrame
order_itemspendiente - Muestra exactamente
product_idq1_unitsq2_unitspendiente
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 Thomas, 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 |
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 |
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 |
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
Cuatro tipos de merge
how= decide qué claves sobreviven a un merge:
"inner"(el valor por defecto): solo las claves que están en ambos lados."left": todas las claves de la tabla izquierda, con NaN donde la derecha no tiene pareja."right": la imagen especular, todas las claves de la tabla derecha.a.merge(b, how="right")conserva las mismas filas queb.merge(a, how="left"), solo cambia el orden de las columnas, así que la mayoría de la gente escribe simplemente la versión left."outer": todas las claves de cualquiera de los lados, con NaN donde falta uno de ellos.
Thomas quiere los productos que faltan en cualquiera de los trimestres, así que solo un outer merge conserva todo lo que necesita.
Unidades por trimestre, y luego outer
Primero reduce cada trimestre a una fila por producto. q1[["order_id"]] conserva solo los ids de
pedido, así que unir con order_items trae las líneas de los pedidos del T1 y nada más:
q1_units = q1[["order_id"]].merge(order_items, on="order_id").groupby(
"product_id", as_index=False
).agg(q1_units=("quantity", "sum"))
107 productos se vendieron en el T1 y 111 en el T2. El outer merge da 116 filas:
both = q1_units.merge(q2_units, on="product_id", how="outer", indicator=True)
both["_merge"].value_counts() # both 102, right_only 9, left_only 5
indicator=True añade la columna _merge, que dice de dónde vino cada fila. Es la forma más fácil
de filtrar las filas “solo en un lado”, y además sirve de comprobación: 102 + 9 + 5 = 116.
Leer el resultado
Los cinco productos de solo-T1 incluyen el Sable Oak Daybed, la Elm Cashmere-Blend Area Rug y la
Cedar Ceramic Candle, todos descatalogados. Los nueve de solo-T2 incluyen el Rowan Walnut Dresser
(lanzado el 2025-04-21) y la Pacifica Black Metal Arc Lamp (2025-04-05), además de huertos urbanos,
utensilios de parrilla y maceteros que solo se venden cuando empieza la temporada de exterior. Un
producto ausente del T2 muestra NaN en q2_units, no 0: pandas no puede saber si “sin fila”
significa cero ventas o datos que faltan, así que deja esa decisión en tus manos.
Errores comunes
- Usar el merge inner por defecto, que descarta justo los productos de un solo lado.
- Unir las líneas de pedido en bruto de los dos trimestres en lugar de totales por producto, lo que multiplica filas.
- Filtrar por
q2_units == 0para encontrar productos ausentes. Lo ausente aparece como NaN, no como 0. - Olvidar quitar la columna
_mergede la tabla final.
¡Linterna encendida!
Practicaste: outer joinright joinindicatormergegroupby
- Resuelto
- Sin pistas
- Al primer intento
