Introducción

Descripción de datos: Problema

El dataset contiene 14,838 registros de salarios en la industria de Data Science, recolectados durante diferentes años y con diversas características asociadas a cada registro. Las variables en el dataset son:

  • work_year: Año en que se registra el salario.
  • experience_level: Nivel de experiencia del empleado (Junior, Mid-level, Senior).
  • employment_type: Tipo de contrato (Tiempo completo, Contrato).
  • job_title: Título del trabajo (Data Scientist, BI Data Analyst, ML Engineer).
  • salary: Salario reportado en la moneda local.
  • salary_currency: Moneda en la que se reporta el salario.
  • salary_in_usd: Salario convertido a dólares estadounidenses.
  • employee_residence: País de residencia del empleado.
  • remote_ratio: Porcentaje de trabajo remoto.
  • company_location: Ubicación de la compañía.
  • company_size: Tamaño de la empresa (Pequeña, Mediana, Grande).
El objetivo de este análisis es entender las tendencias salariales en el área de Data Science considerando diversas variables, como el nivel de experiencia, el tipo de empleo, el país de residencia y el tamaño de la empresa.

Metodología

Población

cienciadatos

La población del dataset de salarios de Data Science presenta las siguientes características:

Variables Numéricas

  • work_year: Los datos se extienden principalmente hasta el año 2024, con un promedio en 2023.

  • salary: Los salarios varían ampliamente, desde 14,000 hasta 30,400,000 (sin especificar la moneda en esta columna).

  • salary_in_usd: Convertidos a dólares, los salarios oscilan entre 15,000 y 800,000 USD, con una media de aproximadamente 149,875 USD.

  • remote_ratio: La proporción de trabajo remoto va de 0% (sin trabajo remoto) a 100% (trabajo completamente remoto), con una media de 32.76%.

Variables Categóricas

  • experience_level: Incluye 4 niveles (por ejemplo, Senior, Mid), siendo el más frecuente el nivel Senior (SE), con 9,696 registros.

  • employment_type: Predomina el tipo de empleo a tiempo completo (FT), que representa casi toda la población (14,772 registros).

  • job_title: Existen 153 títulos de puestos, siendo “Data Engineer” el más común (3,162 registros).

  • salary_currency: Se registran 23 monedas, aunque la mayoría de los salarios están en USD (13,682 registros).

  • employee_residence y company_location: La mayoría de los empleados residen en EE. UU. (12,926 registros), y las empresas también se localizan principalmente en EE. UU. (12,975 registros).

  • company_size: Las empresas de tamaño mediano son las más frecuentes (13,674 registros), con otras de tamaño pequeño y grande.

Estos datos reflejan un conjunto variado en términos de títulos de puestos y ubicación, con un énfasis en el mercado de EE. UU

set.seed(975)
DB <- read_csv("DataScience_salaries_2024.csv", show_col_types = FALSE)
DB=as.data.frame(unclass(DB), stringsAsFactors = TRUE)
str(DB)
## 'data.frame':    14838 obs. of  11 variables:
##  $ work_year         : num  2021 2021 2020 2021 2022 ...
##  $ experience_level  : Factor w/ 4 levels "EN","EX","MI",..: 3 3 3 3 4 3 4 1 2 1 ...
##  $ employment_type   : Factor w/ 4 levels "CT","FL","FT",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ job_title         : Factor w/ 153 levels "Admin & Data Analyst",..: 90 22 90 131 114 131 87 90 109 145 ...
##  $ salary            : num  30400000 11000000 11000000 8500000 7500000 7000000 7000000 6600000 6000000 5500000 ...
##  $ salary_currency   : Factor w/ 23 levels "AUD","BRL","CAD",..: 5 10 10 13 12 13 12 10 12 13 ...
##  $ salary_in_usd     : num  40038 36259 35735 77364 95386 ...
##  $ employee_residence: Factor w/ 88 levels "AD","AE","AM",..: 16 39 39 48 43 48 43 39 43 48 ...
##  $ remote_ratio      : num  100 50 50 50 50 50 50 100 50 50 ...
##  $ company_location  : Factor w/ 77 levels "AD","AE","AM",..: 15 75 35 43 39 43 39 35 39 43 ...
##  $ company_size      : Factor w/ 3 levels "L","M","S": 1 1 1 3 1 3 1 2 1 1 ...
sprintf("El número de filas para la base de datos es: %d", nrow(DB))
## [1] "El número de filas para la base de datos es: 14838"
# Calcular el total de cada nivel en el dataset completo
experience_counts <- table(DB$experience_level) 
experience_counts
## 
##   EN   EX   MI   SE 
## 1148  441 3553 9696
# Gráfico de caja para visualizar la distribución de os
boxplot(salary_in_usd ~ company_size, data = DB, 
        main = "Sueldos en empresas de Tecnologia asociados \n al tamaño de la empresa",
        xlab = "Tamaño de la compañia", 
        ylab = "Sueldo Anual en dolares", 
        col = c("lightblue", "lightgreen", "lightpink"))

