Documentos de Académico
Documentos de Profesional
Documentos de Cultura
import os
from sklearn.metrics import mean_squared_error
%matplotlib inline
plt.style.use('ggplot')
[61]: #Cuando no tenga una libreria con la siguiente linea la pueden instalar
#pip install char_studio
1.1 Introducción
Contexto. Eres un científico de datos en una gran organización. Su empresa está pasando por una
revisión interna de sus prácticas de contratación y compensación a los empleados. En los últimos
años, su empresa ha tenido poco éxito en la conversión de candidatas de alta calidad que deseaba
contratar. La gerencia plantea la hipótesis de que esto se debe a una posible discriminación salarial
y quiere averiguar qué la está causando.
En general, ¿se les paga más a los hombres que a las mujeres en su organización? Si es así, ¿qué
conduciendo esta brecha?
Se tiene una base de datos de empleados que contiene información sobre varios atributos como
desempeño, educación, ingresos, antigüedad, etc
1
1.2 Estadística Descriptiva
[10]: Data.head()
• job title: el título del trabajo (por ejemplo, “Diseñador gráfico”, “Ingeniero de software”,
etc.);
• gender: hombre o mujer;
• age: edad;
• performance: desempeño en una escala del 1 al 5, siendo 1 el más bajo y 5 el más alto;
• education: diferentes niveles de educación (por ejemplo, “Universidad”, “Doctorado”,
“Maestría”, “Escuela secundaria”);
• departament: diferentes departamentos de la organización (por ejemplo, “Operaciones”,
“Gestión”, etc.);
• seniority: antiguedad en una escala de 1 a 5, siendo 1 la más baja y 5 la más alta;
• income, bonus: ingresos y bonificación ambos expresados en dólares
Se crea una nueva columna con el ingreso total
[12]: Data.head()
2
1 5 108476 11128 119604
2 5 90208 9268 99476
3 4 108080 10154 118234
4 5 99464 9319 108783
3
Inferencia - Pruebas de Hipótesis Probar si hay una diferencia en el pago promedio entre hom-
bres y mujeres con una prueba t-student a un nivel de confianza del 95%
[60]: gender
Female 96416.831197
Male 104918.678571
Name: pay, dtype: float64
t = 5.407461816876623
p = 8.000016978237565e-08
Rta. Dado que el p valor < 0.05. Rechazo la hipótesis nula. Así, con un nivel de confianza del 95
existe una diferencia significativa entre el ingreso promedio total de los hombres y mujeres.
4
[61]: 8501.847374847363
5
[64]: # ingresos totales vs antiguedad
sns.boxplot(x='seniority', y = 'pay', data = Data, palette="Set3")
plt.title("Pay vs. Seniority", fontsize=20, verticalalignment='bottom');
6
[26]: # inbresos totales vs desempeño
sns.boxplot(x='performance', y = 'pay', data = Data, palette="Set3")
plt.title("Pay vs. Performance", fontsize=20, verticalalignment='bottom');
7
[27]: # ingresos vs tipo de trabajo
sns.boxplot(x='jobtitle', y = 'pay', data = Data, palette="Set3")
plt.title("Pay vs. Jobtitle", fontsize=20, verticalalignment='bottom')
plt.xticks(rotation=90);
8
1.2.1 Evaluando los atributos por Género
9
[29]: sns.boxplot(x='seniority', y = 'pay', hue = 'gender', data = Data,␣
,→palette="Set3")
10
[30]: sns.boxplot(x='performance', y = 'pay', hue = 'gender', data = Data,␣
,→palette="Set3")
11
[31]: sns.boxplot(x='jobtitle', y = 'pay', hue = 'gender',data = Data, palette="Set3")
plt.title("Pay vs. Jobtitle", fontsize=20, verticalalignment='bottom')
plt.xticks(rotation=90);
12
1.3 ¿Cuáles son las variables que influyen en la remuneración?
1.3.1 La correlación mide la relación lineal entre dos variables
Vemos una relación lineal entre salario y edad. El salario parece estar correlacionado positiva-
mente con la edad; es decir, cuanto mayor es una persona, más tienden a ganar. Por lo tanto,
podría ser que hay más hombres en nuestro conjunto de datos que sean mayores y la diferencia
salarial entre hombres y mujeres que vemos podría ser una consecuencia de esto. La correlación
cuantitativa mide qué tan lineal es la relación entre dos variables.
13
[50]: plt.figure(figsize=(12,10))
rho = [0.999, -0.999, 0.5, -0.7,0.001,-0.3]
cor_list = []
np.random.seed(10)
for i, r in enumerate(rho):
plt.subplot(2,3,i+1)
mean, cov = [4, 6], [(1, r), (r, 1)]
x, y = np.random.multivariate_normal(mean, cov, 150).T
ax = sns.scatterplot(x=x, y=y, color="g")
cor_list.append(np.corrcoef(x,y)[0,1])
plt.xlabel("x")
plt.ylabel("y")
plt.title("Correlación")
14
[11]: cor_list
[11]: [0.9990081442281219,
-0.9992506121564401,
0.5047051300834762,
-0.7228982219723221,
-0.04041125768713201,
-0.32083184263386666]
Para encontrar las variables que tienen la mayor influencia en el salario, podemos calcular una
matriz de correlación que mide las correlaciones por pares entre dos variables cualesquiera:
corr_mat
15
[51]: pay age seniority performance
pay 1.000000 0.533715 0.530307 0.014155
age 0.533715 1.000000 -0.021414 -0.056875
seniority 0.530307 -0.021414 1.000000 -0.021127
performance 0.014155 -0.056875 -0.021127 1.000000
1.4 Uso de modelos lineales para tener en cuenta las variables correlacionadas con el
ingreso
Una vez que identificamos algunas variables independientes que están correlacionadas con la
variable dependiente, se puede utilizar un modelo lineal para capturar esta relación cuantitativa-
mente.
[52]: sns.lmplot(x = 'age', y = 'pay', data = Data, scatter_kws = {'color': (174/
,→255,199/255,14/255)})
16
[52]: Text(-15.450000000000003, 0.5, 'Pay')
Una línea tiene dos parámetros: intersección o intercepto (β 0 ) y pendiente (β 1 ). Por lo tanto, un
modelo lineal de ingreso total frente a la edad se puede representar como
17
1.4.1 Escenarios
[53]: from bqplot import *
from IPython.display import display
from bqplot.interacts import (
FastIntervalSelector, IndexSelector, BrushIntervalSelector,
BrushSelector, MultiSelector, LassoSelector, PanZoom, HandDraw
)
import ipywidgets as widgets
from ipywidgets import *
def run_scenario(scenario='1'):
elif (scenario=='2'):
# defining x,y coordinates, scenario 1
x_coor = [18, 26, 28, 30, 32, 34, 36, 38, 40, 20, 24]
y_coor = [50000, 63000, 70000, 67000, 80000, 75000, 88000, 90000, 92000,␣
,→85000, 70000]
elif (scenario=='3'):
# defining x,y coordinates, scenario 1
x_coor = [18, 20, 22, 32, 34, 36, 38, 40, 38, 36]
y_coor = [50000, 53000, 60000, 80000, 75000, 88000, 90000, 92000, 50000,␣
,→52000]
elif (scenario=='4'):
# defining x,y coordinates, scenario 1
x_coor = [18, 20, 22, 24, 26, 28, 30, 38, 40, 35, 22]
y_coor = [50000, 53000, 60000, 59000, 63000, 70000, 67000, 90000, 92000,␣
,→55000, 90000]
18
for i in range(0, len(x_coor)):
name = str(x_coor[i]) + ', ' + str(y_coor[i])
names.append(name)
y_hat_values = []
for x in x_coor:
new_y_val = a + (b * x)
y_hat_values.append(new_y_val)
19
starting_user_line = Lines(x=user_line_x, y=user_line_y, scales={'x': x_sc,␣
,→ 'y': y_sc}, colors=['green'])
out = Output()
display(out)
def handler(x):
print('hi')
@out.capture()
def observe_scatter_x_y(point, change):
x_array = point.x
y_array = point.y
find_change_x = change['point']['x']
find_change_y = change['point']['y']
hovered_point = point.hovered_point
if (hovered_point == 0):
starting_user_line.set_trait('x', [find_change_x, x_array[1]])
starting_user_line.set_trait('y', [find_change_y, y_array[1]])
# starting_user_line.y[0] = find_change_y
# starting_user_line.x[0] = starting_user_line.x.pop(0)
# starting_user_line.y = starting_user_line.y.pop(0)
# starting_user_line.x = starting_user_line.x.insert(0,␣
,→find_change_y)
# starting_user_line.y = starting_user_line.y.insert(0,␣
,→find_change_y)
20
elif (hovered_point == 1):
starting_user_line.set_trait('x', [x_array[0], find_change_x])
starting_user_line.set_trait('y', [y_array[0], find_change_y])
# starting_user_line.x = starting_user_line.x.pop(1)
# starting_user_line.y = starting_user_line.y.pop(1)
# starting_user_line.x = starting_user_line.x.insert(1,␣
,→find_change_y)
# starting_user_line.y = starting_user_line.y.insert(1,␣
,→find_change_y)
# if change['name'] == 'x':
# line.x = line.x + change['new'] - change['old']
# else:
# line.y = line.y + change['new'] - change['old']
scatter.on_drag(observe_scatter_x_y)
@out.capture()
def on_dropdown_change(b):
fig.close()
button.close()
dropdown.close()
run_scenario(dropdown.value)
dropdown.observe(on_dropdown_change, 'value')
,→justify_content='center', width='300px'))
def on_button_clicked(b):
regression_line.set_trait('visible', True)
button.on_click(on_button_clicked)
box_layout = Layout(display='flex',
justify_content='center',
width='50%')
21
run_scenario()
Output()
Dropdown(description='Escenario:', options=('1', '2', '3', '4'), value='1')
Figure(axes=[Axis(grid_lines='dashed', label='Age', label_color='blue',␣
,→num_ticks=8, scale=LinearScale(max=40....
1.4.2 Residuales
El residual representa la diferencia entre la observación real y la predicha por la línea de regresión
lineal, como se muestra a continuación:
[54]: from bqplot import *
from IPython.display import display
from bqplot.interacts import (
FastIntervalSelector, IndexSelector, BrushIntervalSelector,
BrushSelector, MultiSelector, LassoSelector, PanZoom, HandDraw
)
import ipywidgets as widgets
from ipywidgets import *
22
def_tt = Tooltip(fields=['x', 'y'], formats=['', '.2f'])
,→selected=[5])
out = Output()
display(out)
@out.capture()
def on_scatter_click(marks, dot):
marks.set_trait('selected', [dot['data']['index']])
scatter.on_element_click(on_scatter_click)
y_hat_values = []
for x in x_coor:
new_y_val = a + (b * x)
y_hat_values.append(new_y_val)
23
fig = Figure(marks=[scatter, regression_line], axes=[ax_x, ax_y],␣
,→title='Residuales',)
,→justify_content='center', width='300px'))
@out.capture()
def on_button_clicked(b):
answer = 12
scatter.set_trait('selected', [answer])
residual_line=Lines(x=[x_coor[answer], x_coor[answer]], y=[y_coor[answer],␣
,→y_hat_values[answer]], scales={'x': x_sc, 'y': y_sc}, colors=['red'])
button.on_click(on_button_clicked)
box_layout = Layout(display='flex',
justify_content='center',
width='50%')
display(fig, box)
Output()
Figure(axes=[Axis(grid_lines='dashed', label='Age', label_color='blue',␣
,→num_ticks=8, scale=LinearScale(max=40....
24
random_state = 1234,
shuffle = True
)
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
25
[ ]:
1.5.1 Coeficientes
La intersección β 0 es de aproximadamente 60560 USD. Esto se puede considerar como el salario
base. (Con frecuencia, la intersección no tiene una interpretación significativa, eso está bien). La
pendiente (el coeficiente β 1 para la edad) es 939,25. La interpretación de este coeficiente es si un
empleado envejece un año, se espera que su salario aumente en 967,56 USD en promedio.
Es importante tener en cuenta que la forma en que limpiamos / imputamos los datos antes del
modelado tendrá enormes efectos en los coeficientes que obtenga. Un ejemplo simple es si conver-
timos arbitrariamente todos los valores faltantes a la media de ese parámetro. Esto conducirá a un
coeficiente completamente diferente que si usáramos k - imputación de vecinos más cercanos. Por
eso es tan importante elegir cuidadosa y deliberadamente un método de imputación apropiado
cuando se trata de datos faltantes o incorrectos.
1.5.2 $ p $ -valor
El sistema de hipótesis que estamos probando es
H0 : β i = 0
Ha : β i 6= 0.
El p-valor de β 1 (dado debajo de la columna: ”P > |t|”) es 0.000. Por lo tanto, es estadísticamente
significativo al nivel de significancia del 0.05 y rechazamos la hipótesis nula. Esto implica que la
edad explica algunas de las diferencias salariales.
1.6 $ R $ Cuadrado
Una de las cantidades clave a las que se debe prestar atención al interpretar una tabla de regresión
es la cantidad [$ R $ -cuadrado]. Tenga en cuenta que la tabla muestra R cuadrado y $ R $ cuadrado
ajustado. Nos centraremos en $ R $ cuadrado. Esta cantidad siempre estará entre 0 y 1. Para el
modelo de salario vs. edad, esta cantidad es 0.30 = 30%.
Un $ R $ cuadrado de 30% en este modelo lineal significa que esta variación observada en el
salario no se debe a una casualidad; más bien, el factor edad explica sistemáticamente el 30% de
esta variación salarial. Cuanto mayor sea este parametro, mayor será el porcentaje de variación
observada que puede ser explicada por el modelo. Dado que model1 solo explica aproximada-
mente el 30% de la variación, esto nos motiva a investigar si otros factores además de la edad
pueden utilizarse para explicar las diferencias salariales.
26
1.6.1 Relación entre correlación y $ R $ cuadrado
[27]: 0.28485128851108266
27
Considere el model0 dado por
pay = β 0 + error
La mejor estimación para β 0 es solo el salario promedio. R cuadrado mide qué tan bien la línea de
regresión de model1 (ingresos frente a edad) dada por la línea roja explica la variación observada
en comparación con model0 . La suma de los cuadrados residuales para este modelo es el RSS
28
print("")
print(f"El error (rmse) del test es: {rmse}")
29
numérica (por ejemplo, 26,5, 32). Por el contrario, el género toma solo dos valores: masculino y
femenino. Estas variables se denominan variables categóricas . La forma en que interpretamos los
coeficientes de las variables factoriales en el modelo lineal es ligeramente diferente de los de las
variables numéricas:
[35]: # otra forma de dividir la base de datos
np.random.seed(10000) # todos usamos la misma semilla para obtener la misma␣
,→muestra
ndata = len(Data)
# Selección del 80% de la muestra para el entrenamiento del modelo
idx_train = np.random.choice(range(ndata),int(0.8*ndata),replace=False)
idx_test = np.asarray(list(set(range(ndata)) - set(idx_train)))
train = Data.iloc[idx_train] # the training data set
test = Data.iloc[idx_test] # the test data set
print(train.shape) # 800 empleados
print(test.shape) # 200 empleados
(800, 10)
(200, 10)
30
Omnibus: 2.118 Durbin-Watson: 1.947
Prob(Omnibus): 0.347 Jarque-Bera (JB): 2.167
Skew: 0.100 Prob(JB): 0.338
Kurtosis: 2.842 Cond. No. 2.69
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
[44]: # La función C() me ayuda para indicarle al modelo que es una variable categórica
model2 = 'pay~C(gender)'
lm2 = smf.ols(formula = model2, data = train).fit()
lm2.summary()
Warnings:
31
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
[46]: print(lm2.params)
Intercept 96357.235450
C(gender)[T.Male] 8809.650806
dtype: float64
[48]: print(lm2.aic)
18455.077458508338
[49]: print(lm2.bic)
18464.446681963673
[62]: print(lm2.rsquared*100)
3.082594426218521
[96]: train_dummy
32
5 IT 20 5 PhD Operations
165 Software Engineer 49 5 Masters Administration
42 Software Engineer 31 5 PhD Sales
33
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
1.7.2 Ejercicio 1
Construya un modelo lineal simple donde explique el ingreso total de acuerdo al nivel de Edu-
cación
34
1.7.3 Ejercicio 2
Construya un modelo lineal simple donde explique el ingreso total de acuerdo al título del em-
pleado
1.7.4 Ejercicio 3
Construya un modelo lineal simple donde explique el ingreso total de acuerdo a la antiguedad del
empleado
1.7.5 Ejercicio 4
Compare todos los R-Cuadrados de los modelos previos. Que puede concluir?
1.7.6 RESIDUALES
[111]: #Retomando el modelo de ingresos totales vs la edad en la prueba de entrenamiento
lm1.summary()
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
35
2 Aleatorios
Lo que se busca es una distribución aleatoria de los residuales. Esto podría indicar que un modelo
lineal probablemente da un buen ajuste. Si se observa una tendencia, podría indicar presencia de
autocorrelación o heteroscedasticidad en el modelo.
36
3 NORMALIDAD
3.0.1 Jarque Bera
El estadístico de prueba de Jarque-Bera prueba
H_0: Los residuales se distribuyen normalmente
H_1: Los resiudales siguen alguna otra distribución
El estadístico de prueba se basa en dos momentos de los datos, la asimetría y la curtosis, y tiene
una distribución asintótica de χ2 .
La estadística de prueba está definida
JB = n (S^2 / 6 + (K 3) 2/24)
[152]: stats.jarque_bera(residuales)
[153]: stats.normaltest(residuales)
37
[180]: sm.graphics.qqplot(residuales, dist=stats.norm, line='45', fit=True)
[180]:
38
39
4 Heterocedasticidad
40
Un test muy común para probar la presencia de heteroscedasticidad es la prueba de hipótesis
Breusch-Pagan, también podemos utilizar el test de White
[149]: # p value < alpha rechazo Ho, Ho: Los residuos son homocedasticos vs Ha: Los␣
,→residuos son heterocedasticos
smd.het_breuschpagan(residuales, lm1.model.exog)[1]
#en este caso no Rechazo la Hipótesis nula
[149]: 0.6289249851413743
[156]: 0.8856432056843238
5 AUTOCORRELACIÓN
Otro de los supuestos detrás del modelo de regresión lineal es que los residuales no tienen autocor-
relación seriál. Una serie está autocorrelacionada cuando tiene correlación con su serie rezagada.
Lo evaluamos mediante el test Ljung-Box.
[165]: autocorr[1]
41
[165]: array([0.13274535, 0.32285689, 0.26125155, 0.28156729, 0.4090433 ,
0.53061748, 0.62949274, 0.42767392, 0.38785897, 0.17654873])
[170]: 2.104969794184385
5.1 Bibliografía:
Este notebook y la base de datos están basados en el curso Data Science for All DS4A - Correlation
One y el Ministerio de Tecnología MINTIC
42