100 Días de Código en Python — Día 72: Exploración de datos con pandas — ¿qué carreras pagan más?
Nivel: Grado décimo
Área: Tecnología e Informática
Modalidad: Tutorial práctico
Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 72 (nivel avanzado).
21 min de lectura
17 secciones
Este tutorial adapta pedagógicamente el Día 72, que abre el bloque de ciencia de datos (Días 72 a 81 del curso). Las secciones 📝 Contenido original del curso provienen de las lecciones 519 a 528; el archivo salaries_by_college_major.csv y el cuaderno completo están en los recursos del curso. Los retos 🟢🟡🟠🔴, las secciones sobre cómo leer estos datos con sentido crítico, el proyecto extra y la etapa 1 del nuevo proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Nota sobre las verificaciones: el 27 de septiembre de 2026, con Python 3.14, pandas 3.0.6 y una copia pública del archivo salaries_by_college_major.csv del curso (publicada en GitHub por otro estudiante del mismo curso), se ejecutó todo el código de las lecciones. Todos los resultados coinciden con los del curso (51 filas, 74 300 dólares para Physician Assistant, índice 43, etc.), exceptoclean_df.groupby('Group').mean(), que en pandas 3 lanza TypeError: dtype 'str' does not support operation 'mean'. Las cifras que aparecen en este tutorial son las obtenidas en esa ejecución.
Los títulos universitarios son muy costosos. ¿Se recuperan? Elegir Filosofía o Relaciones Internacionales puede preocupar a los padres, pero ¿los datos les dan la razón? La empresa PayScale hizo una encuesta de un año a 1,2 millones de estadounidenses con solo título de pregrado. Con pandas responderemos:
¿Qué carreras tienen los salarios iniciales más altos?
¿Cuáles tienen los ingresos más bajos después de graduarse?
¿Cuáles tienen el mayor potencial de ingresos?
¿Cuáles son las carreras de menor riesgo en cuanto a ingresos?
¿Ganan más en promedio las carreras de negocios, STEM (ciencia, tecnología, ingeniería y matemáticas) o HASS (humanidades, artes y ciencias sociales)?
Aprenderás a explorar un DataFrame, detectar valores NaN y limpiar datos, seleccionar columnas, filas y celdas, ordenar y agrupar por categoría.
Prerequisitos: pandas básico con CSV (Día 25), listas y diccionarios, print con f-strings. Recomendado: el análisis de datos del Día 53 (limpieza de precios).
En grado décimo empiezas a pensar en qué estudiar después del colegio. Hoy no vas a encontrar "la respuesta", pero sí vas a aprender a interrogar datos para tomar decisiones informadas y, sobre todo, a no creer cualquier cifra sin preguntar de dónde sale (sección 7).
PyCharm es excelente, pero para explorar y visualizar datos es mejor un cuaderno (notebook) de Python. Google Colab se abre desde Google Drive: Nuevo → Más → Google Colaboratory. Si no puedes usarlo, instala Anaconda y usa Jupyter Notebook: Colab es "una versión en línea de Jupyter".
El cuaderno se divide en celdas que se ejecutan por separado; el resultado aparece debajo.
Para ejecutar una celda: Mayús + Enter.
Colab debe conectarse a un "entorno de ejecución" (runtime) para ejecutar código.
Cuenta de Google (puede ser la del colegio) e Internet
Jupyter (Anaconda)
Funciona sin Internet
Instalar Anaconda (pesado)
VS Code con la extensión de Jupyter
Usa tu Python y tu entorno virtual
python -m pip install jupyter pandas matplotlib
Cómo pensar en un cuaderno: es como una calculadora que recuerda lo que hiciste en las celdas anteriores. Por eso importa el orden: si ejecutas una celda que usa clean_df antes de la que lo crea, aparece NameError. Si te pierdes, usa Reiniciar y ejecutar todo.
Descarga salaries_by_college_major.csv de los recursos y arrástralo a la barra lateral de Colab (el ícono de la carpeta). Luego:
Python
1234
import pandas as pd
df = pd.read_csv('salaries_by_college_major.csv')
df.head()
.head() muestra las primeras 5 filas. En el cuaderno, la última línea de una celda se muestra automáticamente con un formato de tabla agradable. Autocompletar: Ctrl + Espacio (Windows) o ⌘ + Espacio (Mac).
🛠️ Nota técnica: en Colab, los archivos que subes a la barra lateral se borran cuando se reinicia el entorno de ejecución (por ejemplo, tras un tiempo sin uso). Si al volver aparece FileNotFoundError, súbelo otra vez o monta tu Google Drive.
Siempre el primer paso de un proyecto de datos es entender con qué se trabaja:
¿Cuántas filas y columnas? → df.shape
¿Cómo se llaman las columnas? → df.columns
¿Hay valores faltantes o datos "basura"? → df.isna()
Los valores NaN (Not a Number) son celdas vacías o que tienen texto donde debería haber números. Al revisar el final con df.tail(), aparece una fila con la fuente de los datos y todas las demás columnas vacías. Se elimina con dropna():
Python
12
clean_df = df.dropna()
clean_df.tail()
(También se podría borrar a mano la fila de índice 50.)
df.shape → (51, 6)
Columnas: 'Undergraduate Major', 'Starting Median Salary', 'Mid-Career Median Salary',
'Mid-Career 10th Percentile Salary', 'Mid-Career 90th Percentile Salary', 'Group'
Última fila (índice 50): 'Source: PayScale Inc.' y NaN en las otras 5 columnas
clean_df.shape → (50, 6)
Un truco más útil que df.isna():df.isna() muestra una tabla enorme de True/False. Para ver cuántos faltan por columna: df.isna().sum() (verificado: 1 en cada columna salvo en Undergraduate Major). Y df.info() resume columnas, tipos y conteos de un solo golpe.
🛠️ Nota técnica: en el resumen de la lección 528 aparece el método .findna(), que no existe. Los métodos son .isna() (o su alias .isnull()) y .notna().
🛠️ Nota técnica:dropna() borra cualquier fila con al menos un NaN. Aquí solo era la fila de la fuente, pero en otros conjuntos de datos podrías perder filas valiosas sin darte cuenta. Compara siempre df.shape antes y después.
🟢 Reto 1 — Aplicación: usa df.info() y df.describe() e interpreta tres números de cada salida.
🟡 Reto 2 — Ampliación: en lugar de dropna(), elimina solo la fila de la fuente con df.drop(50) y comprueba que el resultado es igual.
🟠 Reto 3 — Desafío: crea una copia del CSV en la que falte el salario inicial de una carrera real. ¿Qué hace dropna()? Propón otra forma de manejarlo (por ejemplo, dropna(subset=[...]) o dejar el NaN y tenerlo en cuenta).
🔴 Reto 4 — Pensamiento computacional: escribe una función diagnostico(df) que imprima filas, columnas, tipos y cuántos NaN hay por columna. La usarás en todos los días del bloque.
clean_df['Starting Median Salary']# una columna
clean_df['Starting Median Salary'].max()# 74300.0
clean_df['Starting Median Salary'].idxmax()# 43: el índice de la fila con el máximo
clean_df['Undergraduate Major'].loc[43]# 'Physician Assistant'
clean_df['Undergraduate Major'][43]# lo mismo, con doble corchete
clean_df.loc[43]# la fila completa
Reto: ¿qué carrera tiene el mayor salario a mitad de carrera (10 o más años de experiencia) y cuánto? ¿Cuál tiene el menor salario inicial? ¿Y el menor a mitad de carrera?
Solución (lección 524):
Python
12345678
print(clean_df['Mid-Career Median Salary'].max())print(f"Index for the max mid career salary: {clean_df['Mid-Career Median Salary'].idxmax()}")
clean_df['Undergraduate Major'][8]print(clean_df['Starting Median Salary'].min())
clean_df['Undergraduate Major'].loc[clean_df['Starting Median Salary'].idxmin()]
clean_df.loc[clean_df['Mid-Career Median Salary'].idxmin()]
Si una celda tiene varias líneas, solo la última se muestra automáticamente; para ver las demás, usa print. Resultado: la carrera con el menor salario a mitad de carrera es Education (Educación) y la de menor salario inicial, Spanish (Español).
La forma recomendada por la documentación de pandas, sobre todo para modificar una celda
loc usa la etiqueta del índice (43 es el nombre de la fila, no su posición). iloc usa la posición (df.iloc[0] es siempre la primera fila). Después de dropna() u ordenar, etiqueta y posición pueden ser distintas.
Carreras de menor riesgo: aquellas donde la diferencia entre los que menos ganan (percentil 10) y los que más ganan (percentil 90) es pequeña: hay más certeza sobre el salario. pandas permite restar columnas enteras:
Las tres que se repiten entre "mayor potencial" y "mayor spread" son Economics, Finance y Math. sort_values() ordena de menor a mayor por defecto (ascending=True).
💡 Con pandas 3 (verificado), clean_df.insert(...) sobre el resultado de dropna() funciona sin la advertencia SettingWithCopyWarning que aparecía en versiones anteriores, gracias al modelo Copy-on-Write: clean_df es un DataFrame independiente de df.
🟢 Reto 1: agrega una columna Crecimiento con el porcentaje de aumento entre el salario inicial y el de mitad de carrera. ¿Qué carrera crece más?
🟡 Reto 2: ordena por dos columnas: primero por Group y dentro de cada grupo por salario inicial descendente.
🟠 Reto 3: encuentra las carreras que están a la vez entre las 10 de menor riesgo y las 25 de mayor salario inicial (pista: .isin() o intersección de conjuntos, Día 49).
🔴 Reto 4 — Pensamiento computacional: define tu propia medida de "mejor carrera" combinando salario inicial, crecimiento y riesgo con pesos que tú elijas. Calcula el ranking y explica por qué otra persona con otros pesos obtendría otro resultado.
¿Qué categoría gana más en promedio: STEM, negocios o HASS? .groupby() permite manipular los datos como una tabla dinámica de Excel:
Python
1
clean_df.groupby('Group').count()
Mini reto: usa .mean() para el salario promedio por grupo. Para leer mejor los números (1,012.45):
Python
1
pd.options.display.float_format ='{:,.2f}'.format
Crédito extra: los datos de PayScale son de 2008 y cubren los 10 años anteriores; Finanzas aparece muy arriba, pero ese año hubo una gran crisis financiera. ¿Cambió algo? Usa el web scraping (Día 45) para compartir datos actualizados de la página de PayScale… que hoy tiene muro de pago, así que mejor en una copia antigua de la Wayback Machine.
Resumen del día:.head(), .tail(), .shape, .columns; buscar NaN y limpiar con .dropna(); columnas con df['col'] o df[['col1', 'col2']]; celdas con df['col'][índice] o .loc; .max(), .min(), .idxmax(), .idxmin(); .sort_values() e .insert(); .groupby().
📖 Explicación conceptual (verificada con pandas 3.0.6)#
🛠️ Nota técnica (verificado):clean_df.groupby('Group').mean()falla en pandas 2 y 3 con TypeError: dtype 'str' does not support operation 'mean', porque intenta promediar también la columna de textoUndergraduate Major. En versiones antiguas (las del video) pandas omitía esas columnas en silencio. La corrección:
Python
1
clean_df.groupby('Group').mean(numeric_only=True)
o seleccionar primero las columnas numéricas que te interesan:
Python
1
clean_df.groupby('Group')[['Starting Median Salary','Mid-Career Median Salary']].mean()
Resultado verificado (con el formato de miles):
Grupo
Salario inicial promedio
Salario a mitad de carrera promedio
Business
44,633.33
75,083.33
HASS
37,186.36
62,968.18
STEM
53,862.50
90,812.50
🛠️ Nota técnica: en pandas 3, las columnas de texto tienen el tipo str (antes, object), como muestra df.dtypes. Es la causa del error anterior y verás ese nombre en otros mensajes.
(Sección creada para esta adaptación a partir del "crédito extra" de la lección 527.)
Antes de sacar conclusiones ("hay que estudiar Ingeniería Química"), hazle preguntas a los datos:
Pregunta
En este conjunto de datos
¿Cuándo se recogieron?
2008, sobre los 10 años anteriores. Antes de una crisis financiera y hace casi dos décadas
¿Dónde?
Estados Unidos, en dólares estadounidenses. Los salarios y el costo de las carreras en Colombia son muy distintos
¿Quiénes respondieron?
Personas que usaron PayScale y solo tienen pregrado (quienes hicieron posgrado no están)
¿Qué es la "mediana"?
El valor del medio: la mitad gana más y la mitad menos. No dice cuánto ganará una persona
¿Qué no mide?
Satisfacción, desempleo, costo de la matrícula, gusto por la profesión, calidad de vida
¿Causa o correlación?
Que Economía tenga salarios altos no significa que estudiarla cause ganar más: quienes la eligen pueden ser distintos desde antes
Para Colombia: el Observatorio Laboral para la Educación (OLE) del Ministerio de Educación Nacional publica información sobre graduados de educación superior y su vinculación laboral. Es una fuente mucho más pertinente para tu decisión (explórala en el proyecto extra o con tu orientador escolar).
10
8. 🚀 Proyecto del día: el informe de carreras y salarios#
Comprender las preguntas. 2. Entradas: el CSV. 3. Procesos: diagnosticar → limpiar → calcular → ordenar → agrupar. 4. Salidas: tablas y conclusiones. 5. Una sección del cuaderno por pregunta. 6. Escribir las preguntas como títulos antes de programar. 7. Implementar. 8. Revisar los resultados con la tabla verificada. 9. Corregir. 10. Redactar conclusiones.
Encuentra cuatro problemas: df.dropna() no guarda el resultado (sigue con 51 filas); se trabaja sobre df en lugar de clean_df; 'spread' en minúsculas da KeyError; y mean() sin numeric_only=True falla en pandas 3.
Hacer el "crédito extra": comparar con datos más recientes de PayScale en la Wayback Machine (con requests y Beautiful Soup, Día 45), respetando las condiciones del sitio.
Convertir los salarios a pesos colombianos con una tasa de cambio actual y discutir por qué esa conversión no los vuelve comparables.
El área de orientación quiere entender qué les interesa estudiar a los estudiantes de grado 10.° y 11.° y compararlo con la información de las carreras.
Diseña con tu grupo una encuesta anónima (Google Forms o papel) con: grado, área de interés (Ingenierías, Salud, Artes, Ciencias Sociales, Negocios, Educación, Otra), si piensa estudiar en universidad, técnico o tecnológico, y una pregunta de 1 a 5 sobre qué tanto le importa el salario al elegir.
Exporta las respuestas a CSV (mínimo 30, pueden ser simuladas si no hay tiempo, pero indícalo).
Con pandas: diagnóstico y limpieza (respuestas vacías, textos escritos distinto), conteo por área con groupby, promedio de "importancia del salario" por área y por grado.
Busca en el Observatorio Laboral para la Educación (OLE) información sobre las áreas más elegidas y resúmela en una celda de texto con la fuente.
La suma de los conteos por área es igual al número de respuestas válidas.
Ninguna columna del CSV final permite identificar a una persona.
12
10. 🏗️ Proyecto integrador del bloque de datos — Etapa 1#
(Proyecto creado para esta adaptación. Se construye por etapas en los Días 72 a 75; la descripción completa está en el tutorial del Día 75.)
El Observatorio de Datos del Colegio. Vas a construir, paso a paso, un cuaderno de análisis que responda preguntas reales sobre tu comunidad con datos abiertos.
Etapa 1 (hoy):
Elige un tema para tu observatorio (por ejemplo: educación en tu municipio, calidad del aire, uso de bicicletas, deportes, clima) y tres preguntas que quieras responder.
Busca un conjunto de datos abierto en datos.gov.co (el portal de datos abiertos de Colombia) relacionado con tu tema y descárgalo en CSV.
Aplica tu función diagnostico(df) (Reto 4 de la sección 3) y documenta en Markdown: fuente, fecha, qué representa cada columna, cuántas filas y qué problemas de calidad encontraste.
Cambia el análisis por grupos para que muestre, además del promedio, el máximo y el mínimo salario inicial de cada grupo (pista: .agg(['mean', 'min', 'max']), lo verás a fondo el Día 74).
Ciclo de trabajo: formula el problema → inténtalo tú → consulta a la IA → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.
Actividad 1 — Código de otra versión. Pide a una IA "el promedio de salarios por grupo con pandas". Si responde df.groupby('Group').mean(), ejecútalo en tu versión de pandas y compara con la documentación de DataFrameGroupBy.mean (parámetro numeric_only).
Actividad 2 — Interpretar sin exagerar. Muestra a una IA la tabla de promedios por grupo y pídele conclusiones. ¿Menciona las limitaciones (año, país, mediana, causalidad)? Si no, pídeselas y compara con la sección 7.
Actividad 3 — Verificar una fuente. Pregunta a una IA qué es el Observatorio Laboral para la Educación y qué datos publica. Verifica en su sitio oficial del Ministerio de Educación y anota una diferencia entre lo que dijo la IA y lo que encontraste.
15
13. 🛠️ Correcciones técnicas al material original#
Archivo
Afirmación o comportamiento del curso
Observación
Tratamiento
527
clean_df.groupby('Group').mean()
En pandas 2 y 3 lanza TypeError por la columna de texto (verificado con pandas 3.0.6)
Sección 6: numeric_only=True
528
Buscar NaN con .findna()
Ese método no existe; es .isna()
Nota técnica de la sección 3
523
clean_df['Undergraduate Major'][43]
Funciona para leer; la documentación recomienda .loc[fila, columna]
Sección 4
521
Subir el CSV a la barra lateral de Colab
Se borra al reiniciar el entorno
Nota técnica de la sección 2
519, 527
Conclusiones sobre carreras
Datos de 2008, de Estados Unidos, solo pregrado, medianas
Sección 7
Todo el día
Todos los demás resultados
Coinciden exactamente con los del curso (verificado)
El cuaderno del informe de carreras y salarios, ejecutado de principio a fin, con conclusiones y limitaciones.
Tu función diagnostico(df).
El análisis de la encuesta de tu colegio (proyecto extra).
La etapa 1 del Observatorio de Datos del Colegio.
Cuaderno de errores: celdas ejecutadas en desorden, archivo borrado en Colab, dropna() sin guardar el resultado, nombres de columnas mal escritos, loc con un índice borrado, groupby().mean() con texto, .findna() inexistente, ordenar sin guardar el resultado.