Del gráfico anterior podemos decir:

  • Las empresas medianas (M) muestran la mayor dispersión salarial, con varios valores atípicos hacia arriba, lo que sugiere que algunas posiciones específicas o roles especializados reciben compensaciones significativamente más altas que la media.
  • Las empresas pequeñas (S) tienden a ofrecer salarios más bajos y con menor variabilidad, con una mediana inferior a las empresas grandes (L) y medianas (M).

# Gráfico de caja para visualizar la distribución de os
boxplot(salary_in_usd ~ experience_level, data = DB, 
        main = "Sueldos en empresas de Tecnología asociados al tipo de senority",
        xlab = "Senority de los empleados", 
        ylab = "Sueldo Anual en dolares", 
        col = c("lightblue", "lightgreen", "lightpink", "lightyellow"))

Del gráfico anterior podemos decir:

  • Los empleados con nivel Expert (EX) muestran la mediana salarial más alta, incluso por encima de los Senior (SE), lo que sugiere que la experiencia especializada tiende a ser más valorada.
  • El nivel Entry (EN) muestra la menor dispersión salarial y la mediana más baja, pero interesantemente tiene algunos valores atípicos muy altos, sugiriendo que incluso los empleados junior pueden acceder a salarios elevados en casos excepcionales.

# Crear la gráfica de violín
ggplot(DB, aes(x = company_size, y = salary_in_usd, fill = company_size)) +
  geom_violin(trim = TRUE) +  # trim controla si se recortan los extremos
  geom_boxplot(width = 0.1, alpha = 0.5) + # Opcional: añade un boxplot dentro
  theme_minimal() +
  labs(
    title = "Gráfica de violín - Para sueldos en TI con respecto al tamaño de la empresa",
    x = "Tamaño de la compañia",
    y = "Sueldos en TI"
  ) +
  scale_fill_brewer(palette = "Pastel1") 

Del gráfico anterior se puede añadir que:

  • Las empresas medianas (M) muestran una distribución bimodal (forma de dos bulbos), lo que sugiere dos grupos salariales distintos dentro de estas empresas, posiblemente reflejando una clara diferenciación entre roles junior y senior.
  • Las empresas pequeñas (S) presentan una distribución más concentrada en los salarios bajos (forma de pera invertida), con menos casos de salarios altos, mientras que las grandes (L) muestran una distribución más uniforme a lo largo del rango salarial.

# Crear la gráfica de violín
ggplot(DB, aes(x = experience_level, y = salary_in_usd, fill = experience_level)) +
  geom_violin(trim = TRUE) +  # trim controla si se recortan los extremos
  geom_boxplot(width = 0.1, alpha = 0.5) + # Opcional: añade un boxplot dentro
  theme_minimal() +
  labs(
    title = "Gráfica de violín - Para sueldos en TI con respecto \n al tamaño de la empresa",
    x = "Experiencia (senority) de los Empleados",
    y = "Sueldos en TI"
  ) +
  scale_fill_brewer(palette = "Pastel1") 

Del gráfico anterior se puede añadir que:

  • Los empleados Expert (EX) muestran la distribución más ancha en los salarios medios-altos, lo que indica una mayor variabilidad en sus compensaciones, además de tener la mediana más alta de todos los niveles.
  • El nivel Entry (EN) muestra una distribución fuertemente sesgada hacia salarios bajos (forma de gota), pero mantiene algunos valores atípicos muy altos, sugiriendo que existen oportunidades excepcionales incluso para los menos experimentados.

Tipo de muestreo: Muestreo aleatorio estratificado

Muestra 1

Este dataset contiene información sobre salarios de profesionales en ciencia de datos. Algunas de las variables clave que podrían servir para estratificar la muestra son:

  • experience_level: Nivel de experiencia del empleado (e.g., Junior, Mid, Senior, Experto).

  • employment_type: Tipo de empleo (e.g., tiempo completo, contrato, freelance).

  • job_title: Título del puesto (e.g., Data Scientist, ML Engineer).

  • company_size: Tamaño de la empresa (e.g., pequeña, mediana, grande).

  • remote_ratio: Nivel de trabajo remoto (0%, 50%, 100%).

