Parte 1: Identificación de problemas en los datos

1. Exploren los datos asignados a su grupo

df <- read_csv("Grupo_2.csv")
## Rows: 100 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (6): Ciudad, Nivel_Educativo, Estado_Civil, Sector_Laboral, Propietario_...
## dbl (6): ID, Edad, Salario, Experiencia, Horas_Trabajo_Semana, Cantidad_Hijos
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(df)
## # A tibble: 6 × 12
##      ID  Edad Salario Experiencia Ciudad   Nivel_Educativo Horas_Trabajo_Semana
##   <dbl> <dbl>   <dbl>       <dbl> <chr>    <chr>                          <dbl>
## 1     1    35   27203          NA Ponce    Primaria                          54
## 2     2    43   45647          10 San Juan Primaria                          36
## 3     3    53   42181          10 Caguas   Universitario                     26
## 4     4    38   58530          20 Ponce    Universitario                     45
## 5     5    58   76972          NA Ponce    Universitario                     59
## 6     6    46   59877          NA Caguas   Primaria                          60
## # ℹ 5 more variables: Estado_Civil <chr>, Sector_Laboral <chr>,
## #   Cantidad_Hijos <dbl>, Propietario_Vivienda <chr>, Rango_Salario <chr>
dim(df)
## [1] 100  12
glimpse(df)
## Rows: 100
## Columns: 12
## $ ID                   <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15…
## $ Edad                 <dbl> 35, 43, 53, 38, 58, 46, 38, 62, 35, 30, 45, 33, 3…
## $ Salario              <dbl> 27203, 45647, 42181, 58530, 76972, 59877, 30183, …
## $ Experiencia          <dbl> NA, 10, 10, 20, NA, NA, 26, 29, 38, 24, 30, 30, 2…
## $ Ciudad               <chr> "Ponce", "San Juan", "Caguas", "Ponce", "Ponce", …
## $ Nivel_Educativo      <chr> "Primaria", "Primaria", "Universitario", "Univers…
## $ Horas_Trabajo_Semana <dbl> 54, 36, 26, 45, 59, 60, 22, 41, 49, 33, 28, 50, 5…
## $ Estado_Civil         <chr> "Casado", "Casado", NA, "Casado", "Casado", "Casa…
## $ Sector_Laboral       <chr> "Público", "Público", "Independiente", "Público",…
## $ Cantidad_Hijos       <dbl> 3, 3, 5, NA, 5, 4, 0, 0, 3, 5, 5, 3, NA, 2, 1, 3,…
## $ Propietario_Vivienda <chr> "No", "No", "Sí", "Sí", "Sí", "No", "Sí", "Sí", "…
## $ Rango_Salario        <chr> "Bajo", "Medio", "Medio", "Medio", "Alto", "Medio…
summary(df)
##        ID              Edad          Salario       Experiencia   
##  Min.   :  1.00   Min.   :18.00   Min.   :20213   Min.   : 0.00  
##  1st Qu.: 25.75   1st Qu.:31.00   1st Qu.:37544   1st Qu.:10.00  
##  Median : 50.50   Median :46.00   Median :52147   Median :19.00  
##  Mean   : 50.50   Mean   :43.65   Mean   :50512   Mean   :19.96  
##  3rd Qu.: 75.25   3rd Qu.:56.00   3rd Qu.:62582   3rd Qu.:30.00  
##  Max.   :100.00   Max.   :64.00   Max.   :79438   Max.   :40.00  
##                   NA's   :7       NA's   :9       NA's   :11     
##     Ciudad          Nivel_Educativo    Horas_Trabajo_Semana Estado_Civil      
##  Length:100         Length:100         Min.   :20.00        Length:100        
##  Class :character   Class :character   1st Qu.:28.00        Class :character  
##  Mode  :character   Mode  :character   Median :41.00        Mode  :character  
##                                        Mean   :39.65                          
##                                        3rd Qu.:49.00                          
##                                        Max.   :60.00                          
##                                        NA's   :3                              
##  Sector_Laboral     Cantidad_Hijos  Propietario_Vivienda Rango_Salario     
##  Length:100         Min.   :0.000   Length:100           Length:100        
##  Class :character   1st Qu.:1.000   Class :character     Class :character  
##  Mode  :character   Median :3.000   Mode  :character     Mode  :character  
##                     Mean   :2.787                                          
##                     3rd Qu.:4.000                                          
##                     Max.   :5.000                                          
##                     NA's   :11

