Limpieza de Datos

df <- data.frame(
  ID = c(1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10),
  Age = c(20, 21, 250, 19, 20, 22, 20, 21, 21, 23, 20),
  Gender = c("F", "Female", "M", "male", "F", "M", "F", "F", "F", "Male", "F"),
  Height_cm = c(165, 170, 180, -172, 1.68, 175, 160, 162, 162, 178, 167),
  Weight_kg = c(58, 62, 75, 68, 55, NA, 54, 56, 56, 72, 59),
  Sleep_hours = c(7, 6, 5, NA, 9, 4, 25, 7, 7, 6, 6.5),
  Stress_level = c("3", "4", "8", "2", "low", "5", "3", "3", "3", "4", "2"),
  Exercise_days = c(4, 3, 2, 5, 6, -1, 2, 2, 2, 3, 4),
  Smoker = c("No", "No", "Yes", "No", "No", "Yes", "N", "No", "No", "Yes", "No"),
  GPA = c(8.7, 9.1, 7.8, 8.0, 15.0, 7.2, 8.5, 8.9, 8.9, NA, 8.3),
  Survey_Date = c("2025-08-01", "01/08/2025", "2025-08-02", "2025-08-03", 
                  "2025-08-04", "2025-08-05", "2025-13-01", "2025-08-06", 
                  "2025-08-06", "August 7, 2025", "2025-08-08"),
  stringsAsFactors = FALSE
)

Como primer punto se ingresa la tabla de datos con la que se estará trabajando.

# View data
print(df)
##    ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 1   1  20      F    165.00        58         7.0            3             4
## 2   2  21 Female    170.00        62         6.0            4             3
## 3   3 250      M    180.00        75         5.0            8             2
## 4   4  19   male   -172.00        68          NA            2             5
## 5   5  20      F      1.68        55         9.0          low             6
## 6   6  22      M    175.00        NA         4.0            5            -1
## 7   7  20      F    160.00        54        25.0            3             2
## 8   8  21      F    162.00        56         7.0            3             2
## 9   8  21      F    162.00        56         7.0            3             2
## 10  9  23   Male    178.00        72         6.0            4             3
## 11 10  20      F    167.00        59         6.5            2             4
##    Smoker  GPA    Survey_Date
## 1      No  8.7     2025-08-01
## 2      No  9.1     01/08/2025
## 3     Yes  7.8     2025-08-02
## 4      No  8.0     2025-08-03
## 5      No 15.0     2025-08-04
## 6     Yes  7.2     2025-08-05
## 7       N  8.5     2025-13-01
## 8      No  8.9     2025-08-06
## 9      No  8.9     2025-08-06
## 10    Yes   NA August 7, 2025
## 11     No  8.3     2025-08-08

Identificar valores faltantes dentro de la tabla

cat("\n Missing Values per Column: \n")
## 
##  Missing Values per Column:
print(colSums(is.na(df)))
##            ID           Age        Gender     Height_cm     Weight_kg 
##             0             0             0             0             1 
##   Sleep_hours  Stress_level Exercise_days        Smoker           GPA 
##             1             0             0             0             1 
##   Survey_Date 
##             0

Este fragmento de código muestra por cada categoría el número de datos faltantes que hay (NA), podemos observar que hay tres variables con datos faltantes (Weight_kg,Sleep_hours,GPA) y cada una le falta un valor. ## Detectar duplicados

cat("\n Duplicate rows: \n")
## 
##  Duplicate rows:
print(df[duplicated(df), ])
##   ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 9  8  21      F       162        56           7            3             2
##   Smoker GPA Survey_Date
## 9     No 8.9  2025-08-06

El código muestra que la fila 9 esta repetida, lo que significa que solo la información de este paciente se repite dentro de la tabla.

Comprobación de alcance