Para una estratificación idónea, se selecciona la variable experience_level. Que esta categorizada en cuatro niveles.

# Definir los parámetros
N <- 14838       # Tamaño de la población
Z <- 1.96        # Valor Z para un 95% de nivel de confianza
p <- 0.5         # Proporción estimada
E <- 0.05        # Margen de error

# Calcular el tamaño de muestra
n <- (N * Z^2 * p * (1 - p)) / ((N - 1) * E^2 + Z^2 * p * (1 - p))
n <- ceiling(n)  # Redondear al siguiente número entero

# Mostrar el tamaño de muestra
sprintf("La muestra significativa de la población es: %d", n)
## [1] "La muestra significativa de la población es: 375"
# Se saca el tamaño representativo de la muestra del estrato
# n_h = (N_h/N)*n
N = 14838
N_h.EN=nrow(subset(DB, experience_level == "EN"))
n_h.EN= (N_h.EN/N)*n
sprintf("El tamaño de la muestra para el primer estrato es: %s", round(n_h.EN,0))
## [1] "El tamaño de la muestra para el primer estrato es: 29"
N_h.EX=nrow(subset(DB, experience_level == "EX"))
n_h.EX= (N_h.EX/N)*n
sprintf("El tamaño de la muestra para el segundo estrato es: %s", round(n_h.EX,0))
## [1] "El tamaño de la muestra para el segundo estrato es: 11"
N_h.MI=nrow(subset(DB, experience_level == "MI"))
n_h.MI= (N_h.MI/N)*n
sprintf("El tamaño de la muestra para el tercer estrato es: %s", round(n_h.MI,0))
## [1] "El tamaño de la muestra para el tercer estrato es: 90"
N_h.SE=nrow(subset(DB, experience_level == "SE"))
n_h.SE= (N_h.SE/N)*n
sprintf("El tamaño de la muestra para el cuarto estrato es: %s", round(n_h.SE,0))
## [1] "El tamaño de la muestra para el cuarto estrato es: 245"
# Se saca la muestra aleatoria de cada estrato, con el tamaño especificado para cada estrato
# Definir el tamaño de la muestra redondeado para el nivel de experiencia "EN"
tamañomuestra.EN <- round(n_h.EN, 0)
# Filtrar el dataset para el nivel de experiencia "EN" y tomar una muestra aleatoria sin reemplazo
muestra.EN <- DB %>%
  filter(experience_level == "EN") %>%
  sample_n(size = tamañomuestra.EN, replace = FALSE)
# Mostrar la muestra seleccionada
sprintf("El número de filas para la muestra del primer estrato es: %d", nrow(muestra.EN))
## [1] "El número de filas para la muestra del primer estrato es: 29"
tamañomuestra.EX <- round(n_h.EX, 0)
muestra.EX <- DB %>%
  filter(experience_level == "EX") %>%
  sample_n(size = tamañomuestra.EX, replace = FALSE)
sprintf("El número de filas para la muestra del segundo estrato es: %d", nrow(muestra.EX))
## [1] "El número de filas para la muestra del segundo estrato es: 11"
tamañomuestra.MI <- round(n_h.MI, 0)
muestra.MI <- DB %>%
  filter(experience_level == "MI") %>%
  sample_n(size = tamañomuestra.MI, replace = FALSE)
sprintf("El número de filas para la muestra del tercer estrato es: %d", nrow(muestra.MI))
## [1] "El número de filas para la muestra del tercer estrato es: 90"
tamañomuestra.SE <- round(n_h.SE, 0)
muestra.SE <- DB %>%
  filter(experience_level == "SE") %>%
  sample_n(size = tamañomuestra.SE, replace = FALSE)
sprintf("El número de filas para la muestra del cuarto estrato es: %d", nrow(muestra.SE))
## [1] "El número de filas para la muestra del cuarto estrato es: 245"
# Unión de las muestras para el totala de la muestra estratificada
muestra.estratificada = rbind(muestra.EN, muestra.EX, muestra.MI, muestra.SE)
sprintf("El número de filas para la muestra estratificada es: %d", nrow(muestra.estratificada))
## [1] "El número de filas para la muestra estratificada es: 375"

Muestra 2

