El objetivo de este notebook es buscar predecir el salario de una persona en función de ciertas características, como su edad, nivel de escolaridad etc. Lo anterior a través de la experimentación con técnicas de Machine Learning.
Los datos utilizados son de origen en Kaggle bajo licencia Community Data License Agreement – Sharing, Version 1.0
Se inicia el proceso con la carga de los datos,
salario <- read.csv("Data/Salary_Data.csv", dec = ".")
head(salario)
| Age | Gender | Education.Level | Job.Title | Years.of.Experience | Salary |
|---|---|---|---|---|---|
| 32 | Male | Bachelor’s | Software Engineer | 5 | 90000 |
| 28 | Female | Master’s | Data Analyst | 3 | 65000 |
| 45 | Male | PhD | Senior Manager | 15 | 150000 |
| 36 | Female | Bachelor’s | Sales Associate | 7 | 60000 |
| 52 | Male | Master’s | Director | 20 | 200000 |
| 29 | Male | Bachelor’s | Marketing Analyst | 2 | 55000 |
str(salario)
## 'data.frame': 6702 obs. of 6 variables:
## $ Age : int 32 28 45 36 52 29 42 31 26 38 ...
## $ Gender : chr "Male" "Female" "Male" "Female" ...
## $ Education.Level : chr "Bachelor's" "Master's" "PhD" "Bachelor's" ...
## $ Job.Title : chr "Software Engineer" "Data Analyst" "Senior Manager" "Sales Associate" ...
## $ Years.of.Experience: num 5 3 15 7 20 2 12 4 1 10 ...
## $ Salary : int 90000 65000 150000 60000 200000 55000 120000 80000 45000 110000 ...
El dataset cuenta con 6.704 registros y 6 variables, producto de la recolección a través de encuestas, ofertas de empleo y otras fuentes publicas según especifica el autor.
La distribución de variables esta dada:
| Variable | Tipo | Descripción |
|---|---|---|
| Age | Discreta | Edad del empleado |
| Gender | Nominal | Genero del empleado |
| Education Level | Nominal | Nivel de escolaridad del empleado |
| Job title | Nominal | Cargo del empleado |
| Years of experience | Continua | Años de experiencia del empleado |
| Salary | Discreta | Salario del empleado (valor a predecir) |
Se verifican estadísticos iniciales para las variables cuantitativas donde se encuentra:
$ 115.327 Mensuales, el valor mínimo da una primera
impresión de ser un error de recolección, sin embargo se realizara un
análisis detallado de los valores atípicos en una siguiente
instancia.summary(salario[,c(1, 5, 6)])
| Age | Years.of.Experience | Salary | |
|---|---|---|---|
| Min. :21.00 | Min. : 0.000 | Min. : 350 | |
| 1st Qu.:28.00 | 1st Qu.: 3.000 | 1st Qu.: 70000 | |
| Median :32.00 | Median : 7.000 | Median :115000 | |
| Mean :33.62 | Mean : 8.095 | Mean :115327 | |
| 3rd Qu.:38.00 | 3rd Qu.:12.000 | 3rd Qu.:160000 | |
| Max. :62.00 | Max. :34.000 | Max. :250000 | |
| NA | NA’s :1 | NA’s :3 |
describe(salario[, c(1, 5, 6)])
| vars | n | mean | sd | median | trimmed | mad | min | max | range | skew | kurtosis | se | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Age | 1 | 6702 | 3.362086e+01 | 7.614633 | 32 | 3.281723e+01 | 7.4130 | 21 | 62 | 41 | 0.9051906 | 0.185473 | 0.0930137 |
| Years.of.Experience | 2 | 6701 | 8.094687e+00 | 6.059003 | 7 | 7.440496e+00 | 5.9304 | 0 | 34 | 34 | 0.9807484 | 0.766085 | 0.0740170 |
| Salary | 3 | 6699 | 1.153270e+05 | 52786.183911 | 115000 | 1.151674e+05 | 66717.0000 | 350 | 250000 | 249650 | 0.0573182 | -1.167340 | 644.9340070 |
En cuanto a la forma de las variables, se observa un valor positivo
de asimetria en las variables Age y
Years of experience lo que podría indicar una mayor
concentración de valores en la parte inicial de las distribuciones
-personas jovenes con baja experiencia, lo que es coherente con la
realidad-, así como un valor negativo de curtosis que indica una
concentración de datos de manera aplanada (ausencia de pico).
Se reemplazan los datos faltantes por su media y se ajusta el tipo de cada variable (Gender & Education level -> Factor)
Se visualiza la distribución de las variables cuantitativas, donde se puede apreciar los concepto mencionados anteriormente sobre el comportamiento de cada variable.
Respecto al salario, se observa una gran concentración cuasiunifrome de datos entre $50.000 y $200.000.
Luego, se realiza la verificación y composición de las variables categóricas (Cualitativas)
Cantidad de empleados de acuerdo con su genero
| Genero | Total | F_relativa |
|---|---|---|
| Male | 3674 | 0.548 |
| Female | 3014 | 0.450 |
| Other | 14 | 0.002 |
Cantidad de empleados de acuerdo con su nivel educativo
| nivel_educacion | Total | F_relativa |
|---|---|---|
| Bachelor’s Degree | 3023 | 0.451 |
| Master’s Degree | 1861 | 0.278 |
| phD | 1369 | 0.204 |
| High School | 448 | 0.067 |
| Other | 1 | 0.000 |
La muestra cuenta con un total de 193 cargos diferentes asociados principalmente al desarrollo de software, análisis de datos, recursos humanos, marketing, y RH, de los cuales se muestran los mas recurrentes:
Como se preveía, se observa como la experiencia y edad de los empleadas, pueden ser fuertes candidatas a explicar y aportar información para la predicción de salarios, al tener estas una relación visualmente directa y aunque se bien no es totalmente lineal en la fase de modelamiento podría contemplarse alguna transformación (logaritmo) para mejorar esta relación y entregar mucha mas información a los modelos de regresión, así mismo, y coherente con la realidad, una relación lineal y directa entre la variable de edad y experiencia profesional y aquí se observa como la mayoría de datos (IQR) se encuentran concentrados en personas mas jóvenes (sesgo de la muestra).
Distribución de variables en función del Genero
Distribución de variables en función del Nivel educativo
Se ejecuta análisis de correlación entre las variables cuantitativas,
con el objetivo de identificar posibles variables no explicativas, sin
embargo y aunque en relación a la variable salario los años
de experiencia tienen una correlación de 0.8 lo que podría afectar el
modela-miento, se deja como susceptible de eliminación durante dicha
fase.
Dado que desde la fuente los datos tienen una muy buena calidad, y los pocos faltantes se completaron a través de la media, no se ejecutara ninguna acción durante el proceso de limpieza de datos.
Únicamente se divide el salario entre 1000 para manejar el dato en miles de USD
Se garantiza que las variables categóricas se encuentren como factor (para que el modelo las convierta a dummies y elimine una para evitar problemas de multicolinealidad).
Se generan los conjuntos de entrenamiento y test.
set.seed(42)
salario_f<- salario
names(salario_f)<- c("Age", "Gender", "Education.Level", ".", "Years.of.Experience", "Salary")
head(salario_f)
| Age | Gender | Education.Level | . | Years.of.Experience | Salary |
|---|---|---|---|---|---|
| 32 | Male | Bachelor’s Degree | Software Engineer | 5 | 90000 |
| 28 | Female | Master’s Degree | Data Analyst | 3 | 65000 |
| 45 | Male | phD | Senior Manager | 15 | 150000 |
| 36 | Female | Bachelor’s Degree | Sales Associate | 7 | 60000 |
| 52 | Male | Master’s Degree | Director | 20 | 200000 |
| 29 | Male | Bachelor’s Degree | Marketing Analyst | 2 | 55000 |
salario_f<- dummy_cols(salario_f, select_columns = c("Gender", "Education.Level", "."), remove_first_dummy = TRUE)
salario_f<- salario_f[,c(-2, -3, -4)]
sample<- sample.int(nrow(salario_f), floor(.8*nrow(salario_f)))
salario_train <- salario_f[sample,]
salario_test<- salario_f[-sample,]
salario_train$Salary<- sapply(salario_train$Salary, FUN = function(x){x/1000})
salario_test$Salary<- sapply(salario_test$Salary, FUN = function(x){x/1000})
Un primer modelo a probar sera la regresión lineal para
predecir el salario en función las variables Age y
Years of experience que tenían una correlación interesante,
durante el procesos descriptivo.
#creacion de modelo basico
regresion0 <- lm(Salary~Age + Years.of.Experience, data = salario_train)
summary(regresion0)
##
## Call:
## lm(formula = Salary ~ Age + Years.of.Experience, data = salario_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -154.394 -20.900 -6.335 21.271 99.289
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 101.7202 3.9103 26.01 <2e-16 ***
## Age -1.8038 0.1598 -11.29 <2e-16 ***
## Years.of.Experience 9.2314 0.2008 45.97 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 30.73 on 5358 degrees of freedom
## Multiple R-squared: 0.6626, Adjusted R-squared: 0.6625
## F-statistic: 5261 on 2 and 5358 DF, p-value: < 2.2e-16
El modelo con las variables seleccionadas (Edad, años de experiencia)
como predictores del salario, logran obtener un \(R^2 = 0.66\) es decir, que logra recoger un
66% de variabilidad de los datos. Así mismo el p-value es
significativo por lo que es posible rechazar la hipótesis nula y afirmar
que los resultados del modelo no son causados por el azar, finalmente,
las dos variables predictoras tienen coeficientes significativos lo que
indican que están aportando información al modelo.
Dados los resultados su interpretación es:
\[Salario = 101.720 + (Edad)\cdot-1.8 + (Experiencia)\cdot9.23\] La base son 101.720 USD y por cada año de edad que tenga la persona se restaran 1.80 USD y se sumaran 9.23 USD por cada año de experiencia con la que cuenta.
Finalmente el modelo aunque no es explicado por el azar tiene un error residual alto \((\pm 30.730 \ USD)\) y esa variabilidad quizá se podrá explicar con el resto de variables que aun no fueron incluidas para su entrenamiento, y con las cuales se experimentara en siguientes ejercicios.
Dado que es un modelo entrenado a partir de dos variables cuantitativas, es posible representarlo de manera tridimensional, (esto ya no sera posible en futuros ejercicios dado que no existen herramientas para representar mas de 3D)
Cada uno de los puntos representa la ubicación de cada una de las observaciones en el plano tridimensional, mientras que el plano (azul) representa el plano de regresión creado por el modelo a través de las variables predictoras.
Una premisa inicial es la explicabilidad por separado de las variables edad y experiencia, sin embargo en el gráfico se puede observar como se sobrevalora el salario, cuando un empleado tiene un valor alto en una de las variables predictoras y bajo en la otra, este comportamiento puede sugerir que existe interacción entre estas dos variables, por lo que es posible agregar este nuevo enfoque al modelo.
regresion1 <- lm(Salary~Age + Years.of.Experience + Age:Years.of.Experience, data = salario_train)
summary(regresion1)
##
## Call:
## lm(formula = Salary ~ Age + Years.of.Experience + Age:Years.of.Experience,
## data = salario_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -98.118 -20.429 -5.941 15.074 105.165
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 25.365475 4.209817 6.025 1.8e-09 ***
## Age 0.484454 0.160158 3.025 0.0025 **
## Years.of.Experience 18.855096 0.338347 55.727 < 2e-16 ***
## Age:Years.of.Experience -0.249087 0.007377 -33.767 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 27.91 on 5357 degrees of freedom
## Multiple R-squared: 0.7218, Adjusted R-squared: 0.7216
## F-statistic: 4633 on 3 and 5357 DF, p-value: < 2.2e-16
Con esta adición el \(R^2\) del modelo aumento a 0.72 mientras que el error residual bajo a $27.910 USD (Igualmente continua siendo alto), en futuros modelos se incluirán el resto de variables para intentar explicar esta variabilidad.
\[Salario = 25.365 + (0.48 + (-0.24)\cdot (Experiencia))\cdot (Edad) + (Experiencia)\cdot 18.85\]
Regresión con la inclusión del dataset completo
Se entrena modelo de regresión con el total de las variables
options(max.print = 150)
regresion2<- lm(Salary~., data = salario_train)
summary(regresion2)
##
## Call:
## lm(formula = Salary ~ ., data = salario_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -119.406 -9.974 0.260 10.499 66.209
##
## Coefficients: (20 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 39.1304 21.7334 1.800 0.07184
## Age 0.6043 0.1344 4.498 7.02e-06
## Years.of.Experience 4.6228 0.1660 27.843 < 2e-16
## Gender_Male 0.6283 0.6817 0.922 0.35679
## Gender_Other -18.6670 6.6311 -2.815 0.00490
## `Education.Level_Bachelor's Degree` -7.2091 1.4209 -5.073 4.04e-07
## `Education.Level_High School` -22.8226 2.7545 -8.286 < 2e-16
## `Education.Level_Master's Degree` -1.4719 1.2448 -1.182 0.23709
## Education.Level_phD NA NA NA NA
## ._Accountant -14.1447 30.1848 -0.469 0.63937
## `._Administrative Assistant` -46.1863 26.1465 -1.766 0.07738
## `._Back end Developer` 22.8411 21.3997 1.067 0.28586
## `._Business Analyst` -9.8498 30.1780 -0.326 0.74414
## `._Business Development Manager` -5.8141 30.1921 -0.193 0.84730
## `._Business Intelligence Analyst` NA NA NA NA
## ._CEO 71.6678 30.2193 2.372 0.01775
## `._Chief Data Officer` NA NA NA NA
## `._Chief Technology Officer` 67.8729 30.2300 2.245 0.02480
## `._Content Marketing Manager` 13.8858 21.5519 0.644 0.51941
## ._Copywriter -18.0863 30.1851 -0.599 0.54908
## `._Creative Director` NA NA NA NA
## `._Customer Service Manager` -34.4399 30.2150 -1.140 0.25441
## `._Customer Service Rep` -18.1104 30.1789 -0.600 0.54847
## `._Customer Service Representative` -11.9158 23.4649 -0.508 0.61160
## `._Customer Success Manager` -18.7146 30.1782 -0.620 0.53519
## `._Customer Success Rep` -12.2550 30.1859 -0.406 0.68477
## `._Data Analyst` 51.7196 21.3804 2.419 0.01560
## `._Data Entry Clerk` -12.0280 30.1865 -0.398 0.69031
## `._Data Scientist` 54.6975 21.4075 2.555 0.01065
## `._Delivery Driver` -3.4385 23.5007 -0.146 0.88368
##
## (Intercept) .
## Age ***
## Years.of.Experience ***
## Gender_Male
## Gender_Other **
## `Education.Level_Bachelor's Degree` ***
## `Education.Level_High School` ***
## `Education.Level_Master's Degree`
## Education.Level_phD
## ._Accountant
## `._Administrative Assistant` .
## `._Back end Developer`
## `._Business Analyst`
## `._Business Development Manager`
## `._Business Intelligence Analyst`
## ._CEO *
## `._Chief Data Officer`
## `._Chief Technology Officer` *
## `._Content Marketing Manager`
## ._Copywriter
## `._Creative Director`
## `._Customer Service Manager`
## `._Customer Service Rep`
## `._Customer Service Representative`
## `._Customer Success Manager`
## `._Customer Success Rep`
## `._Data Analyst` *
## `._Data Entry Clerk`
## `._Data Scientist` *
## `._Delivery Driver`
## [ reached getOption("max.print") -- omitted 171 rows ]
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 21.34 on 5180 degrees of freedom
## Multiple R-squared: 0.8427, Adjusted R-squared: 0.8373
## F-statistic: 154.2 on 180 and 5180 DF, p-value: < 2.2e-16
El modelo con el totalidad de variables aumenta su \(R^2= 0.83\) lo que quiere decir que puede
explicar el 83% de variabilidad en los datos, con un error residual
estándar de \(\pm 21.340 USD\) y un
p-valué significativo y aunque los resultados mejoraron bastante
respecto al modelo básico inicial, existen muchas variables sin
significancia por lo que habría que aplicar
Feacture selection con el objetivo de continuar mejorando
los resultados de entrenamiento.
En la revisión de los residuos frente a las predicciones (gráficos primera fila) se observa un leve tendencia alta de residuos para predicciones altas, lo que podría ser un signo de no homocedasticidad.
La verificación Q-Q que compara los residuos contra la curva normal muestra algunos valores atípicos que pueden indicar que el modelo no cumple el supuesto de normalidad.
Dado que el p-value > 0.05 no se rechaza la hipótesis nula y por tanto no se sospecha de autocorrelacion en los residuos.
A continuación la evaluación de los 3 primeros modelos generados frente a los datos de test (Datos que son nuevos para cada modelo) a través de la métrica \(RMSE\) (Raíz del error cuadrático medio) bajo esta medición, el mejor modelo sera aquel que obtenga un valor menor.
Como se esperaba el mejor modelo hasta el momento es el que incluye la totalidad de variables del dataset, sin embargo aun es posible mejorarlo a través de diferentes técnicas que se abordaran mas adelante.
A continuación se muestra gráficamente el comportamiento de los residuos tanto en los datos de entrenamiento como de test, donde se observa de manera visual la ausencia de overfiting.
\[Residuo = Prediccion - valor\ real\]
Aplicar técnicas de feacture selection
regresion_step<- step(regresion2, direction = "both")
summary(regresion_step)
##
## Call:
## lm(formula = Salary ~ Age + Years.of.Experience + Gender_Other +
## `Education.Level_Bachelor's Degree` + `Education.Level_High School` +
## `Education.Level_Master's Degree` + `._Administrative Assistant` +
## `._Back end Developer` + ._CEO + `._Chief Technology Officer` +
## `._Content Marketing Manager` + `._Data Analyst` + `._Data Scientist` +
## `._Digital Marketing Manager` + `._Director of Data Science` +
## `._Director of Engineering` + `._Director of HR` + `._Director of Marketing` +
## `._Director of Operations` + `._Event Coordinator` + `._Financial Analyst` +
## `._Financial Manager` + `._Front end Developer` + `._Front End Developer` +
## `._Full Stack Engineer` + `._HR Generalist` + `._Human Resources Coordinator` +
## `._Human Resources Manager` + `._Junior Business Operations Analyst` +
## `._Junior HR Coordinator` + `._Junior HR Generalist` + `._Junior Sales Associate` +
## `._Junior Software Developer` + `._Junior Web Developer` +
## `._Marketing Coordinator` + `._Marketing Director` + `._Marketing Manager` +
## `._Operations Analyst` + `._Operations Director` + `._Operations Manager` +
## `._Product Manager` + `._Project Manager` + ._Recruiter +
## `._Research Director` + `._Research Scientist` + `._Sales Director` +
## `._Sales Manager` + `._Sales Representative` + `._Senior Business Analyst` +
## `._Senior Data Engineer` + `._Senior Data Scientist` + `._Senior Financial Analyst` +
## `._Senior Human Resources Manager` + `._Senior Operations Coordinator` +
## `._Senior Operations Manager` + `._Senior Product Manager` +
## `._Senior Product Marketing Manager` + `._Senior Project Engineer` +
## `._Senior Research Scientist` + `._Senior Software Engineer` +
## `._Social M` + `._Software Developer` + `._Software Engineer` +
## `._Software Engineer Manager` + `._Supply Chain Manager` +
## `._Training Specialist` + `._VP of Finance` + `._VP of Operations` +
## `._Marketing Analyst`, data = salario_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -121.634 -10.443 0.229 10.833 67.259
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 35.2031 3.9588 8.892 < 2e-16 ***
## Age 0.5666 0.1311 4.322 1.57e-05 ***
## Years.of.Experience 4.7208 0.1624 29.069 < 2e-16 ***
## Gender_Other -19.5919 6.3859 -3.068 0.002166 **
## `Education.Level_Bachelor's Degree` -8.3482 1.3651 -6.115 1.03e-09 ***
## `Education.Level_High School` -23.4084 2.0872 -11.215 < 2e-16 ***
## `Education.Level_Master's Degree` -2.0254 1.2064 -1.679 0.093226 .
## `._Administrative Assistant` -40.5899 15.0471 -2.698 0.007008 **
## `._Back end Developer` 28.6758 1.7777 16.131 < 2e-16 ***
## ._CEO 76.7952 21.3055 3.604 0.000316 ***
## `._Chief Technology Officer` 72.0345 21.3080 3.381 0.000728 ***
## `._Content Marketing Manager` 19.0896 3.0693 6.219 5.37e-10 ***
## `._Data Analyst` 57.6647 1.5580 37.013 < 2e-16 ***
## `._Data Scientist` 59.3916 1.7602 33.741 < 2e-16 ***
## `._Digital Marketing Manager` 12.9735 3.6059 3.598 0.000324 ***
## `._Director of Data Science` 64.2012 3.4753 18.474 < 2e-16 ***
## `._Director of Engineering` 27.6904 15.0829 1.836 0.066432 .
## `._Director of HR` 9.6277 3.1082 3.098 0.001962 **
## `._Director of Marketing` 28.0715 2.7883 10.068 < 2e-16 ***
## `._Director of Operations` 13.1678 7.2266 1.822 0.068493 .
## `._Event Coordinator` -34.5963 15.0442 -2.300 0.021507 *
## `._Financial Analyst` 18.8178 3.9942 4.711 2.52e-06 ***
## `._Financial Manager` 42.4974 2.2817 18.625 < 2e-16 ***
## `._Front end Developer` 20.3278 1.7807 11.416 < 2e-16 ***
## `._Front End Developer` 17.1156 4.4337 3.860 0.000115 ***
## `._Full Stack Engineer` 33.9610 1.6635 20.415 < 2e-16 ***
## `._HR Generalist` -30.0314 15.0484 -1.996 0.046023 *
## `._Human Resources Coordinator` -12.1916 3.4493 -3.535 0.000412 ***
## `._Human Resources Manager` 11.6680 2.4950 4.677 2.99e-06 ***
## `._Junior Business Operations Analyst` -32.6929 15.0450 -2.173 0.029824 *
## `._Junior HR Coordinator` -10.4731 4.5175 -2.318 0.020468 *
## `._Junior HR Generalist` -8.0695 3.4395 -2.346 0.019008 *
## `._Junior Sales Associate` -4.7373 2.4584 -1.927 0.054034 .
## `._Junior Software Developer` -13.6823 3.3396 -4.097 4.25e-05 ***
## `._Junior Web Developer` -6.2578 3.9136 -1.599 0.109886
## `._Marketing Coordinator` 6.8789 2.0642 3.332 0.000867 ***
## `._Marketing Director` 66.6454 3.3381 19.965 < 2e-16 ***
## `._Marketing Manager` 21.4854 1.8844 11.401 < 2e-16 ***
## `._Operations Analyst` -36.7679 21.2829 -1.728 0.084122 .
## `._Operations Director` 44.6510 21.2780 2.098 0.035912 *
## `._Operations Manager` 12.0150 2.4234 4.958 7.35e-07 ***
## `._Product Manager` 59.2059 1.6874 35.087 < 2e-16 ***
## `._Project Manager` 32.4272 5.3966 6.009 1.99e-09 ***
## ._Recruiter -30.3107 15.0469 -2.014 0.044016 *
## `._Research Director` 55.4858 3.2609 17.015 < 2e-16 ***
## `._Research Scientist` 53.8307 3.2956 16.334 < 2e-16 ***
## `._Sales Director` 35.5998 3.0723 11.587 < 2e-16 ***
## `._Sales Manager` 19.4362 3.4257 5.674 1.47e-08 ***
## `._Sales Representative` -7.5277 4.0387 -1.864 0.062391 .
## `._Senior Business Analyst` 13.1626 8.7259 1.508 0.131498
## `._Senior Data Engineer` 19.0503 10.7262 1.776 0.075783 .
## `._Senior Data Scientist` 43.3499 3.2779 13.225 < 2e-16 ***
## `._Senior Financial Analyst` 13.7981 8.0856 1.706 0.087975 .
## `._Senior Human Resources Manager` 7.5519 3.6858 2.049 0.040520 *
## `._Senior Operations Coordinator` 15.4078 10.6592 1.445 0.148377
## `._Senior Operations Manager` 18.5397 10.6577 1.740 0.081994 .
## `._Senior Product Manager` 27.9589 10.6655 2.621 0.008781 **
## `._Senior Product Marketing Manager` 19.2679 3.2154 5.992 2.21e-09 ***
## `._Senior Project Engineer` 42.8145 1.8150 23.589 < 2e-16 ***
## `._Senior Research Scientist` 26.1817 3.8152 6.863 7.54e-12 ***
## `._Senior Software Engineer` 31.9757 1.9152 16.696 < 2e-16 ***
## `._Social M` 35.5269 21.2822 1.669 0.095111 .
## `._Software Developer` 7.2779 2.3610 3.083 0.002063 **
## `._Software Engineer` 48.6148 1.3985 34.761 < 2e-16 ***
## `._Software Engineer Manager` 37.2419 1.8081 20.597 < 2e-16 ***
## `._Supply Chain Manager` -31.1932 21.2756 -1.466 0.142668
## `._Training Specialist` -40.6021 21.2583 -1.910 0.056194 .
## `._VP of Finance` 50.4968 21.2791 2.373 0.017676 *
## `._VP of Operations` 40.4968 21.2791 1.903 0.057078 .
## `._Marketing Analyst` 5.6197 2.3208 2.421 0.015492 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 21.23 on 5291 degrees of freedom
## Multiple R-squared: 0.841, Adjusted R-squared: 0.8389
## F-statistic: 405.5 on 69 and 5291 DF, p-value: < 2.2e-16
Se ejecuta un modelo stepwise, que aunque tiene resultados muy similares al modelo con el dataset completo, se gana en parsimonia (Mismos resultados con muchas menor variables requeridas.)
En la revisión de los supuestos de normalidad, se observan algunos atipicos con gran influencia lo que podria estar afectando los resultados del modelo.
El siguiente algoritmo a experimentar es una SVM para regresión, y
para este se realiza un ajuste adicional sobre los datos y es comenzar a
tratar la variable education level como un factor
ordenado.
set.seed(42)
salario_f<- salario
names(salario_f)<- c("Age", "Gender", "Education.Level", ".", "Years.of.Experience", "Salary")
salario_f$Education.Level <- ordered(salario_f$Education.Level, levels= c("Other", "High School", "Bachelor's Degree",
"Master's Degree", "phD"),
labels= c(0, 1, 2, 3, 4))
salario_f<- dummy_cols(salario_f, select_columns = c("Gender", "."), remove_first_dummy = TRUE)
salario_f<- salario_f[,c(-2, -3, -4)]
sample<- sample.int(nrow(salario_f), floor(.8*nrow(salario_f)))
salario_train <- salario_f[sample,]
salario_test<- salario_f[-sample,]
salario_train$Salary<- sapply(salario_train$Salary, FUN = function(x){x/1000})
salario_test$Salary<- sapply(salario_test$Salary, FUN = function(x){x/1000})
regression_svr = svm(formula = Salary ~ .,
data = salario_train,
type = "eps-regression",
kernel = "poly")
pred3<-predict(regression_svr, salario_test)
RMSE3<-sqrt(mean((pred3 - salario_test$Salary)^2))
Se ejecuta un modelo de vectores de maquina de soporte con un kernel
polinomico sin ajustes de hiperparametros y se obtiene
inicialmente un resultado un poco peor al mejor conseguido a través de
la regresión lineal.
La revisión de los residuos entre los conjuntos de datos no indican
algún tipo de overfiting sin embargo se observa una gran
dispersión entre las predicciones y los valores reales.
Como segunda instancia se busca ajustar los hiperparametros de regularización a través de la validación cruzada, donde en el gráfico a continuación se pueden observar los mejores resultados identificando el punto mas caliente.
Identificar el valor exacto en el grafico no es tan sencillo, asi que se muestran a continuacion y seran los valores con los que se ejecute un nuevo modelo de regresion - SVR.
Mejor epsilon: 5.6 Mejor costo: 3.2768^{4}
regression_svr = svm(formula = Salary ~ .,
data = salario_train,
type = "eps-regression", epsilon = 5.6, cost = 32768)
pred4<-predict(regression_svr, salario_test)
RMSE4<-sqrt(mean((pred4 - salario_test$Salary)^2))
Aunque la maquina de vectores de soporte dio unos buenos resultados,
vamos a experimentar con un par de modelos adicionales, buscando mejorar
un poco mas los resultados.
En primera instancia se utilizan los arboles de decisión, según se muestra a continuación:
regresion_ad<- rpart(formula= salario_train$Salary ~ ., data= salario_train)
rpart.plot(regresion_ad)
Parecen primar la variable de experiencia y algunos puestos en los
cortes realizados por el árbol para clasificar el salario, y aunque su
corte es discreto, veamos como se comporta el error medio de
prediccion:
Resulta en un error bastante alto, quizá no se logra capturar de manera correcta la variabilidad de los datos, pero y si en vez de 1 solo árbol, tal vez unimos 150?
regresion_rf<- randomForest(x= salario_train[,-3], y = salario_train$Salary, ntree= 150,
keep.forest= TRUE, importance= TRUE)
##
## Call:
## randomForest(x = salario_train[, -3], y = salario_train$Salary, ntree = 150, importance = TRUE, keep.forest = TRUE)
## Type of random forest: regression
## Number of trees: 150
## No. of variables tried at each split: 65
##
## Mean of squared residuals: 111.2418
## % Var explained: 96.02
Se ejecuta un modelo de Random Forest de 150 arboles aleatorios, que consiguen explicar el 96% de variabilidad en los datos, veamos su comportamiento de prediccion en los datos de test:
Hemos conseguido el mejor resultado hasta ahora logrando disminuir cerca de 2mil USD de error promedio en la predicción respecto a lo conseguido con el modelo de SVM.
Observando la importancia de las mejores 30 variables, vemos como la edad y los años de experiencia son aquellas que contribuyen en promedio a la mejora de RMSE en la predicción en cada uno de los arboles aleatorios.
Durante el análisis descriptivo se presumía que el nivel educativo tendrá relevancia en la predicción de salarios, sin embargo vemos como resultan ser mas importantes otras variables. (por lo menos para este modelo.)
| Modelo | RMSE |
|---|---|
| Regresión lineal de 2 variables | 30.5 |
| Regresión linea 2 var. relacionadas | 27.59 |
| Regresión lineal dataset total | 21.42 |
| SVM | 23.46 |
| SVM sintonizado | 11.31 |
| Árbol de desicion | 22.84 |
| Random forest | 9.65 |
Veamos el comportamiento de predicción sobre cada uno de los salarios reales de test (registros únicos, para evitar problemas en la visualización)
Pues bien, vemos como la predicción se acerca bastante a los salarios reales, podríamos intentar mejorar mas los resultados reales a través de la sintonizador de hiperparametros con validación cruzada, sin embargo esto se deja a gusto de los lectores que deseen experimentar mas.
En cuanto a técnicas y modelos de machine learning el ejercicio finaliza acá, sin embargo, no se descarta en el futuro aplicar redes neuronales y deep learning para ver sus resultados hacia este problema.
Muchas gracias.