cat("\n Suspicious ages: \n")
## 
##  Suspicious ages:
print(df[df$Age < 0 | df$Age > 100, ])  
##   ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 3  3 250      M       180        75           5            8             2
##   Smoker GPA Survey_Date
## 3    Yes 7.8  2025-08-02
cat("\n Suspicious heigths : \n")
## 
##  Suspicious heigths :
print(df[df$Height_cm < 50 | df$Height_cm > 250, ])
##   ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 4  4  19   male   -172.00        68          NA            2             5
## 5  5  20      F      1.68        55           9          low             6
##   Smoker GPA Survey_Date
## 4     No   8  2025-08-03
## 5     No  15  2025-08-04
cat("\n Suspicious sleep hours: \n")
## 
##  Suspicious sleep hours:
print(df[df$Sleep_hours < 0 | df$Sleep_hours > 24, ])
##    ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## NA NA  NA   <NA>        NA        NA          NA         <NA>            NA
## 7   7  20      F       160        54          25            3             2
##    Smoker GPA Survey_Date
## NA   <NA>  NA        <NA>
## 7       N 8.5  2025-13-01
cat("\n Suspicious GPA:  \n")
## 
##  Suspicious GPA:
print(df[df$GPA < 0 | df$GPA > 10, ])
##    ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 5   5  20      F      1.68        55           9          low             6
## NA NA  NA   <NA>        NA        NA          NA         <NA>            NA
##    Smoker GPA Survey_Date
## 5      No  15  2025-08-04
## NA   <NA>  NA        <NA>
cat("\n Suspicious exercise day: \n")
## 
##  Suspicious exercise day:
print(df[df$Exercise_days < 0 | df$Exercise_days > 7, ])
##   ID Age Gender Height_cm Weight_kg Sleep_hours Stress_level Exercise_days
## 6  6  22      M       175        NA           4            5            -1
##   Smoker GPA Survey_Date
## 6    Yes 7.2  2025-08-05

Dentro de estas líneas de código se establecen relaciones lógicas para determinar si la información contenido dentro de cada categoría es coherente, por ejemplo si nos encontramos en la edad del paciente solo se acepta de un rango de edad de 0 a 100 y así se restringe cada categoría.

Categorías inconsistentes

cat("\n Unique values in Gender: \n")
## 
##  Unique values in Gender:
print(unique(df$Gender))
## [1] "F"      "Female" "M"      "male"   "Male"
cat("\n Unique Values in Smoker: \n")
## 
##  Unique Values in Smoker:
print(unique(df$Smoker))
## [1] "No"  "Yes" "N"
cat("\n Unique Values is Stress_Level: \n")
## 
##  Unique Values is Stress_Level:
print(unique(df$Stress_level))
## [1] "3"   "4"   "8"   "2"   "low" "5"

Con ayuda de la función unique() busca dentro de las categorías seleccionadas todas las respuestas proporcionadas por los pacientes, como en el caso de sí son fumadores se obtuvieron tres tipos de respuesta diferente “No”,“Yes”, y “N”, lo que permite identificar inconsisntencias dentro de los datos recopilados.

Simple recording

df$Gender <- tolower(df$Gender)
df$Gender[df$Gender == "female"] <- "f"
df$Gender[df$Gender == "male"] <- "m"

df$Smoker <- tolower(df$Smoker)
df$Smoker[df$Smoker == "n"] <- "no"

cat("\n Cleaned Gender Values: \n")
## 
##  Cleaned Gender Values:
print(unique(df$Gender))
## [1] "f" "m"
cat("\n Cleaned Smoker Values: \n")
## 
##  Cleaned Smoker Values:
print(unique(df$Smoker))
## [1] "no"  "yes"

Como primer punto se asegura de convertir la información a minúsculas para poder manipularla, luego de eso como ya se habían identificado las respuestas de los pacientes érmite hacer un cambio de esas respuestas a otras más apropiadas, se observa cuando intecambia “n” por “no” y así se asegura que la información en la tabla este limpia.

Convertir Respuesta de Estrés a numérica.

df$Stress_level_num <- suppressWarnings(as.numeric(df$Stress_level))

cat("\n Rows with not numeric stress levels: \n")
## 
##  Rows with not numeric stress levels:
print(df[is.na(df$Stress_level_num), c("ID","Stress_level")])
##   ID Stress_level
## 5  5          low

Este fragmento de código lo que hace es identificar el id del paciente que no tiene un vakor numérico dentro de su respesta. Primero as.numeric(df$Stress_level) convierte todos los valores a numérico y si hay alguno que no está en este formato lo convierte a NA, luego los resultados se guardan en una columna nueva Stress_level_num y finalmente con is.na(dfStress_level_num), busca donde la conversión falló y permite mostrar la fila del paciente donde hay un valor no numérico.

Imputación simple.

median_weight <- median(df$Weight_kg, na.rm = TRUE) 
df$Weight_kg[is.na(df$Weight_kg)] <- median_weight

# Median Imputation for Sleep_Hours
median_sleep <- median(df$Sleep_hours)

Por último, esta parte del código lo que permite es que en lugar de eliminar filas