# Se saca el tamaño representativo de la muestra del estrato
# n_h = (N_h/N)*n
n2 = 1000
N2 = 14838
N_h.EN2=nrow(subset(DB, experience_level == "EN"))
n_h.EN2= (N_h.EN2/N2)*n2
sprintf("El tamaño de la muestra 2 para el primer estrato es: %s", round(n_h.EN2,0))
## [1] "El tamaño de la muestra 2 para el primer estrato es: 77"
N_h.EX2=nrow(subset(DB, experience_level == "EX"))
n_h.EX2= (N_h.EX2/N2)*n2
sprintf("El tamaño de la muestra 2 para el segundo estrato es: %s", round(n_h.EX2,0))
## [1] "El tamaño de la muestra 2 para el segundo estrato es: 30"
N_h.MI2=nrow(subset(DB, experience_level == "MI"))
n_h.MI2= (N_h.MI2/N2)*n2
sprintf("El tamaño de la muestra 2 para el tercer estrato es: %s", round(n_h.MI2,0))
## [1] "El tamaño de la muestra 2 para el tercer estrato es: 239"
N_h.SE2=nrow(subset(DB, experience_level == "SE"))
n_h.SE2= (N_h.SE2/N2)*n2
sprintf("El tamaño de la muestra 2 para el cuarto estrato es: %s", round(n_h.SE2,0))
## [1] "El tamaño de la muestra 2 para el cuarto estrato es: 653"
# Se saca la muestra aleatoria de cada estrato, con el tamaño especificado para cada estrato
# Definir el tamaño de la muestra redondeado para el nivel de experiencia "EN"
tamañomuestra.EN2 <- round(n_h.EN2, 0)
# Filtrar el dataset para el nivel de experiencia "EN" y tomar una muestra aleatoria sin reemplazo
muestra.EN2 <- DB %>%
  filter(experience_level == "EN") %>%
  sample_n(size = tamañomuestra.EN2, replace = FALSE)
# Mostrar la muestra seleccionada
sprintf("El número de filas para la muestra 2 del primer estrato es: %d", nrow(muestra.EN2))
## [1] "El número de filas para la muestra 2 del primer estrato es: 77"
tamañomuestra.EX2 <- round(n_h.EX2, 0)
muestra.EX2 <- DB %>%
  filter(experience_level == "EX") %>%
  sample_n(size = tamañomuestra.EX2, replace = FALSE)
sprintf("El número de filas para la muestra 2 del segundo estrato es: %d", nrow(muestra.EX2))
## [1] "El número de filas para la muestra 2 del segundo estrato es: 30"
tamañomuestra.MI2 <- round(n_h.MI2, 0)
muestra.MI2 <- DB %>%
  filter(experience_level == "MI") %>%
  sample_n(size = tamañomuestra.MI2, replace = FALSE)
sprintf("El número de filas para la muestra del tercer estrato es: %d", nrow(muestra.MI2))
## [1] "El número de filas para la muestra del tercer estrato es: 239"
tamañomuestra.SE2 <- round(n_h.SE2, 0)
muestra.SE2 <- DB %>%
  filter(experience_level == "SE") %>%
  sample_n(size = tamañomuestra.SE2, replace = FALSE)
sprintf("El número de filas para la muestra del cuarto estrato es: %d", nrow(muestra.SE2))
## [1] "El número de filas para la muestra del cuarto estrato es: 653"
# Unión de las muestras para el total de la muestra estratificada
muestra.estratificada2 = rbind(muestra.EN2, muestra.EX2, muestra.MI2, muestra.SE2)
sprintf("El número de filas para la muestra estratificada es: %d", nrow(muestra.estratificada2))
## [1] "El número de filas para la muestra estratificada es: 999"
# Densidad de la muestra 2 del salario en dolares normalizado
muestra.estratificada2$salary_log <- log(muestra.estratificada2$salary_in_usd)

Estimadores

Estimador puntual

# Densidad del salario en dolares de la población
options(scipen=10)
plot(density(DB$salary_in_usd, na.rm = TRUE),
     main = "Densidad de Salarios Poblacional",
     xlab = "Salario",
     ylab = "Densidad",
     col = "blue",
     lwd = 2)

# Media poblacional
salario_promedio <- mean(DB$salary_in_usd)
sprintf("El salario promedio de la muestra problacional es: %s", round(salario_promedio,2))
## [1] "El salario promedio de la muestra problacional es: 149874.72"
# Densidad de salario en dolares de la población normalizado
options(scipen=10)
DB$salary_log <- log(DB$salary_in_usd)

plot(density(DB$salary_log, na.rm = TRUE),
     main = "Densidad de Salarios Normalizada",
     xlab = "Salario",
     ylab = "Densidad",
     col = "blue",
     lwd = 2)

