La solicitud

De Thomas Whitaker, Director de Merchandising
Tu objetivo
Paso 1 de 3. Revisa qué productos se pueden juzgar. Etiqueta cada producto con product_group: 'retired' si is_active es False, si no 'new in 2025' si launched_on >= '2025-01-01', si no 'established'. Asigna a result un DataFrame con las columnas product_group, products (el número de productos), sold_in_2025 (cuántos tuvieron alguna venta en 2025) y missing_cost (cuántos tienen unit_cost faltante), ordenado por product_group y con índice por defecto.
- Usa el DataFrame
orderspendiente - Usa el DataFrame
order_itemspendiente - Muestra exactamente
product_groupproductssold_in_2025missing_costpendiente
Paso 2 de 3. Encuentra los tres más débiles por categoría. Solo para productos consolidados, calcula las unidades y los ingresos netos de 2025 de cada producto, y su proporción de los ingresos de 2025 de su categoría. Asigna a result un DataFrame con las columnas category, product_id, name, units_2025, revenue_2025 (redondeado a 2) y category_share_pct (revenue * 100 / ingresos de la categoría, redondeado a 1) para los tres productos con menos ingresos en cada categoría, ordenado por category y luego por revenue_2025, con índice por defecto.
- Usa el DataFrame
productspendiente - Usa el DataFrame
orderspendiente - Muestra exactamente
categoryproduct_idnameunits_2025revenue_2025category_share_pctpendiente
Paso 3 de 3. Dimensiona los tres más débiles. Para productos consolidados, asigna a result un DataFrame con las columnas category, products (el número de productos consolidados), category_revenue (ingresos netos de 2025, redondeados a 2), bottom3_revenue (ingresos de los tres más débiles, redondeados a 2) y bottom3_share_pct (bottom3_revenue * 100 / category_revenue con valores sin redondear, redondeado a 1), ordenado por bottom3_share_pct y con índice por defecto.
- Usa el DataFrame
productspendiente - Usa el DataFrame
orderspendiente - Muestra exactamente
categoryproductscategory_revenuebottom3_revenuebottom3_share_pctpendiente
Paso 1 · 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.
Paso 2 · tu código
Cargando el editor…
Solución de referencia
| product_id | name | category | subcategory | unit_price |
|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 |
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
| product_id | name | category | subcategory | unit_price |
|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 |
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 |
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 |
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 |
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
Qué estás revisando, y por qué
Antes de clasificar nada, decide qué productos se pueden juzgar con justicia. Tres grupos se comportan de forma distinta:
- Los productos retirados ya están saliendo de la gama; pertenecen a otra revisión.
- Los productos nuevos en 2025 tuvieron solo parte del año a la venta. Un farol lanzado en agosto no se puede comparar con uno que vendió todo el verano.
- Los productos consolidados estuvieron a la venta los doce meses: esos son los que hay que clasificar.
El paso 1 parte de products y le une las ventas de 2025 con how="left", así que un producto que
no vendió nada seguiría ahí, con unidades NaN. np.select etiqueta entonces cada producto, tomando
la primera condición que es verdadera:
p["product_group"] = np.select(
[~p["is_active"], p["launched_on"] >= "2025-01-01"],
["retired", "new in 2025"],
default="established",
)
En la agregación, ("units", "count") cuenta los productos que vendieron, y una pequeña lambda
cuenta los costos unitarios faltantes, porque un producto lento con un costo desconocido es uno cuyo
margen nadie puede juzgar.
Clasificar dentro de cada categoría
El paso 2 necesita el total de la categoría en cada fila de producto. transform devuelve un valor
por fila, alineado con la tabla original, mientras que un simple sum() devolvería una fila por
categoría:
t["share"] = t["revenue"] * 100 / t.groupby("category")["revenue"].transform("sum")
low = t.sort_values(["category", "revenue"]).groupby("category").head(3)
head(3) después de ordenar es la forma en pandas de decir «los tres primeros por grupo». El paso 3
usa el mismo truco, luego suma los tres más débiles y divide entre el total de la categoría.
Cómo leer el resultado
| category | producto más débil | units_2025 | category_share_pct |
|---|---|---|---|
| Furniture | Upland Oak Bookcase | 9 | 0.7 |
| Textiles | Spruce Wool Duvet Cover | 25 | 0.7 |
| Outdoor | Orchard Aluminum Adirondack Chair | 93 | 1.0 |
| Lighting | Fern Rattan Desk Lamp | 13 | 1.2 |
La proporción de ingresos y las unidades juntas cuentan la historia. La estantería y la lámpara de escritorio casi no vendieron nada; la silla Adirondack vendió 93 unidades pero a $51.99 cada una, así que apenas se nota en una categoría de juegos de patio y parrillas.
Errores comunes
is_activees una columna booleana, así que~p["is_active"]la invierte;p["is_active"] == "false"no coincide con nada.groupby().head(3)conserva las tres primeras filas en el orden actual, así que ordena primero.- Una proporción de ingresos no dice nada sobre la ganancia. Siete productos consolidados no tienen costo unitario, así que su margen se desconoce.
¡Linterna encendida!
Practicaste: data validationleft mergenp selectgroupby transformgroupby headpercent of total
- Resuelto
- Sin pistas
- Al primer intento