2. Identifiquen los problemas en los datos.

Valores faltantes

vis_miss(df)

colSums(is.na(df))
##                   ID                 Edad              Salario 
##                    0                    7                    9 
##          Experiencia               Ciudad      Nivel_Educativo 
##                   11                    4                    3 
## Horas_Trabajo_Semana         Estado_Civil       Sector_Laboral 
##                    3                    4                    1 
##       Cantidad_Hijos Propietario_Vivienda        Rango_Salario 
##                   11                    3                    9

Inconsistencias

df %>% filter(!is.na(Edad), !is.na(Experiencia), Experiencia > Edad) %>% select(Edad, Experiencia)
## # A tibble: 10 × 2
##     Edad Experiencia
##    <dbl>       <dbl>
##  1    35          38
##  2    18          37
##  3    26          30
##  4    25          35
##  5    23          28
##  6    25          40
##  7    20          37
##  8    25          27
##  9    20          36
## 10    28          29

Posibles valores extremos

df %>% select(where(is.numeric)) %>% summary()
##        ID              Edad          Salario       Experiencia   
##  Min.   :  1.00   Min.   :18.00   Min.   :20213   Min.   : 0.00  
##  1st Qu.: 25.75   1st Qu.:31.00   1st Qu.:37544   1st Qu.:10.00  
##  Median : 50.50   Median :46.00   Median :52147   Median :19.00  
##  Mean   : 50.50   Mean   :43.65   Mean   :50512   Mean   :19.96  
##  3rd Qu.: 75.25   3rd Qu.:56.00   3rd Qu.:62582   3rd Qu.:30.00  
##  Max.   :100.00   Max.   :64.00   Max.   :79438   Max.   :40.00  
##                   NA's   :7       NA's   :9       NA's   :11     
##  Horas_Trabajo_Semana Cantidad_Hijos 
##  Min.   :20.00        Min.   :0.000  
##  1st Qu.:28.00        1st Qu.:1.000  
##  Median :41.00        Median :3.000  
##  Mean   :39.65        Mean   :2.787  
##  3rd Qu.:49.00        3rd Qu.:4.000  
##  Max.   :60.00        Max.   :5.000  
##  NA's   :3            NA's   :11

3. Propongan estrategias de preprocesamiento para solucionar estos problemas.

Parte 2: Imputación de datos

1. Para las variables con valores faltantes, decidan cuál método de imputación aplicar (media, mediana, moda, regresión, eliminación, etc.).

Se utilizarán dos estrategias de imputación:

Imputación simple: - Variables numéricas -> Mediana - Variables categóricas -> Moda

Imputación multivariada: - Método MICE (Multiple Imputation by Chained Equations)

Estas estrategias permiten comparar un método simple con uno más avanzado que utiliza información de múltiples variables.

2. Justifiquen su elección con base en la naturaleza de los datos.

Se utilizaron diferentes métodos de imputación dependiendo del tipo de variable. Para las variables numéricas (Edad, Salario, Experiencia, Horas_Trabajo_Semana y Cantidad_Hijos) se utilizó la mediana, ya que ayuda a evitar que valores extremos afecten demasiado los resultados y permite mantener el tamaño de la muestra. Para las variables categóricas (Ciudad, Nivel_Educativo, Estado_Civil, Sector_Laboral y Propietario_Vivienda) se utilizó la moda, porque simplemente reemplaza los valores faltantes con la categoría que aparece con más frecuencia en los datos. Además, se utilizó imputación multivariada con el paquete mice, que estima los valores faltantes utilizando la información de varias variables al mismo tiempo, lo que ayuda a conservar mejor la relación entre los datos.