# Densidad de la muestra 1
options(scipen=10)
plot(density(muestra.estratificada$salary_in_usd, na.rm = TRUE),
     main = "Densidad de la muestra 1 estratificada de salarios",
     xlab = "Salario",
     ylab = "Densidad",
     col = "green",
     lwd = 2)

Comprobación de sesgo muestra 1

# Media muestral de la muestra 1
salario_estratificado_promedio <- mean(muestra.estratificada$salary_in_usd)
sprintf("El salario estratificado promedio de la muestra 1 es: %s", round(salario_estratificado_promedio,2))
## [1] "El salario estratificado promedio de la muestra 1 es: 149400.89"
# Densidad de la muestra 1 del salario en dolares normalizado
options(scipen=10)
muestra.estratificada$salary_log <- log(muestra.estratificada$salary_in_usd)

plot(density(muestra.estratificada$salary_log, na.rm = TRUE),
     main = "Densidad de la muestra 1 estratificada de Salarios Normalizada",
     xlab = "Salario",
     ylab = "Densidad",
     col = "green",
     lwd = 2)

Comprobación de sesgo muestra 2

# Media muestral de la muestra 2
salario_estratificado_promedio2 <- mean(muestra.estratificada2$salary_in_usd)
sprintf("El salario estratificado promedio de la muestra 2 es: %s", round(salario_estratificado_promedio2,2))
## [1] "El salario estratificado promedio de la muestra 2 es: 147656.52"
# Densidad de la muestra 2 del salario en dolares normalizado
options(scipen=10)
muestra.estratificada2$salary_log <- log(muestra.estratificada2$salary_in_usd)

plot(density(muestra.estratificada2$salary_log, na.rm = TRUE),
     main = "Densidad de la muestra 2 estratificada de Salarios Normalizada",
     xlab = "Salario",
     ylab = "Densidad",
     col = "green",
     lwd = 2)

# Densidad de salarios poblacionales - muestrales(muestra 1 y muestra 2)
plot(density(DB$salary_log, na.rm = TRUE),
     main = "Densidad de Salarios",
     xlab = "Salario",
     ylab = "Densidad",
     col = "blue",
     lwd = 2)

# Primera muestra
lines(density(muestra.estratificada$salary_log, na.rm = TRUE), col = "red", lwd = 2)

# Segunda muestra
lines(density(muestra.estratificada2$salary_log, na.rm = TRUE), col = "green", lwd = 2)

legend("topright", 
       legend = c("Salario Poblacional", "Salario Muestral 1", "Salario Muestral 2"),
       col = c("blue", "red", "green"),
       lwd = 2)

# Comprobación del estimador
salario_estratificado_promedio_estimador_muestra1 <- salario_promedio - salario_estratificado_promedio
sprintf("El salario estratificado promedio de la muestra 1 con respecto al salario promedio poblacional es: %s", round(salario_estratificado_promedio_estimador_muestra1,2))
## [1] "El salario estratificado promedio de la muestra 1 con respecto al salario promedio poblacional es: 473.83"
salario_estratificado_promedio_estimador_muestra2 <- salario_promedio - salario_estratificado_promedio2
sprintf("El salario estratificado promedio de la muestra 2 con respecto al salario promedio poblacional es: %s", round(salario_estratificado_promedio_estimador_muestra2,2))
## [1] "El salario estratificado promedio de la muestra 2 con respecto al salario promedio poblacional es: 2218.19"
Conclusión

Con estos valores, podemos concluir que existe un sesgo en la muestra, ya que los salarios estratificados promedio de las muestras difieren del salario promedio poblacional. Por lo tanto, se ha aplicado un estimador de intervalos de confianza para corregir este sesgo y obtener una estimación más precisa de la media poblacional. En particular, el salario estratificado promedio de la muestra 1 es 473.83 unidades por debajo del promedio poblacional, mientras que en la muestra 2 es 2218.19 unidades por encima.

Intervalos de confianza

Se decide un nivel de confianza del 95% para los siguientes cálculos:

Intervalos de confianza para la media de las muestras

# Cálculo de la media y la desviación estándar de la muestra 1
media_muestral <- mean(muestra.estratificada$salary_log)
desviacion_muestral <- sd(muestra.estratificada$salary_log)
n <- length(muestra.estratificada$salary_log) #Tamaño muestral de la muestra 1
# Cálculo de la media y la desviación estándar de la muestra 2
media_muestral2 <- mean(muestra.estratificada2$salary_log)
desviacion_muestral2 <- sd(muestra.estratificada2$salary_log)
n2 <- length(muestra.estratificada2$salary_log) #Tamaño muestral de la muestra 2

