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
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.
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.
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.
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.
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.
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 calcula con la mediana y le asigna ese valor a los NA.