3. Apliquen diferentes estrategias de imputación según las características de las variables de su conjunto de datos.

# Imputación numéricas con mediana

df_median <- df %>%
  mutate(across(where(is.numeric),
                ~ ifelse(is.na(.x), median(.x, na.rm = TRUE), .x)))

data_median_long <- bind_rows(
  df %>% select(where(is.numeric)) %>% mutate(Origen = "Original"),
  df_median %>% select(where(is.numeric)) %>% mutate(Origen = "Imputado (Mediana)")
) %>%
  pivot_longer(cols = -Origen, names_to = "Variable", values_to = "Valor") %>%
  filter(!is.na(Valor))

p_median <- ggplot(data_median_long, aes(x = Valor, color = Origen, fill = Origen, text = Origen)) +
  geom_density(alpha = 0.2) +
  facet_wrap(~Variable, scales = "free") +
  labs(title = "Original vs Imputado con Mediana (Variables numéricas)", x = "Valor", y = "Densidad") +
  theme_minimal()

ggplotly(p_median, tooltip = c("text", "x", "y"))
df_imp <- df %>%
  mutate(
    Edad = ifelse(is.na(Edad), median(Edad, na.rm = TRUE), Edad),
    Salario = ifelse(is.na(Salario), median(Salario, na.rm = TRUE), Salario),
    Experiencia = ifelse(is.na(Experiencia), median(Experiencia, na.rm = TRUE), Experiencia),
    Horas_Trabajo_Semana = ifelse(is.na(Horas_Trabajo_Semana), median(Horas_Trabajo_Semana, na.rm = TRUE), Horas_Trabajo_Semana),
    Cantidad_Hijos = ifelse(is.na(Cantidad_Hijos), median(Cantidad_Hijos, na.rm = TRUE), Cantidad_Hijos)
  )
moda_estado <- names(sort(table(df_imp$Estado_Civil), decreasing = TRUE))[1]

# Datos para comparar antes vs después
data_estado <- bind_rows(
  df %>% select(Estado_Civil) %>% mutate(Origen = "Original"),
  df_imp %>% select(Estado_Civil) %>% mutate(Origen = "Imputado (Moda)")
) %>%
  filter(!is.na(Estado_Civil))  # comparación justa (quita NA del original)

# 1) Identificar columnas categóricas (character o factor)
cat_cols <- names(df)[sapply(df, function(x) is.character(x) | is.factor(x))]

# 2) Crear data en formato largo: Original vs Imputado (Moda)
data_cat_all <- bind_rows(
  df %>%
    select(all_of(cat_cols)) %>%
    mutate(Origen = "Original"),
  df_imp %>%
    select(all_of(cat_cols)) %>%
    mutate(Origen = "Imputado (Moda)")
) %>%
  mutate(across(all_of(cat_cols), as.character)) %>%  # evita problemas con factores
  pivot_longer(
    cols = all_of(cat_cols),
    names_to = "Variable",
    values_to = "Categoria"
  ) %>%
  filter(!is.na(Categoria))