# Nivel de confianza para las muestras es el mismo
nivel_confianza <- 0.95
alpha <- 1 - nivel_confianza

# Valor crítico para un intervalo del 95% (distribución t de Student) de ambas muestras
t_critico <- qt(1 - alpha/2, df = n - 1)

# Error estándar de la muestra 1
error_estandar <- desviacion_muestral / sqrt(n)
# Error estándar de la muestra 2
error_estandar2 <- desviacion_muestral2 / sqrt(n2)

# Intervalo de confianza de la muestra 1
limite_inferior <- media_muestral - t_critico * error_estandar
limite_superior <- media_muestral + t_critico * error_estandar
# Intervalo de confianza de la muestra 2
limite_inferior2 <- media_muestral2 - t_critico * error_estandar2
limite_superior2 <- media_muestral2 + t_critico * error_estandar2

cat("Intervalo de confianza del", nivel_confianza * 100, "% para la media de la muestra 1 es: [", limite_inferior, ",", limite_superior, "]\n")
## Intervalo de confianza del 95 % para la media de la muestra 1 es: [ 11.77368 , 11.86542 ]
cat("Intervalo de confianza del", nivel_confianza * 100,  "% para la media de la muestra 2 es: [", limite_inferior2, ",", limite_superior2, "]\n")
## Intervalo de confianza del 95 % para la media de la muestra 2 es: [ 11.76654 , 11.8268 ]
Conclusión

Los intervalos de confianza muestran que ambas muestras ofrecen una estimación precisa y confiable de la media poblacional. El solapamiento y la similitud en los rangos de los intervalos indican que las diferencias observadas entre las muestras no son significativas, y las estimaciones son estables y consistentes. Esto sugiere que cualquiera de las muestras podría utilizarse para inferir correctamente la tendencia central de la población. Además, la estrechez de los intervalos refuerza la calidad y precisión de las estimaciones.

Intervalo de confianza para la proporción de las muestras

# Proporción de la muestra 1 y la muestra 2
p <- 0.5  #Proporción (50%)

# Valor critico de la muestra 1 y de la muestra 2 es el mismo ya que aplicamos el mismo nivel de confianza
valor_critico <- qnorm((1 + nivel_confianza) / 2)

# Error estándar de la proporción en la muestra 1
error_estandar_proporcion <- sqrt((p * (1 - p)) / n)
# Error estándar de la proporción en la muestra 2
error_estandar_proporcion2 <- sqrt((p * (1 - p)) / n2)

# Intervalo de confianza de la muestra 1
limite_inferior <- p - valor_critico * error_estandar_proporcion
limite_superior <- p + valor_critico * error_estandar_proporcion
# Intervalo de confianza de la muestra 2
limite_inferior2 <- p - valor_critico * error_estandar_proporcion2
limite_superior2 <- p + valor_critico * error_estandar_proporcion2

cat("Intervalo de confianza del", nivel_confianza * 100, "% para la proporción de la muestra 1 es: [", limite_inferior, ",", limite_superior, "]\n")
## Intervalo de confianza del 95 % para la proporción de la muestra 1 es: [ 0.4493939 , 0.5506061 ]
cat("Intervalo de confianza del", nivel_confianza * 100,  "% para la proporción de la muestra 2 es: [", limite_inferior2, ",", limite_superior2, "]\n")
## Intervalo de confianza del 95 % para la proporción de la muestra 2 es: [ 0.4689947 , 0.5310053 ]
Conclusión

Se observa que ambos intervalos de confianza se superponen, lo que indica que no hay una diferencia estadísticamente significativa en las proporciones estimadas para las dos muestras. Esto sugiere que las proporciones en ambas muestras podrían ser similares dentro del rango de error aceptado. Ambas muestras parecen tener proporciones similares en términos de la característica evaluada, ya que sus intervalos de confianza se solapan. Para hacer afirmaciones más definitivas sobre diferencias, se podría necesitar una muestra más grande o un análisis más específico con pruebas de hipótesis.

Intervalo de confianza para la diferencia de medias de las muestras

# Error estándar de la diferencia de medias
error_estandar_diferencia <- sqrt((desviacion_muestral^2 / n) + (desviacion_muestral2^2 / n2))

# Valor crítico de la distribución t
valor_critico_diferencia <- qt((1 + nivel_confianza) / 2, df = n + n2 - 2)

# Diferencia de medias
medias_diferencia <- n - n2

