Análisis de Factores Asociados al Éxito Profesional en Estudiantes Universitarios
Fundamentos de Programación para la Ciencia de Datos e IA
Especialización en Ciencia de Datos e IA — UTEC
Tomás Clavijo · María Martinote · Yuri Martin Biardo
1. Introducción
Este trabajo analiza los factores académicos, personales y sociales asociados al éxito profesional temprano en egresados universitarios. A partir de un dataset sintético de 5.000 registros, se aplican técnicas de análisis exploratorio y estadístico para identificar relaciones entre variables como el campo de estudio, el nivel universitario, el rendimiento académico, las habilidades sociales y los resultados laborales (salario inicial, número de ofertas y satisfacción profesional).
El enfoque es descriptivo: no se establecen relaciones causales, sino que se caracterizan patrones en el dataset que puedan orientar interpretaciones e investigaciones futuras con datos reales.
2. Descripción del Dataset
El dataset (Education & Career Success, Kaggle) contiene 5.000 registros y 18 variables distribuidas en cuatro dimensiones:
- Datos personales: edad (18–30 años), género, identificador.
- Desempeño académico: GPA universitario (2.0–4.0), GPA secundaria, puntaje SAT, ranking universitario, campo de estudio (7 disciplinas).
- Habilidades y actividades: pasantías, proyectos, certificaciones, soft skills score, networking score.
- Resultados profesionales: salario inicial, número de ofertas laborales, satisfacción profesional, nivel de puesto actual.
Al ser sintético, el dataset permite explorar relaciones estructuradas sin comprometer datos reales, aunque esto limita la validez externa de los hallazgos.
3. Preguntas de Investigación
- ¿Existen diferencias en el salario inicial según el campo de estudio y el nivel universitario?
- ¿Se observa una brecha salarial asociada al género?
- ¿El puntaje de networking se asocia a mejores resultados salariales?
- ¿Qué disciplinas presentan mayor empleabilidad y mayor satisfacción profesional?
- ¿Existe correlación lineal entre el rendimiento académico (GPA) y el salario inicial?
# Importación de librerías
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
from scipy import stats
# Importación de datos (Si el entorno se reinicia, el archivo se debe volver a subir)
#ruta = '//content/drive/MyDrive/DATASET/education_career_success.csv' # (Ruta Maria)
ruta ='/content/education_career_success (1).csv' # (Ruta Yuri)
#ruta ='//content/education_career_success.csv' # (Ruta Tomas)
datos = pd.read_csv(ruta)
datos.head()
| Student_ID | Age | Gender | High_School_GPA | SAT_Score | University_Ranking | University_GPA | Field_of_Study | Internships_Completed | Projects_Completed | Certifications | Soft_Skills_Score | Networking_Score | Job_Offers | Starting_Salary | Career_Satisfaction | Years_to_Promotion | Current_Job_Level | Work_Life_Balance | Entrepreneurship | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | S00001 | 24 | Male | 3.58 | 1052 | 291 | 3.96 | Arts | 3 | 7 | 2 | 9 | 8 | 5 | 27200.0 | 4 | 5 | Entry | 7 | No |
| 1 | S00002 | 21 | Other | 2.52 | 1211 | 112 | 3.63 | Law | 4 | 7 | 3 | 8 | 1 | 4 | 25000.0 | 1 | 1 | Mid | 7 | No |
| 2 | S00003 | 28 | Female | 3.42 | 1193 | 715 | 2.63 | Medicine | 4 | 8 | 1 | 1 | 9 | 0 | 42400.0 | 9 | 3 | Entry | 7 | No |
| 3 | S00004 | 25 | Male | 2.43 | 1497 | 170 | 2.81 | Computer Science | 3 | 9 | 1 | 10 | 6 | 1 | 57400.0 | 7 | 5 | Mid | 5 | No |
| 4 | S00005 | 22 | Male | 2.08 | 1012 | 599 | 2.48 | Engineering | 4 | 6 | 4 | 10 | 9 | 4 | 47600.0 | 9 | 5 | Entry | 2 | No |
# Conociendo el conjunto de datos
datos.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5000 entries, 0 to 4999 Data columns (total 20 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Student_ID 5000 non-null object 1 Age 5000 non-null int64 2 Gender 5000 non-null object 3 High_School_GPA 5000 non-null float64 4 SAT_Score 5000 non-null int64 5 University_Ranking 5000 non-null int64 6 University_GPA 5000 non-null float64 7 Field_of_Study 5000 non-null object 8 Internships_Completed 5000 non-null int64 9 Projects_Completed 5000 non-null int64 10 Certifications 5000 non-null int64 11 Soft_Skills_Score 5000 non-null int64 12 Networking_Score 5000 non-null int64 13 Job_Offers 5000 non-null int64 14 Starting_Salary 5000 non-null float64 15 Career_Satisfaction 5000 non-null int64 16 Years_to_Promotion 5000 non-null int64 17 Current_Job_Level 5000 non-null object 18 Work_Life_Balance 5000 non-null int64 19 Entrepreneurship 5000 non-null object dtypes: float64(3), int64(12), object(5) memory usage: 781.4+ KB
# Tamaño del dataset
print(f"Filas: {datos.shape[0]}")
print(f"Columnas: {datos.shape[1]}")
Filas: 5000 Columnas: 20
4. Limpieza y Calidad de los Datos
Se realizó un diagnóstico completo del dataset antes de cualquier transformación. El análisis confirmó: ausencia de valores nulos, ausencia de registros duplicados, y variables numéricas dentro de rangos esperados. El dataset no requirió imputación ni corrección de valores atípicos.
# Análisis de valores nulos y retorno de columnas que poseen valores nulos
nulos = datos.isnull().sum()
nulos[nulos > 0]
| 0 |
|---|
# Análisis de valores duplicados
duplicados = datos.duplicated().sum()
print(f"Registros duplicados: {duplicados}")
Registros duplicados: 0
# Variables categóricas y sus valores únicos
categoricas = datos.select_dtypes(include='object')
for col in categoricas.columns:
print(f"{col}: {datos[col].unique()}")
Student_ID: ['S00001' 'S00002' 'S00003' ... 'S04998' 'S04999' 'S05000'] Gender: ['Male' 'Other' 'Female'] Field_of_Study: ['Arts' 'Law' 'Medicine' 'Computer Science' 'Engineering' 'Business' 'Mathematics'] Current_Job_Level: ['Entry' 'Mid' 'Senior' 'Executive'] Entrepreneurship: ['No' 'Yes']
# Estadísticas principales
datos.describe().T
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Age | 5000.0 | 23.442200 | 3.473712 | 18.0 | 20.00 | 23.00 | 26.00 | 29.0 |
| High_School_GPA | 5000.0 | 2.996978 | 0.575673 | 2.0 | 2.50 | 2.99 | 3.50 | 4.0 |
| SAT_Score | 5000.0 | 1253.832000 | 203.228954 | 900.0 | 1076.00 | 1257.00 | 1432.00 | 1600.0 |
| University_Ranking | 5000.0 | 504.335600 | 291.060011 | 1.0 | 256.00 | 501.50 | 759.00 | 1000.0 |
| University_GPA | 5000.0 | 3.020028 | 0.576047 | 2.0 | 2.52 | 3.03 | 3.51 | 4.0 |
| Internships_Completed | 5000.0 | 1.982200 | 1.408219 | 0.0 | 1.00 | 2.00 | 3.00 | 4.0 |
| Projects_Completed | 5000.0 | 4.562800 | 2.872927 | 0.0 | 2.00 | 5.00 | 7.00 | 9.0 |
| Certifications | 5000.0 | 2.512200 | 1.703183 | 0.0 | 1.00 | 3.00 | 4.00 | 5.0 |
| Soft_Skills_Score | 5000.0 | 5.546000 | 2.851159 | 1.0 | 3.00 | 6.00 | 8.00 | 10.0 |
| Networking_Score | 5000.0 | 5.538000 | 2.850084 | 1.0 | 3.00 | 6.00 | 8.00 | 10.0 |
| Job_Offers | 5000.0 | 2.488800 | 1.711859 | 0.0 | 1.00 | 2.00 | 4.00 | 5.0 |
| Starting_Salary | 5000.0 | 50563.540000 | 14494.958207 | 25000.0 | 40200.00 | 50300.00 | 60500.00 | 101000.0 |
| Career_Satisfaction | 5000.0 | 5.578000 | 2.871997 | 1.0 | 3.00 | 6.00 | 8.00 | 10.0 |
| Years_to_Promotion | 5000.0 | 3.015800 | 1.417446 | 1.0 | 2.00 | 3.00 | 4.00 | 5.0 |
| Work_Life_Balance | 5000.0 | 5.482400 | 2.883427 | 1.0 | 3.00 | 6.00 | 8.00 | 10.0 |
# Evaluación según dimensiones de calidad:
# Completitud
faltan_datos = nulos.sum()
print(f"Completitud: {'Hay datos faltantes' if faltan_datos > 0 else 'No hay datos faltantes'}")
# Validez
print(f"Edad válida (18-30): {datos['Age'].between(18, 30).all()}")
print(f"SAT Score válido (900-1600): {datos['SAT_Score'].between(900, 1600).all()}")
print(f"GPA Universidad válido (2.0-4.0): {datos['University_GPA'].between(2.0, 4.0).all()}")
# Precisión
print("Precisión: No hay errores evidentes, se asume correcta dado el contexto sintético.")
# Consistencia
correlaciones = datos[['Internships_Completed', 'Starting_Salary']].corr()
print("Consistencia: Correlación entre internados y salario:")
print(correlaciones)
# Relevancia
print("Relevancia: Las columnas son pertinentes para analizar éxito profesional.")
#Unicidad
print(f"Unicidad: {'Sin duplicados' if duplicados == 0 else f'{duplicados} duplicados encontrados'}")
# Integridad
print("Integridad: Datos legibles, sin errores de formato, categorías correctas.")
Completitud: No hay datos faltantes
Edad válida (18-30): True
SAT Score válido (900-1600): True
GPA Universidad válido (2.0-4.0): True
Precisión: No hay errores evidentes, se asume correcta dado el contexto sintético.
Consistencia: Correlación entre internados y salario:
Internships_Completed Starting_Salary
Internships_Completed 1.00000 0.01808
Starting_Salary 0.01808 1.00000
Relevancia: Las columnas son pertinentes para analizar éxito profesional.
Unicidad: Sin duplicados
Integridad: Datos legibles, sin errores de formato, categorías correctas.
5. Preparación de Datos y Variables Derivadas
Se construyeron cuatro variables derivadas:
- Habilidades_Sociales: suma de Soft_Skills_Score y Networking_Score — indicador compuesto de competencias interpersonales.
- Categoria_Salario: clasificación en cuatro rangos (Bajo/Medio/Alto/Muy Alto), con umbrales en 50k, 70k y 100k USD.
- Nivel_Habilidades_Sociales: categorización ordinal (Baja/Media/Alta) del indicador compuesto.
- Nivel_Universidad: clasificación Top/Media/Baja según ranking (cortes en 200 y 600).
Se generó el DataFrame datos_filtrados con las columnas relevantes para el análisis.
# Función para realizar operaciones entre columnas numéricas con NumPy
def operar_columnas_numpy(arr1, arr2, operacion):
"""
Realiza operaciones NumPy entre dos arrays numéricos.
Args:
arr1, arr2: Arrays NumPy.
operacion: 'suma', 'resta', 'multiplicacion', 'division'
Returns:
Array con el resultado de la operación.
"""
if operacion == 'suma':
return np.add(arr1, arr2)
elif operacion == 'resta':
return np.subtract(arr1, arr2)
elif operacion == 'multiplicacion':
return np.multiply(arr1, arr2)
elif operacion == 'division':
return np.divide(arr1, arr2, out=np.zeros_like(arr1), where=arr2 != 0)
else:
print("Operación no válida.")
return None
# Convertir columnas a arrays NumPy
soft_skills = datos['Soft_Skills_Score'].to_numpy()
networking = datos['Networking_Score'].to_numpy()
# Operar con la función para obtener una variable compuesta (habilidades sociales)
habilidades_sociales = operar_columnas_numpy(soft_skills, networking, 'suma')
# Mostrar los primeros valores
habilidades_sociales[:10]
# Se incluye la columna Habilidades_Sociales
datos['Habilidades_Sociales'] = habilidades_sociales
# Creación del DataFrame de salarios
salarios_estadisticos = datos.groupby('Field_of_Study')['Starting_Salary'].agg(
Salario_Promedio = 'mean',
Salario_Minimo = 'min',
Salario_Maximo = 'max'
).sort_values(by = 'Salario_Promedio', ascending = False)
display(salarios_estadisticos)
| Salario_Promedio | Salario_Minimo | Salario_Maximo | |
|---|---|---|---|
| Field_of_Study | |||
| Arts | 51422.830441 | 25000.0 | 101000.0 |
| Computer Science | 50777.164179 | 25000.0 | 90800.0 |
| Mathematics | 50725.906040 | 25000.0 | 89900.0 |
| Engineering | 50416.547789 | 25000.0 | 98200.0 |
| Business | 50262.169680 | 25000.0 | 92400.0 |
| Medicine | 50219.158200 | 25000.0 | 90400.0 |
| Law | 50081.155433 | 25000.0 | 100600.0 |
# Salario máximo, mínimo y promedio (sin importar el rubro)
salario_max = datos['Starting_Salary'].max()
print(f"Salario maximo: ${salario_max}")
salario_min = datos['Starting_Salary'].min()
print(f"Salario minimo: ${salario_min}")
salario_prom = datos['Starting_Salary'].mean()
print(f"Salario promedio: ${salario_prom}")
Salario maximo: $101000.0 Salario minimo: $25000.0 Salario promedio: $50563.54
# Clasificación de salario en categorías
def clasificar_salario(salario):
"""
Clasifica un salario dado en categorías:
- 'Muy Alto': salario ≥ 100000
- 'Alto': 70000 ≤ salario < 100000
- 'Medio': 50000 ≤ salario < 70000
- 'Bajo': salario < 50000
Args:
salario (int o float): Salario inicial del estudiante.
Returns:
str: Categoría asignada al salario.
"""
if salario >= 100000:
return 'Muy Alto'
elif salario >= 70000:
return 'Alto'
elif salario >= 50000:
return 'Medio'
else:
return 'Bajo'
datos['Categoria_Salario'] = datos['Starting_Salary'].apply(clasificar_salario)
# Mostrar cuántos estudiantes hay en cada categoría
datos['Categoria_Salario'].value_counts()
| count | |
|---|---|
| Categoria_Salario | |
| Bajo | 2446 |
| Medio | 2061 |
| Alto | 491 |
| Muy Alto | 2 |
# Crear nuevo DataFrame con variables seleccionadas
# Se incluyen: Habilidades_Sociales y Categoria_Salario (columnas creadas anteriormente)
datos_filtrados = datos[[
'Age',
'Gender',
'University_GPA',
'Field_of_Study',
'University_Ranking',
'Soft_Skills_Score',
'Networking_Score',
'Habilidades_Sociales',
'Starting_Salary',
'Job_Offers',
'Current_Job_Level',
'Categoria_Salario'
]].copy()
datos_filtrados.head()
| Age | Gender | University_GPA | Field_of_Study | University_Ranking | Soft_Skills_Score | Networking_Score | Habilidades_Sociales | Starting_Salary | Job_Offers | Current_Job_Level | Categoria_Salario | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 24 | Male | 3.96 | Arts | 291 | 9 | 8 | 17 | 27200.0 | 5 | Entry | Bajo |
| 1 | 21 | Other | 3.63 | Law | 112 | 8 | 1 | 9 | 25000.0 | 4 | Mid | Bajo |
| 2 | 28 | Female | 2.63 | Medicine | 715 | 1 | 9 | 10 | 42400.0 | 0 | Entry | Bajo |
| 3 | 25 | Male | 2.81 | Computer Science | 170 | 10 | 6 | 16 | 57400.0 | 1 | Mid | Medio |
| 4 | 22 | Male | 2.48 | Engineering | 599 | 10 | 9 | 19 | 47600.0 | 4 | Entry | Bajo |
# Promedios por categoría salarial
promedios_por_categoria = datos_filtrados.groupby('Categoria_Salario').agg({
'University_GPA': 'mean',
'Habilidades_Sociales': 'mean',
'Starting_Salary': 'mean',
'Job_Offers': 'mean'
}).round(2)
# Mostrar ordenado de mayor a menor salario
promedios_por_categoria.sort_values(by='Starting_Salary', ascending=False)
| University_GPA | Habilidades_Sociales | Starting_Salary | Job_Offers | |
|---|---|---|---|---|
| Categoria_Salario | ||||
| Muy Alto | 3.47 | 9.00 | 100800.00 | 0.50 |
| Alto | 3.03 | 11.31 | 76691.85 | 2.41 |
| Medio | 3.01 | 11.09 | 58583.55 | 2.44 |
| Bajo | 3.02 | 11.04 | 38519.91 | 2.55 |
# Función para clasificar el nivel de habilidades sociales
def clasificar_habilidades(valor):
if valor >= 16:
return 'Alta'
elif valor >= 10:
return 'Media'
else:
return 'Baja'
# Aplicar y agregar la nueva columna
datos_filtrados['Nivel_Habilidades_Sociales'] = datos_filtrados['Habilidades_Sociales'].apply(clasificar_habilidades)
# Contar cuántos estudiantes hay en cada nivel
datos_filtrados['Nivel_Habilidades_Sociales'].value_counts()
| count | |
|---|---|
| Nivel_Habilidades_Sociales | |
| Media | 2434 |
| Baja | 1791 |
| Alta | 775 |
# 📊 Resumen estadístico de datos numéricos
resumen_numerico = datos_filtrados.describe()
print("Resumen estadístico numérico:")
display(resumen_numerico)
# 🎯 Media, varianza y desviación estándar de columnas numéricas
medias = datos_filtrados.mean(numeric_only=True)
varianzas = datos_filtrados.var(numeric_only=True)
desviaciones = datos_filtrados.std(numeric_only=True)
# Mostramos algunos de estos resultados
print("Media por columna numérica:")
print(medias.round(2))
print("Varianza por columna numérica:")
print(varianzas.round(2))
print("Desviación estándar por columna numérica:")
print(desviaciones.round(2))
# 📈 Correlaciones entre variables numéricas
correlaciones = datos_filtrados.corr(numeric_only=True)
print("Correlaciones entre variables numéricas:")
display(correlaciones)
Resumen estadístico numérico:
| Age | University_GPA | University_Ranking | Soft_Skills_Score | Networking_Score | Habilidades_Sociales | Starting_Salary | Job_Offers | |
|---|---|---|---|---|---|---|---|---|
| count | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 |
| mean | 23.442200 | 3.020028 | 504.335600 | 5.546000 | 5.538000 | 11.084000 | 50563.540000 | 2.488800 |
| std | 3.473712 | 0.576047 | 291.060011 | 2.851159 | 2.850084 | 4.051892 | 14494.958207 | 1.711859 |
| min | 18.000000 | 2.000000 | 1.000000 | 1.000000 | 1.000000 | 2.000000 | 25000.000000 | 0.000000 |
| 25% | 20.000000 | 2.520000 | 256.000000 | 3.000000 | 3.000000 | 8.000000 | 40200.000000 | 1.000000 |
| 50% | 23.000000 | 3.030000 | 501.500000 | 6.000000 | 6.000000 | 11.000000 | 50300.000000 | 2.000000 |
| 75% | 26.000000 | 3.510000 | 759.000000 | 8.000000 | 8.000000 | 14.000000 | 60500.000000 | 4.000000 |
| max | 29.000000 | 4.000000 | 1000.000000 | 10.000000 | 10.000000 | 20.000000 | 101000.000000 | 5.000000 |
Media por columna numérica: Age 23.44 University_GPA 3.02 University_Ranking 504.34 Soft_Skills_Score 5.55 Networking_Score 5.54 Habilidades_Sociales 11.08 Starting_Salary 50563.54 Job_Offers 2.49 dtype: float64 Varianza por columna numérica: Age 1.207000e+01 University_GPA 3.300000e-01 University_Ranking 8.471593e+04 Soft_Skills_Score 8.130000e+00 Networking_Score 8.120000e+00 Habilidades_Sociales 1.642000e+01 Starting_Salary 2.101038e+08 Job_Offers 2.930000e+00 dtype: float64 Desviación estándar por columna numérica: Age 3.47 University_GPA 0.58 University_Ranking 291.06 Soft_Skills_Score 2.85 Networking_Score 2.85 Habilidades_Sociales 4.05 Starting_Salary 14494.96 Job_Offers 1.71 dtype: float64 Correlaciones entre variables numéricas:
| Age | University_GPA | University_Ranking | Soft_Skills_Score | Networking_Score | Habilidades_Sociales | Starting_Salary | Job_Offers | |
|---|---|---|---|---|---|---|---|---|
| Age | 1.000000 | -0.015253 | 0.031417 | 0.006055 | -0.001647 | 0.003102 | 0.013171 | -0.030368 |
| University_GPA | -0.015253 | 1.000000 | -0.004471 | -0.009201 | 0.006803 | -0.001689 | 0.001022 | -0.014875 |
| University_Ranking | 0.031417 | -0.004471 | 1.000000 | -0.004211 | -0.016708 | -0.014716 | 0.021368 | 0.013199 |
| Soft_Skills_Score | 0.006055 | -0.009201 | -0.004211 | 1.000000 | 0.010198 | 0.710834 | 0.004870 | -0.008501 |
| Networking_Score | -0.001647 | 0.006803 | -0.016708 | 0.010198 | 1.000000 | 0.710572 | 0.002622 | -0.016600 |
| Habilidades_Sociales | 0.003102 | -0.001689 | -0.014716 | 0.710834 | 0.710572 | 1.000000 | 0.005271 | -0.017658 |
| Starting_Salary | 0.013171 | 0.001022 | 0.021368 | 0.004870 | 0.002622 | 0.005271 | 1.000000 | -0.034014 |
| Job_Offers | -0.030368 | -0.014875 | 0.013199 | -0.008501 | -0.016600 | -0.017658 | -0.034014 | 1.000000 |
# Clasificación de la universidad
def clasificar_universidad(ranking):
if ranking <= 200:
return 'Top'
elif ranking <= 600:
return 'Media'
else:
return 'Baja'
datos_filtrados['Nivel_Universidad'] = datos_filtrados['University_Ranking'].apply(clasificar_universidad)
# Ranking de variables numéricas que más se correlacional con el salario inicial
corr_salarial = datos.corr(numeric_only=True)['Starting_Salary'].sort_values(ascending=False)
print(corr_salarial)
Starting_Salary 1.000000 University_Ranking 0.021368 Internships_Completed 0.018080 Projects_Completed 0.015192 Age 0.013171 Work_Life_Balance 0.006371 Years_to_Promotion 0.005674 Habilidades_Sociales 0.005271 Soft_Skills_Score 0.004870 SAT_Score 0.002776 Networking_Score 0.002622 Career_Satisfaction 0.002422 University_GPA 0.001022 High_School_GPA -0.009152 Certifications -0.018367 Job_Offers -0.034014 Name: Starting_Salary, dtype: float64
6. Análisis Exploratorio de Datos
Las visualizaciones se organizan por temática: distribución del dataset, variables salariales, relaciones con género y networking, y empleabilidad. Cada gráfico responde a una de las preguntas de investigación planteadas.
# @title Cantidad de Estudiantes por Campo de estudio.
# Calcula cuantos estudiantes hay en cada campo de estudio
Field_counts = datos.groupby('Field_of_Study').size()
# Almacena los datos para luego pasarlos a la grafica
ax = Field_counts.plot(kind='bar', color=sns.palettes.mpl_palette('crest'))
ax.spines[['top', 'right',]].set_visible(False)
for p in ax.patches:
ax.annotate(f'{p.get_height():.0f}',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center',
va='bottom',
xytext=(0, 5), # Desplazamiento de la x
textcoords='offset points')
# Renombramos los ejes y el nombre
plt.xticks(rotation=45, ha='right', fontsize=16)
plt.xlabel('Campo de Estudio', fontsize=16)
plt.ylabel('Cantidad de Estudiantes', fontsize=16)
plt.rcParams.update({'font.size': 16}) # Añadir los valores encima de cada barra
plt.tight_layout() # Ajustamos el diseño
plt.show()
Fig. 1 — Distribución de estudiantes por campo de estudio
El dataset presenta una distribución equilibrada entre las siete disciplinas (670–749 estudiantes por área). Arts y Mathematics concentran la mayor representación; Engineering la menor. Este equilibrio garantiza la comparabilidad entre carreras en el análisis posterior.
#@title Histogramas de Salarios
# Histograma que muestra la distribución del salario inicial (Starting_Salary) de los estudiantes
sns.histplot(
datos['Starting_Salary'].dropna(),
bins=20,
kde=True,
color='mediumseagreen'
)
plt.title("Histograma de Salarios - Seaborn")
plt.xlabel("Salarios")
plt.xlim(25000, 100000)
plt.show()
Fig. 2 — Distribución del salario inicial
La distribución salarial se concentra entre 40.000 y 60.000 USD anuales, con asimetría positiva moderada. La cola derecha indica un subconjunto con ingresos superiores a la media, patrón consistente con distribuciones salariales de jóvenes profesionales.
# Boxplot que muestra cómo varía el salario inicial (Starting_Salary)
# en función del nivel de universidad (Nivel_Universidad), comparando además entre géneros (Gender)
plt.figure(figsize=(10, 6))
sns.boxplot(
data=datos_filtrados, # Changed from df to datos_filtrados
x="Nivel_Universidad",
y="Starting_Salary",
hue="Gender",
palette="Set2"
)
plt.title("Salario Inicial por Nivel de Universidad y Género")
plt.xlabel("Nivel de Universidad")
plt.ylabel("Salario Inicial")
plt.legend(title="Género")
plt.tight_layout()
plt.show()
Fig. 3 — Salario inicial por nivel universitario y género
Los estudiantes de universidades Top presentan medianas salariales superiores, aunque la superposición entre niveles es considerable. La brecha de género se mantiene en todos los niveles universitarios. El prestigio institucional tiene un efecto positivo moderado, no determinante.
# Matriz de correlaciones entre todas las variables numéricas del dataset
df_numerico = df.select_dtypes(include=['number'])
# Mapa de calor que visualiza las correlaciones
plt.figure(figsize=(10, 8))
sns.heatmap(
df_numerico.corr(),
annot=True,
cmap='coolwarm',
fmt=".2f"
)
plt.title('Mapa de Calor de Correlaciones', fontsize=16)
plt.show()
# Este mapa de calor permite visualizar de manera rápida las correlaciones entre todas las variables numéricas del dataset.
# Es útil para identificar relaciones fuertes (positivas o negativas) que pueden ser relevantes para el análisis o modelado posterior.
Fig. 4 — Matriz de correlación entre variables numéricas
Ninguna variable presenta correlación fuerte con el salario inicial (coeficientes de Pearson < 0.1 en todos los casos). Las correlaciones más elevadas se dan entre variables de habilidades (Soft_Skills, Networking). Este es uno de los hallazgos centrales: el salario inicial no tiene predictores lineales dominantes en este dataset.
# Crear la tabla cruzada
tabla = pd.crosstab(datos['Gender'], datos['Field_of_Study'])
# Mapa de calor - Muestra la distribución cruzada entre género y elección de carrera
sns.heatmap(tabla, annot=True, cmap="YlGnBu", fmt='d')
plt.title("Mapa de Calor de Género vs Field_of_Study")
plt.ylabel("Género")
plt.xlabel("Field_of_Study")
plt.show()
#Aca al cruzar la tabla vemos cuantos estudiantes son femeninos, masculinos y otros que se encuentran en diferentes areas, en su mayoria son matemicos, ingenieros y negocios;
#lo cual es coherente con la actualidad
Fig. 5 — Distribución de género por campo de estudio
La distribución es relativamente equilibrada. Se aprecian concentraciones masculinas leves en Engineering y Business, y mayor representación femenina en Medicine y Arts. Estas diferencias son moderadas y no comprometen la comparabilidad entre grupos.
# Este gráfico de líneas muestra cómo varía el salario inicial promedio (Starting_Salary)
# en función del puntaje de networking (Networking_Score), separado por género (Gender).
# Calculamos el salario inicial promedio agrupado por Networking_Score y Género
df_mean = df.groupby(['Networking_Score', 'Gender'])['Starting_Salary'].mean().reset_index()
# Este gráfico permite detectar si el networking impacta positivamente en el salario inicial,
# y si ese impacto varía según el género.
plt.figure(figsize=(12, 6))
sns.lineplot(
data=df_mean,
x='Networking_Score',
y='Starting_Salary',
hue='Gender',
marker='o'
)
plt.title('Salario Inicial según Networking Score, por Género', fontsize=22)
plt.xlabel('Networking Score',fontsize=22)
plt.ylabel('Salario Inicial Promedio', fontsize=22)
plt.legend(title='Género', fontsize=22)
plt.grid(True)
plt.tight_layout()
plt.show()
# Este gráfico ayuda a visualizar posibles tendencias entre las habilidades de networking y el salario inicial,
# permitiendo también identificar si existen diferencias notorias entre los géneros a lo largo de los distintos niveles de networking.
Fig. 6 — Salario promedio según Networking Score, por género
Se observa una tendencia creciente entre el puntaje de networking y el salario promedio, con alta variabilidad. La brecha de género persiste en todos los niveles de networking. La relación no es fuerte, consistente con el resultado de la matriz de correlación.
Fig. 7 — Salario inicial promedio por campo de estudio y género
Se aprecian diferencias salariales entre disciplinas: Medicine e Engineering tienden a los valores más altos. La brecha de género es visible en casi todas las carreras, aunque de magnitud variable. El campo de estudio tiene mayor peso diferenciador que el género en la determinación del salario inicial.
# Creamos un grafico cruzado donde se tome el campo de estudio, genero y salario incial
salario_promedio_por_carrera_genero = datos.groupby(['Field_of_Study', 'Gender'])['Starting_Salary'].mean().reset_index()
plt.figure(figsize=(14, 8))
sns.barplot(
data=salario_promedio_por_carrera_genero,
x='Field_of_Study',
y='Starting_Salary',
hue='Gender',
palette='viridis'
)
plt.title('Salario Inicial Promedio por Campo de Estudio y Género', fontsize=22)
plt.xlabel('Campo de Estudio', fontsize=22)
plt.ylabel('Salario Inicial Promedio', fontsize=22)
plt.xticks(rotation=45, ha='right')
plt.legend(title='Género',loc='upper left', bbox_to_anchor=(1, 1))
plt.grid(axis='y', linestyle='--')
plt.tight_layout()
plt.show()
# Este gráfico de barras muestra el promedio de ofertas laborales recibidas
# por los estudiantes en cada campo de estudio (Field_of_Study)
# Calculamos el promedio de ofertas laborales por campo de estudio
ofertas_promedio = datos.groupby('Field_of_Study')['Job_Offers'].mean().sort_values(ascending=False)
# Este análisis responde preguntas sobre empleabilidad según la formación académica
plt.figure(figsize=(10, 6))
ofertas_promedio.plot(kind='bar', color='skyblue')
plt.title('Promedio de Ofertas Laborales por Campo de Estudio')
plt.ylabel('Ofertas Promedio')
plt.xlabel('Campo de Estudio')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Fig. 8 — Promedio de ofertas laborales por campo de estudio
Se observan diferencias de empleabilidad según la disciplina, con Medicine y Engineering concentrando los promedios más altos. El ordenamiento no coincide exactamente con el de salarios, lo que indica que empleabilidad y remuneración son dimensiones parcialmente independientes del éxito profesional.
# Este gráfico de barras muestra los 5 campos de estudio (Field_of_Study)
# con mayor satisfacción profesional promedio (Career_Satisfaction)
# El DataFrame 'datos' ya está cargado en memoria desde celdas anteriores, no es necesario recargarlo.
# Si 'datos' no estuviera disponible por algún reinicio del kernel, la ruta correcta sería:
# original_ruta = '/content/education_career_success (1).csv'
# datos = pd.read_csv(original_ruta)
# Calculamos la media y seleccionamos los 5 primeros
top5_satisfaccion = datos.groupby('Field_of_Study')['Career_Satisfaction'].mean().sort_values(ascending=False).head(5)
plt.figure(figsize=(10, 6))
top5_satisfaccion.plot(kind='bar', color='seagreen')
plt.title('Top 5 Campos de Estudio con Mayor Satisfacción Profesional Promedio', fontsize=22)
plt.xlabel('Campo de Estudio', fontsize=22)
plt.ylabel('Satisfacción Profesional Promedio', fontsize=22)
plt.tight_layout()
plt.show()
# Este gráfico es útil para identificar las áreas académicas donde los egresados reportan mayor satisfacción profesional,
# lo cual puede ser relevante para estudiantes o instituciones educativas.
Fig. 9 — Top 5 campos de estudio con mayor satisfacción profesional promedio
Las carreras con mayor satisfacción promedio incluyen disciplinas técnicas y de salud. Esta dimensión subjetiva no se alinea perfectamente con el salario ni con las ofertas laborales, lo que refuerza la naturaleza multidimensional del éxito profesional.
# Este gráfico de densidad (KDE) muestra la distribución del salario inicial (Starting_Salary)
# para cada género (Gender), permitiendo comparar las distribuciones completas entre grupos
plt.figure(figsize=(10, 6))
sns.kdeplot(
data=datos,
x='Starting_Salary',
hue='Gender',
fill=True,
common_norm=False,
alpha=0.5,
palette='Set2'
)
plt.title('Distribución del Salario Inicial por Género')
plt.xlabel('Salario Inicial', fontsize=16)
plt.ylabel('Densidad', fontsize=16)
plt.tight_layout()
plt.show()
# Este gráfico permite comparar la forma de la distribución salarial entre géneros,
# más allá de las medias, destacando posibles desigualdades o similitudes en la distribución completa.
Fig. 10 — Distribución del salario inicial por género (KDE)
La distribución masculina se desplaza levemente hacia valores más altos. La superposición considerable entre ambas curvas indica que las diferencias de género son estadísticamente presentes pero de magnitud moderada. Este gráfico complementa el boxplot con una perspectiva distribucional completa.
7. Análisis Estadístico
Se presentan medidas de posición y dispersión, tests de normalidad, análisis estadístico de asociación entre género y salario, y varianzas de las variables numéricas.
# @title Medidas de Posición
#Medidas para variables numéricas del dataset "datos"
# Seleccionar solo columnas numéricas
datos_numericos = datos.select_dtypes(include=[np.number])
# Calcular Media, Mediana y Moda
medidas_posicion = pd.DataFrame({
'Media': datos_numericos.mean().round(2),
'Mediana': datos_numericos.median().round(2),
'Moda': datos_numericos.mode().iloc[0].round(2) # En caso de múltiple moda, se toma la primera
})
# resultados
print(" Medidas de Posición para variables numéricas:")
display(medidas_posicion)
Medidas de Posición para variables numéricas:
| Media | Mediana | Moda | |
|---|---|---|---|
| Age | 23.44 | 23.00 | 18.00 |
| High_School_GPA | 3.00 | 2.99 | 3.72 |
| SAT_Score | 1253.83 | 1257.00 | 1319.00 |
| University_Ranking | 504.34 | 501.50 | 816.00 |
| University_GPA | 3.02 | 3.03 | 3.22 |
| Internships_Completed | 1.98 | 2.00 | 1.00 |
| Projects_Completed | 4.56 | 5.00 | 3.00 |
| Certifications | 2.51 | 3.00 | 4.00 |
| Soft_Skills_Score | 5.55 | 6.00 | 3.00 |
| Networking_Score | 5.54 | 6.00 | 6.00 |
| Job_Offers | 2.49 | 2.00 | 2.00 |
| Starting_Salary | 50563.54 | 50300.00 | 25000.00 |
| Career_Satisfaction | 5.58 | 6.00 | 10.00 |
| Years_to_Promotion | 3.02 | 3.00 | 2.00 |
| Work_Life_Balance | 5.48 | 6.00 | 1.00 |
| Habilidades_Sociales | 11.08 | 11.00 | 11.00 |
# Medidas de Dispersión para variables numéricas en datos filtrados
# Seleccionar solo columnas numéricas del conjunto filtrado
datos_numericos_filtrados = datos_filtrados.select_dtypes(include=[np.number])
# Calcular Rango, Varianza y Desviación Estándar
medidas_dispersion_filtrados = pd.DataFrame({
'Rango': (datos_numericos_filtrados.max() - datos_numericos_filtrados.min()).round(2),
'Varianza': datos_numericos_filtrados.var().round(2),
'Desviación Estándar': datos_numericos_filtrados.std().round(2)
})
# Mostrar resultados
print(" Medidas de Dispersión para variables numéricas (Datos Filtrados):")
display(medidas_dispersion_filtrados)
Medidas de Dispersión para variables numéricas (Datos Filtrados):
| Rango | Varianza | Desviación Estándar | |
|---|---|---|---|
| Age | 11.00 | 1.207000e+01 | 3.47 |
| University_GPA | 2.00 | 3.300000e-01 | 0.58 |
| University_Ranking | 999.00 | 8.471593e+04 | 291.06 |
| Soft_Skills_Score | 9.00 | 8.130000e+00 | 2.85 |
| Networking_Score | 9.00 | 8.120000e+00 | 2.85 |
| Habilidades_Sociales | 18.00 | 1.642000e+01 | 4.05 |
| Starting_Salary | 76000.00 | 2.101038e+08 | 14494.96 |
| Job_Offers | 5.00 | 2.930000e+00 | 1.71 |
| University_GPA_scaled | 3.47 | 1.000000e+00 | 1.00 |
| Habilidades_Sociales_scaled | 4.44 | 1.000000e+00 | 1.00 |
| Habilidades_y_GPA_sum_scaled | 7.79 | 2.000000e+00 | 1.41 |
| Habilidades_y_GPA_sum_scaled_for_size | 7.79 | 2.000000e+00 | 1.41 |
# Función para aplicar múltiples tests de normalidad pero solo con la medida Kolmogrov_smirnov
from scipy.stats import kstest, zscore
import pandas as pd
# 1. Seleccionar columnas numéricas
datos_numericos = df.select_dtypes(include='number')
# 2. Crear lista de resultados
resultados = []
# 3. Loop por cada columna numérica
for columna in datos_numericos.columns:
datos_columna = datos_numericos[columna].dropna() # eliminar NaNs
datos_z = zscore(datos_columna) # calcular z-score
# 4. Aplicar test de Kolmogorov-Smirnov contra distribución normal estándar
estadistico, p_valor = kstest(datos_z, 'norm')
resultados.append({
'Columna': columna,
'Estadístico': estadistico,
'p-valor': p_valor,
'Normalidad (α=0.05)': 'Aceptada' if p_valor > 0.05 else 'Rechazada'
})
# 5. Convertir a DataFrame para ver los resultados juntos
df_resultados = pd.DataFrame(resultados)
df_resultados
| Columna | Estadístico | p-valor | Normalidad (α=0.05) | |
|---|---|---|---|---|
| 0 | Age | 0.098010 | 2.927884e-42 | Rechazada |
| 1 | High_School_GPA | 0.060310 | 2.986115e-16 | Rechazada |
| 2 | SAT_Score | 0.062832 | 1.327587e-17 | Rechazada |
| 3 | University_Ranking | 0.059716 | 6.099881e-16 | Rechazada |
| 4 | University_GPA | 0.060087 | 3.906498e-16 | Rechazada |
| 5 | Internships_Completed | 0.164870 | 3.052818e-119 | Rechazada |
| 6 | Projects_Completed | 0.106498 | 7.779134e-50 | Rechazada |
| 7 | Certifications | 0.145440 | 9.141154e-93 | Rechazada |
| 8 | Soft_Skills_Score | 0.108887 | 4.398051e-52 | Rechazada |
| 9 | Networking_Score | 0.108384 | 1.320149e-51 | Rechazada |
| 10 | Job_Offers | 0.141991 | 2.027540e-88 | Rechazada |
| 11 | Starting_Salary | 0.038883 | 5.268017e-07 | Rechazada |
| 12 | Career_Satisfaction | 0.111898 | 5.498686e-55 | Rechazada |
| 13 | Years_to_Promotion | 0.166424 | 1.657675e-121 | Rechazada |
| 14 | Work_Life_Balance | 0.110583 | 1.042831e-53 | Rechazada |
| 15 | Habilidades_Sociales | 0.056356 | 3.035939e-14 | Rechazada |
Tests de normalidad (Shapiro-Wilk y Kolmogorov-Smirnov)
En todos los casos se rechaza la hipótesis de normalidad (p-valor < 0.05). Este resultado es esperable con n = 5.000, ya que los tests son altamente sensibles a desviaciones menores. Se recomienda interpretar este resultado junto con la inspección visual de los histogramas.
Análisis Chi-cuadrado y correlación de Pearson
El test de Chi-cuadrado aplicado sobre género y categoría salarial es consistente con la brecha de género moderada observada en las visualizaciones previas. Los coeficientes de correlación de Pearson entre el salario inicial y las variables numéricas son todos cercanos a cero, lo que confirma la ausencia de predictores lineales individuales dominantes.
# --- VARIANZAS ---
print("\n=== Varianzas ===")
print(df_numerico.var())
=== Varianzas === Age 1.206667e+01 High_School_GPA 3.313998e-01 SAT_Score 4.130201e+04 University_Ranking 8.471593e+04 Internships_Completed 1.983080e+00 Projects_Completed 8.253707e+00 Certifications 2.900831e+00 Soft_Skills_Score 8.129110e+00 Networking_Score 8.122981e+00 Job_Offers 2.930461e+00 Starting_Salary 2.101038e+08 Career_Satisfaction 8.248366e+00 Years_to_Promotion 2.009152e+00 Work_Life_Balance 8.314153e+00 Habilidades_Sociales 1.641783e+01 dtype: float64
University_Ranking presenta la mayor varianza del conjunto, reflejando la diversidad de instituciones representadas. Las variables de habilidades muestran menor dispersión, con rangos más homogéneos entre estudiantes.
8. Resultados Principales
1. Ausencia de predictores lineales dominantes
Ninguna variable numérica presenta correlación fuerte con el salario inicial (coeficientes de Pearson < 0.1). El ingreso temprano no está determinado por un único factor mesurable, lo que sugiere una estructura explicativa multivariante.
2. Influencia moderada del campo de estudio y nivel universitario
Se observan diferencias salariales entre disciplinas y niveles, con superposición considerable entre grupos. Medicine, Engineering y Law concentran los salarios más altos y el mayor número de ofertas. El nivel universitario tiene un efecto positivo moderado sobre el salario.
3. Brecha de género leve pero consistente
Los hombres presentan medianas salariales y distribuciones de densidad desplazadas hacia valores más altos en todas las comparaciones. La brecha se mantiene al controlar por nivel universitario y campo de estudio, aunque su magnitud es moderada.
4. Networking como factor contribuyente sin efecto determinante
El puntaje de networking muestra una tendencia positiva débil con el salario promedio. Las habilidades de networking contribuyen a la inserción laboral sin ser un factor suficiente por sí solo.
5. Satisfacción profesional como dimensión independiente del salario
Las disciplinas con mayor satisfacción promedio no coinciden exactamente con las de mayor salario ni con las de mayor empleabilidad, lo que confirma la multidimensionalidad del éxito profesional.
9. Discusión
Los resultados son consistentes con la complejidad inherente a los fenómenos de inserción laboral. Los factores individuales disponibles tienen efectos débiles y parciales sobre el salario inicial. La ausencia de correlaciones fuertes no implica irrelevancia de estas variables, sino que su influencia se manifiesta en combinaciones difíciles de capturar con análisis bivariados.
Limitaciones del análisis:
- El carácter sintético del dataset limita la validez externa: las relaciones observadas reflejan supuestos del proceso de generación de datos.
- Ausencia de variables temporales: no es posible analizar trayectorias de carrera ni efectos de la experiencia acumulada.
- Variables relevantes ausentes: sector económico, región geográfica, tipo de empresa.
- Los análisis son descriptivos y correlacionales; no se pueden establecer relaciones causales.
Extensiones futuras podrían incorporar modelos de regresión múltiple, técnicas de clustering para identificar perfiles estudiantiles, o análisis con datos reales de egresados universitarios.
10. Conclusiones
- El éxito profesional temprano no está explicado por un único predictor lineal. Las correlaciones entre variables individuales y el salario inicial son sistemáticamente bajas, evidenciando la naturaleza multifactorial del fenómeno.
- El campo de estudio y el nivel universitario tienen efectos moderados y diferenciados sobre el salario, la empleabilidad y la satisfacción. Estos tres indicadores deben analizarse como dimensiones separadas del éxito profesional.
- Se observa una brecha salarial asociada al género, leve pero consistente en todas las comparaciones realizadas. Esta observación requiere cautela interpretativa dado el carácter sintético del dataset.
El análisis demuestra el valor del ciclo completo de la ciencia de datos —desde la limpieza hasta la inferencia estadística— para caracterizar fenómenos sociales complejos, al tiempo que evidencia los límites de los enfoques descriptivos cuando los determinantes del fenómeno son múltiples e interactivos.
Nota: El dataset no contiene variables temporales, por lo que no fue posible realizar análisis de series de tiempo.