# 3) Gráfica de barras con facetas por variable categórica
p_moda_all <- ggplot(data_cat_all, aes(x = Categoria, fill = Origen)) +
  geom_bar(position = "dodge") +
  facet_wrap(~Variable, scales = "free_x") +
  labs(
    title = "Variables categóricas: Original vs Imputado con Moda",
    x = "Categoría",
    y = "Frecuencia"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplotly(p_moda_all)
#  Imputación multivariada usando MICE
imp_mice <- mice(df, method = "pmm", m = 5, print = FALSE)
## Warning: Number of logged events: 6
df_mice <- mice::complete(imp_mice)
data_mice_long <- bind_rows(
  df %>% select(where(is.numeric)) %>% mutate(Origen = "Original"),
  df_mice %>% select(where(is.numeric)) %>% mutate(Origen = "Imputado (MICE)")
) %>%
  pivot_longer(cols = -Origen, names_to = "Variable", values_to = "Valor") %>%
  filter(!is.na(Valor))

p_mice <- ggplot(
  data_mice_long,
  aes(x = Valor, color = Origen, fill = Origen, text = paste("Origen:", Origen))
) +
  geom_density(alpha = 0.2) +
  facet_wrap(~Variable, scales = "free") +
  labs(
    title = "Original vs Imputado con MICE",
    x = "Valor",
    y = "Densidad"
  ) +
  theme_minimal()

ggplotly(p_mice, tooltip = c("text", "x", "y"))
#  Imputación multivariada usando norm.predict

Imput_reg_mult <- mice(df, method = "norm.predict", m = 5, print = FALSE)
## Warning: Number of logged events: 6
Complete_reg_mult <- mice::complete(Imput_reg_mult)

data_reg_long <- bind_rows(
  df %>% select(where(is.numeric)) %>% mutate(Origen = "Original"),
  Complete_reg_mult %>% select(where(is.numeric)) %>% mutate(Origen = "Regresión múltiple")
) %>%
  pivot_longer(cols = -Origen, names_to = "Variable", values_to = "Valor") %>%
  filter(!is.na(Valor))

p_reg <- ggplot(
  data_reg_long,
  aes(x = Valor, color = Origen, fill = Origen, text = paste("Origen:", Origen))
) +
  geom_density(alpha = 0.2) +
  facet_wrap(~Variable, scales = "free") +
  labs(
    title = "Original vs Imputado (Regresión múltiple: norm.predict)",
    x = "Valor",
    y = "Densidad"
  ) +
  theme_minimal()

ggplotly(p_reg, tooltip = c("text", "x", "y"))

4. Comparen los resultados obtenidos con cada estrategia y expliquen cuál es la más adecuada en su caso.

Mediana:

Sugiere que la mediana no cambió de forma importante la distribución general.Imputación.

Moda Se mantiene igual el imputado y el original.

MICE (pmm):

Sugiere que MICE preserva bien la distribución y, al ser multivariado, tiende a conservar mejor las relaciones entre variables que un método univariado.

Regresión múltiple (norm.predict):

Distribución es similar, pero este método tiende a generar valores más suaves y alineados con el modelo, lo que puede reducir la variabilidad real y hacer que los datos imputados queden demasiado pegados a patrones lineales.

Conclusión:

Para este conjunto de datos, la imputación multivariada con MICE (pmm) es la más adecuada para las variables numéricas porque mantiene la distribución observada y ayuda a preservar relaciones entre variables.

5. Expliquen cómo la elección del método de imputación afecta el análisis posterior de los datos.

El método de imputación puede modificar tanto la distribución de las variables como las relaciones entre ellas.

Media/mediana pueden reducir la variabilidad, especialmente si hay muchos faltantes, lo que puede afectar histogramas/densidades y también impactar medidas como la desviación estándar.

Moda puede aumentar la frecuencia de una categoría específica, alterando proporciones y comparaciones entre grupos..

El norm.predict puede fortalecer artificialmente relaciones lineales porque los valores imputados se ajustan a un modelo, lo que puede influir en correlaciones..

MICE (pmm) suele preservar mejor la distribución y las relaciones multivariadas, por lo que puede producir conclusiones más consistentes cuando el análisis depende de correlaciones, modelos predictivos o comparaciones entre variables.

Parte 3: Discretización y modificación

1. Transformen las variables categóricas en un formato adecuado para el análisis.

df_final <- df_imp %>% mutate(across(where(is.character), as.factor))

df_final <- df_final %>% mutate(Rango_Salario = case_when(Salario < 20000 ~ "Bajo", Salario < 50000 ~ "Medio", Salario >= 50000 ~ "Alto"))

glimpse(df_final)
## Rows: 100
## Columns: 12
## $ ID                   <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15…
## $ Edad                 <dbl> 35, 43, 53, 38, 58, 46, 38, 62, 35, 30, 45, 33, 3…
## $ Salario              <dbl> 27203, 45647, 42181, 58530, 76972, 59877, 30183, …
## $ Experiencia          <dbl> 19, 10, 10, 20, 19, 19, 26, 29, 38, 24, 30, 30, 2…
## $ Ciudad               <fct> Ponce, San Juan, Caguas, Ponce, Ponce, Caguas, Ca…
## $ Nivel_Educativo      <fct> Primaria, Primaria, Universitario, Universitario,…
## $ Horas_Trabajo_Semana <dbl> 54, 36, 26, 45, 59, 60, 22, 41, 49, 33, 28, 50, 5…
## $ Estado_Civil         <fct> Casado, Casado, NA, Casado, Casado, Casado, Casad…
## $ Sector_Laboral       <fct> Público, Público, Independiente, Público, Indepen…
## $ Cantidad_Hijos       <dbl> 3, 3, 5, 3, 5, 4, 0, 0, 3, 5, 5, 3, 3, 2, 1, 3, 5…
## $ Propietario_Vivienda <fct> No, No, Sí, Sí, Sí, No, Sí, Sí, Sí, No, No, No, N…
## $ Rango_Salario        <chr> "Medio", "Medio", "Medio", "Alto", "Alto", "Alto"…

2. Expliquen las decisiones tomadas en este proceso.

Se estandarizaron los nombres de las columnas con clean_names() para evitar inconsistencias en los nombres (espacios, mayúsculas o caracteres especiales). Luego se transformaron las variables categóricas de tipo character a tipo factor, ya que en R las variables categóricas deben estar en formato factor para análisis y visualización, permitiendo que el programa reconozca correctamente sus categorías y facilite comparaciones entre grupos.

Parte 4: Visualización avanzada

1. Crea un mapa de calor interactivo de correlaciones entre las variables numéricas usando plotly.

cor_mat <- df_final %>%
  select(where(is.numeric)) %>%
  cor(use = "complete.obs")

plot_ly(
  x = colnames(cor_mat),
  y = colnames(cor_mat),
  z = cor_mat,
  type = "heatmap"
)

¿Qué patrones observas en los datos?

Podemos ver que las dos relaciones mas grandes son de salario con experiencia y edad con cantidad de hijos. Ambos hacen sentido ya que con mas experiencia tiende uno a tener mayor sueldo y las personas con mas edad han tenido tiempo a tener mas hijos.

2. Genera un gráfico de barras interactivo con ggplotly para comparar cantidad de hijos según el rango de salario.

p_barras <- df_final %>%
  count(Rango_Salario, Cantidad_Hijos) %>%
  ggplot(aes(x = Rango_Salario, y = n, fill = factor(Cantidad_Hijos))) +
  geom_bar(stat = "identity", position = "dodge")

ggplotly(p_barras)

¿Qué patrones observas en los datos?

Podemos ver que las personas con un salario mas alto tienen mas hijos en general.

3. Crea un gráfico de dispersión donde se visualice la relación entre Salario y Experiencia.

plot_ly(
  df_final,
  x = ~Experiencia,
  y = ~Salario,
  type = "scatter",
  mode = "markers"
)

¿Qué patrones observas en los datos?

Con la grafica no es completamente obvio pero si nos fijamos los puntos se ven mas concentrado arriba a la derecha lo que señala lo mismo que vimos en el mapa de calor, que con mas experiencia el salario tiende a ser mas alto.