# Intervalo de confianza para la diferencia de medias
limite_inferior_diferencia <- medias_diferencia - valor_critico * error_estandar_diferencia
limite_superior_diferencia <- medias_diferencia + valor_critico * error_estandar_diferencia

cat("Intervalo de confianza del", nivel_confianza * 100,  "% la diferencia de medias es: [", limite_inferior_diferencia, ",", limite_superior_diferencia, "]\n")
## Intervalo de confianza del 95 % la diferencia de medias es: [ -624.0547 , -623.9453 ]
Conclusión

La diferencia de medias negativa indica que, en promedio, los valores observados en la muestra 1 son más bajos que en la muestra 2 en aproximadamente 624 unidades. Existe una diferencia significativa en las medias entre las dos muestras. La muestra 1 tiene valores más bajos que la muestra 2, y esta diferencia es estadísticamente significativa, ya que el intervalo de confianza negativo confirma que la diferencia observada no es un resultado de la variabilidad aleatoria.

Testeando el intervalo de confianza

Se desea hallar la proporción de empleados que tienen un entry level de la población a partir de la muestra, para ello se va a establecer un intervalo de confianza del 95% y luego comparar la realidad con respecto a la población.

N = 14838
N_h.EN=nrow(subset(DB, experience_level == "EN"))
proporcion_poblacional.EN = N_h.EN/N
print(sprintf("El %s %s de la población son trabajadores que tienen un entry level",round(proporcion_poblacional.EN*100,2),"%"))
## [1] "El 7.74 % de la población son trabajadores que tienen un entry level"
tamaño_muestral = as.numeric(nrow(muestra.estratificada))
n_h.EN = nrow(subset(muestra.estratificada, experience_level == "EN")) 
proporcional_muestral.EN = as.numeric(n_h.EN/tamaño_muestral)

valor_critico <- 1.96 #intervalo de confianza del 95%
error_estandar.proporcional = sqrt((proporcional_muestral.EN * (1 - proporcional_muestral.EN)) / tamaño_muestral)

# Intervalo de confianza de la muestra 1
limite_inferior <- proporcional_muestral.EN - valor_critico * error_estandar.proporcional
limite_superior <- proporcional_muestral.EN + valor_critico * error_estandar.proporcional

cat("Con una confianza del 95% podemos inferir que la proporción poblacional de los empleados que se encuentran en un entry level a partir de los datos de la población se encuentra entre un: [", round(limite_inferior*100,2), "%,", round(limite_superior*100,2), "%]\n")
## Con una confianza del 95% podemos inferir que la proporción poblacional de los empleados que se encuentran en un entry level a partir de los datos de la población se encuentra entre un: [ 5.03 %, 10.44 %]
cat("Al compararlo con el valor de la población vemos que el intervalo de confianza es cierto dado a que la proporcion poblacional es de un 7%, ahora revisemos si con un 99% de confianza el intervalo se cierra un poco más")
## Al compararlo con el valor de la población vemos que el intervalo de confianza es cierto dado a que la proporcion poblacional es de un 7%, ahora revisemos si con un 99% de confianza el intervalo se cierra un poco más
valor_critico <- 2.576 #intervalo de confianza del 95%
error_estandar.proporcional = sqrt((proporcional_muestral.EN * (1 - proporcional_muestral.EN)) / tamaño_muestral)

# Intervalo de confianza de la muestra 1
limite_inferior <- proporcional_muestral.EN - valor_critico * error_estandar.proporcional
limite_superior <- proporcional_muestral.EN + valor_critico * error_estandar.proporcional

cat("Con una confianza del 99% podemos inferir que la proporción poblacional de los empleados que se encuentran en un entry level a partir de los datos de la población se encuentra entre un: [", round(limite_inferior*100,2), "%,", round(limite_superior*100,2), "%]\n")
## Con una confianza del 99% podemos inferir que la proporción poblacional de los empleados que se encuentran en un entry level a partir de los datos de la población se encuentra entre un: [ 4.18 %, 11.29 %]
Conclusión

El intervalo de confianza a medida que aumenta su severidad (95% a 99%) no se volvió un intervalo más pequeño sino que se aumentó.Esto sucede porque, para ser más seguros de que el verdadero parámetro poblacional está dentro del intervalo, se necesita considerar un rango más amplio de valores.

Resultados

Prueba de normalidad

