La solicitud

De Laura Bennett, Directora de Finanzas
Tu objetivo
Paso 1 de 3. Verifica la tabla. Haz merge de employees con una copia de su propia columna employee_id (renombrada mgr_id) usando how='left', left_on='manager_id', right_on='mgr_id' e indicator=True. Asigna a result un DataFrame de una fila con employees (filas), distinct_ids, distinct_names (first_name + ' ' + last_name distintos), no_manager (manager_id falta), unknown_manager (manager_id presente pero sin coincidencia) y min_salary y max_salary.
- Usa el DataFrame
employeespendiente - Muestra exactamente
employeesdistinct_idsdistinct_namesno_managerunknown_managermin_salarymax_salarypendiente - 1 fila, ordenadas como se pidependiente
Paso 2 de 3. Resume por departamento. Asigna a result un DataFrame con las columnas department, headcount, payroll (salario total), mean_salary (redondeado a 0), median_salary y hired_since_2024 (hire_date el 2024-01-01 o después). Ordena por payroll descendente y luego por department, con índice por defecto.
- Usa el DataFrame
employeespendiente - Muestra exactamente
departmentheadcountpayrollmean_salarymedian_salaryhired_since_2024pendiente - 9 filas, ordenadas como se pidependiente
Paso 3 de 3. Cuenta los reportes directos. Haz merge de employees (izquierda) con una tabla de gerentes construida a partir de employees (employee_id renombrado mgr_id, más manager = first_name + ' ' + last_name y title) con left_on='manager_id', right_on='mgr_id' (interno). Asigna a result un DataFrame con las columnas manager, title (el puesto del gerente) y direct_reports. Ordena por direct_reports descendente y luego por manager, con índice por defecto.
- Usa el DataFrame
employeespendiente - Muestra exactamente
managertitledirect_reportspendiente - 12 filas, ordenadas como se pidependiente
Este caso se desbloquea cuando terminas cualquiera de estos:
La solicitud y la lección ya se pueden leer. Resuelve todos los niveles de uno de esos capítulos, en la ruta que prefieras, y este caso se abre.
Paso 1 · tu código
Cargando el editor…
Solución de referencia
| employee_id | first_name | last_name | department | title |
|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer |
| 2 | Robert | Kim | Executive | Chief Operating Officer |
| 3 | Megan | Collins | Sales | Head of Sales |
| 4 | Chloe | Gutierrez | Sales | Account Executive |
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
| employee_id | first_name | last_name | department | title |
|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer |
| 2 | Robert | Kim | Executive | Chief Operating Officer |
| 3 | Megan | Collins | Sales | Head of Sales |
| 4 | Chloe | Gutierrez | Sales | Account Executive |
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
| employee_id | first_name | last_name | department | title |
|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer |
| 2 | Robert | Kim | Executive | Chief Operating Officer |
| 3 | Megan | Collins | Sales | Head of Sales |
| 4 | Chloe | Gutierrez | Sales | Account Executive |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Laura, y por qué
DataFrames
Cargados como DataFrames de pandas, junto con pd y np.
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 |
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 |
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 verificando y por qué
Una exportación de RR. HH. se ve ordenada, pero a menudo se edita a mano: se vuelve a ingresar a las personas tras un cambio de puesto, los gerentes se van y sus reportes siguen apuntando a ellos. Antes de sumar nada, comprueba tres cosas.
- ¿Alguien está listado dos veces? Los ids son únicos por diseño, así que cuenta también los nombres distintos.
- ¿Cada línea de reporte lleva a algún sitio? Un
manager_idque no coincide con ningúnemployee_ides un huérfano. Solo el CEO debe carecer de gerente. - ¿Son plausibles los salarios?
min()ymax()detectan una cifra mensual escrita como anual, o un cero faltante.
La verificación de reportes necesita un automerge: la tabla unida con una copia de sí misma, un lado para
el empleado y otro para el gerente. how="left" conserva a todos los empleados, e indicator=True agrega
una columna _merge que dice si se encontró una fila de gerente:
checked = e.merge(managers, how="left", left_on="manager_id", right_on="mgr_id", indicator=True)
checked["_merge"].value_counts() # both 59, left_only 1
La única fila left_only es el CEO, cuyo manager_id falta. Un huérfano sería una fila
left_only que sí tiene manager_id. Aquí no hay ninguna.
Plantilla, nómina, media y mediana
El paso 2 es un solo groupby con agregación con nombre. El par interesante es media y mediana. La media
suma todos los salarios y divide; la mediana es el salario del medio cuando están ordenados. En un
departamento de siete donde una persona es el responsable, el salario del responsable mueve mucho la media y apenas
la mediana:
| department | headcount | mean_salary | median_salary |
|---|---|---|---|
| Engineering | 8 | 149,750 | 139,500 |
| Data & Analytics | 7 | 108,000 | 92,000 |
| Sales | 9 | 84,000 | 73,000 |
| Customer Support | 9 | 59,333 | 50,000 |
Para “cuánto gana aquí una persona típica”, informa de la mediana. La nómina sigue siendo la suma: eso es lo que paga el presupuesto.
Tramo de control
El tramo de control es el número de personas que reportan directamente a un gerente. Es un insumo habitual
del diseño organizativo: demasiado estrecho y la empresa es pesada en la cúpula, demasiado amplio y los gerentes no pueden
con todo. Con un merge interno, cada fila es una línea de reporte, así que contar filas por gerente da el
tramo. Conserva solo las columnas que necesitas en el lado izquierdo, o las dos columnas title chocan.
manager_id es una columna float por el valor faltante del CEO. Al hacer merge con el entero
mgr_id, 3.0 sigue coincidiendo con 3; pandas compara los valores, no los tipos.
Los tramos aquí van de 2 (Anna Chen, Sales Manager) a 7. Los dos gerentes de Support tienen 5 y 3.
Trampas
- Un merge interno en la verificación oculta justo las filas que buscas.
- Agrupar por nombre fusiona a dos gerentes que comparten uno; agrupa por id en una empresa grande.
- Las medias departamentales de 2 o 5 personas pueden revelar salarios individuales. Mantenlas fuera de los informes que salgan de Finanzas y RR. HH.
¡Linterna encendida!
Practicaste: data validationself mergemerge indicatorgroupbymedianspan of control
- Resuelto
- Sin pistas
- Al primer intento