Antes de realizar una prueba de hipótesis sobre los datos, es fundamental verificar si estos siguen una distribución normal, ya que esta conclusión determina el tipo de prueba que se debe emplear para validar la hipótesis. Para este caso especifico se decide prácticar la prueba de Kolmogorov-Smirnov (K-S) ya que nuestra cantidad de datos es grande por lo que si se usa la prueba de Shapiro-Wilk puede que detecte pequeñas variaciones irrelevantes.

media_muestral <- mean(muestra.estratificada$salary_in_usd)
sd_muestral <- sd(muestra.estratificada$salary_in_usd)
resultado <- ks.test(muestra.estratificada$salary_in_usd, "pnorm", mean = media_muestral, sd = sd_muestral)
## Warning in ks.test.default(muestra.estratificada$salary_in_usd, "pnorm", : ties
## should not be present for the one-sample Kolmogorov-Smirnov test
resultado
## 
##  Asymptotic one-sample Kolmogorov-Smirnov test
## 
## data:  muestra.estratificada$salary_in_usd
## D = 0.085754, p-value = 0.00805
## alternative hypothesis: two-sided

La prueba de kolmogorov nos retorna un p-value de 0.00805 esto es menor que nuestro valor de criticidad de 0.05 (0.008 < 0.05) por ende se rechaza la hipótesis nula y se afirma de que los datos no siguen una distribución normal, con el fin de tener una segunda validación se propone aplicar el gráfico de Q-Q plot para poder ver el comportamiento del mismo.

qqnorm(muestra.estratificada$salary_in_usd)
qqline(muestra.estratificada$salary_in_usd, col="red")

El Q-Q plot confirma que el salario en dólares en nuestra muestra no sigue una distribución normal, ya que se observan valores atípicos en los salarios altos que se desvían significativamente de la normalidad.

Prueba de hipótesis

  • H₀ (Hipótesis Nula): El salario de los empleados de empresas grandes no es significativamente mayor en comparación con el salario de los empleados de empresas de menor tamaño.

  • H₁ (Hipótesis Alternativa): El salario de los empleados de empresas grandes es significativamente mayor en comparación con el salario de los empleados de empresas de menor tamaño.

  • Error Tipo I (αα): Concluir incorrectamente que los salarios de los empleados en empresas grandes son significativamente mayores que en las pequeñas, cuando en realidad no lo son.

  • Error Tipo II (ββ): Concluir incorrectamente que no existe una diferencia significativa entre los salarios de empleados de empresas grandes y pequeñas, cuando en realidad sí existe una diferencia.

Se aplica comparación de medias con una prueba t de muestras independientes.

# Realizar análisis de medianas usando kruskal-wallis
kruskal_test <- kruskal.test(salary_in_usd ~ company_size, data = muestra.estratificada)

# Resumen del resultado
kruskal_test
## 
##  Kruskal-Wallis rank sum test
## 
## data:  salary_in_usd by company_size
## Kruskal-Wallis chi-squared = 0.33357, df = 2, p-value = 0.8464

Inferencia de datos

  • Existe una marcada desigualdad salarial en empresas medianas, con una distribución bimodal que indica posible segmentación entre roles técnicos/no técnicos o diferentes niveles de especialización.
  • Las empresas pequeñas tienden a ser más conservadoras en su estructura salarial, con menos variabilidad y compensaciones más bajas, posiblemente debido a recursos más limitados o estructuras organizacionales más simples.
  • Los profesionales Entry-level, a pesar de tener los salarios más bajos en promedio, muestran algunos valores atípicos muy altos en todas las categorías de empresas, lo que sugiere la existencia de roles o tecnologías emergentes donde incluso los juniors pueden acceder a compensaciones excepcionales si poseen habilidades muy específicas o demandadas.

Resultados clave:

Valor del estadístico de prueba:

  • El estadístico de Kruskal-Wallis es 213.54, lo que indica una fuerte variación entre los grupos.

Grados de libertad (df):

  • Los grados de libertad son 2, correspondientes a los tres niveles de la variable company_size (pequeña, mediana, grande).

P-valor 0.8464:

  • Como el p-valor es alto, no podemos concluir que existan diferencias significativas en los salarios entre empresas de diferentes tamaños.

Interpretación:

Conclusión sobre H₀:

Se acepta la hipótesis nula, concluyendo que el salario de los empleados de empresas grandes no es significativamente mayor en comparación con los de empresas de otros tamaños dentro del contexto de los datos analizados.

Conclusiones Finales

Recomendaciones

Referencias

Delikkaya, Y. (2024). Data Science Salaries 2024 [Dataset]. Kaggle. https://www.kaggle.com/datasets/yusufdelikkaya/datascience-salaries-2024