El presente documento en formato R Markdown desarrolla una revisión
integral de la base de datos
Sleep_health_and_lifestyle_dataset.csv. En primer lugar, se
realiza una revisión de las variables con el fin de identificar su
naturaleza, su utilidad analítica y los ajustes previos necesarios para
su adecuada interpretación. Posteriormente, se construyen las
visualizaciones recomendadas para cada variable usando
ggplot2, acompañadas de una interpretación orientada al
análisis estadístico. En una sección independiente se incorporan los
análisis de normalidad mediante la prueba de Shapiro-Wilk y gráficos QQ
para las variables cuantitativas pertinentes. Finalmente, se propone una
sección de modelado con variables respuesta y explicativas coherentes
con la estructura de la base y con el contexto del problema.
library(ggplot2)
datos <- read.csv("Sleep_health_and_lifestyle_dataset.csv")
str(datos)
## 'data.frame': 374 obs. of 13 variables:
## $ Person.ID : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Gender : chr "Male" "Male" "Male" "Male" ...
## $ Age : int 27 28 28 28 28 28 29 29 29 29 ...
## $ Occupation : chr "Software Engineer" "Doctor" "Doctor" "Sales Representative" ...
## $ Sleep.Duration : num 6.1 6.2 6.2 5.9 5.9 5.9 6.3 7.8 7.8 7.8 ...
## $ Quality.of.Sleep : int 6 6 6 4 4 4 6 7 7 7 ...
## $ Physical.Activity.Level: int 42 60 60 30 30 30 40 75 75 75 ...
## $ Stress.Level : int 6 8 8 8 8 8 7 6 6 6 ...
## $ BMI.Category : chr "Overweight" "Normal" "Normal" "Obese" ...
## $ Blood.Pressure : chr "126/83" "125/80" "125/80" "140/90" ...
## $ Heart.Rate : int 77 75 75 85 85 85 82 70 70 70 ...
## $ Daily.Steps : int 4200 10000 10000 3000 3000 3000 3500 8000 8000 8000 ...
## $ Sleep.Disorder : chr "None" "None" "None" "Sleep Apnea" ...
head(datos)
## Person.ID Gender Age Occupation Sleep.Duration Quality.of.Sleep
## 1 1 Male 27 Software Engineer 6.1 6
## 2 2 Male 28 Doctor 6.2 6
## 3 3 Male 28 Doctor 6.2 6
## 4 4 Male 28 Sales Representative 5.9 4
## 5 5 Male 28 Sales Representative 5.9 4
## 6 6 Male 28 Software Engineer 5.9 4
## Physical.Activity.Level Stress.Level BMI.Category Blood.Pressure Heart.Rate
## 1 42 6 Overweight 126/83 77
## 2 60 8 Normal 125/80 75
## 3 60 8 Normal 125/80 75
## 4 30 8 Obese 140/90 85
## 5 30 8 Obese 140/90 85
## 6 30 8 Obese 140/90 85
## Daily.Steps Sleep.Disorder
## 1 4200 None
## 2 10000 None
## 3 10000 None
## 4 3000 Sleep Apnea
## 5 3000 Sleep Apnea
## 6 3000 Insomnia
summary(datos)
## Person.ID Gender Age Occupation
## Min. : 1.00 Length:374 Min. :27.00 Length:374
## 1st Qu.: 94.25 Class :character 1st Qu.:35.25 Class :character
## Median :187.50 Mode :character Median :43.00 Mode :character
## Mean :187.50 Mean :42.18
## 3rd Qu.:280.75 3rd Qu.:50.00
## Max. :374.00 Max. :59.00
## Sleep.Duration Quality.of.Sleep Physical.Activity.Level Stress.Level
## Min. :5.800 Min. :4.000 Min. :30.00 Min. :3.000
## 1st Qu.:6.400 1st Qu.:6.000 1st Qu.:45.00 1st Qu.:4.000
## Median :7.200 Median :7.000 Median :60.00 Median :5.000
## Mean :7.132 Mean :7.313 Mean :59.17 Mean :5.385
## 3rd Qu.:7.800 3rd Qu.:8.000 3rd Qu.:75.00 3rd Qu.:7.000
## Max. :8.500 Max. :9.000 Max. :90.00 Max. :8.000
## BMI.Category Blood.Pressure Heart.Rate Daily.Steps
## Length:374 Length:374 Min. :65.00 Min. : 3000
## Class :character Class :character 1st Qu.:68.00 1st Qu.: 5600
## Mode :character Mode :character Median :70.00 Median : 7000
## Mean :70.17 Mean : 6817
## 3rd Qu.:72.00 3rd Qu.: 8000
## Max. :86.00 Max. :10000
## Sleep.Disorder
## Length:374
## Class :character
## Mode :character
##
##
##
# La variable Sleep Disorder contiene valores faltantes. En esta base se asumirán
# como ausencia de trastorno del sueño.
datos$Sleep.Disorder[is.na(datos$Sleep.Disorder)] <- "No Disorder"
datos$Sleep.Disorder <- as.factor(datos$Sleep.Disorder)
# Unificación de categorías de BMI Category
datos$BMI.Category[datos$BMI.Category == "Normal Weight"] <- "Normal"
datos$BMI.Category <- as.factor(datos$BMI.Category)
# Separación de la presión arterial en sistólica y diastólica
bp_split <- strsplit(as.character(datos$Blood.Pressure), "/")
datos$Systolic <- as.numeric(sapply(bp_split, `[`, 1))
datos$Diastolic <- as.numeric(sapply(bp_split, `[`, 2))
# Variable binaria auxiliar para modelado logístico
# 0 = No Disorder, 1 = presenta algún trastorno
datos$Sleep.Disorder.Binary <- ifelse(datos$Sleep.Disorder == "No Disorder", 0, 1)
datos$Sleep.Disorder.Binary <- as.factor(datos$Sleep.Disorder.Binary)
# Estructura final
str(datos)
## 'data.frame': 374 obs. of 16 variables:
## $ Person.ID : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Gender : chr "Male" "Male" "Male" "Male" ...
## $ Age : int 27 28 28 28 28 28 29 29 29 29 ...
## $ Occupation : chr "Software Engineer" "Doctor" "Doctor" "Sales Representative" ...
## $ Sleep.Duration : num 6.1 6.2 6.2 5.9 5.9 5.9 6.3 7.8 7.8 7.8 ...
## $ Quality.of.Sleep : int 6 6 6 4 4 4 6 7 7 7 ...
## $ Physical.Activity.Level: int 42 60 60 30 30 30 40 75 75 75 ...
## $ Stress.Level : int 6 8 8 8 8 8 7 6 6 6 ...
## $ BMI.Category : Factor w/ 3 levels "Normal","Obese",..: 3 1 1 2 2 2 2 1 1 1 ...
## $ Blood.Pressure : chr "126/83" "125/80" "125/80" "140/90" ...
## $ Heart.Rate : int 77 75 75 85 85 85 82 70 70 70 ...
## $ Daily.Steps : int 4200 10000 10000 3000 3000 3000 3500 8000 8000 8000 ...
## $ Sleep.Disorder : Factor w/ 3 levels "Insomnia","None",..: 2 2 2 3 3 1 1 2 2 2 ...
## $ Systolic : num 126 125 125 140 140 140 140 120 120 120 ...
## $ Diastolic : num 83 80 80 90 90 90 90 80 80 80 ...
## $ Sleep.Disorder.Binary : Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1 ...
# Función auxiliar para construir tablas con frecuencia, proporción y etiqueta
preparar_pastel <- function(x) {
tab <- as.data.frame(table(x))
colnames(tab) <- c("Categoria", "Frecuencia")
tab$Proporcion <- tab$Frecuencia / sum(tab$Frecuencia)
tab$Porcentaje <- round(tab$Proporcion * 100, 1)
tab$Etiqueta <- paste0(tab$Porcentaje, "%")
tab
}
A continuación se presenta una revisión general de las variables con su tipo y observaciones analíticas principales.
revision_variables <- data.frame(
Variable = c(
"Person ID", "Gender", "Age", "Occupation", "Sleep Duration",
"Quality of Sleep", "Physical Activity Level", "Stress Level",
"BMI Category", "Blood Pressure", "Heart Rate", "Daily Steps",
"Sleep Disorder", "Systolic", "Diastolic", "Sleep Disorder Binary"
),
Tipo = c(
"Identificador", "Categórica nominal", "Cuantitativa discreta",
"Categórica nominal", "Cuantitativa continua",
"Cuantitativa discreta/ordinal", "Cuantitativa discreta",
"Cuantitativa discreta/ordinal", "Categórica nominal",
"Texto compuesto", "Cuantitativa discreta", "Cuantitativa discreta",
"Categórica nominal", "Cuantitativa discreta", "Cuantitativa discreta",
"Categórica binaria"
),
Observacion = c(
"Sirve como identificador; no se recomienda para análisis sustantivo.",
"Permite comparaciones por género.",
"Adecuada para análisis descriptivo y relaciones con sueño y presión arterial.",
"Útil para comparaciones entre grupos ocupacionales.",
"Variable central del estudio; se relaciona con estrés y calidad del sueño.",
"Puede ser tratada como ordinal o numérica discreta.",
"Permite analizar el comportamiento físico diario.",
"Variable de interés por su relación con salud y sueño.",
"Conviene unificar categorías antes del análisis.",
"Debe descomponerse en sistólica y diastólica.",
"Indica condición fisiológica relevante.",
"Aproxima el nivel de actividad cotidiana.",
"Se sustituyen los NA por 'No Disorder' para facilitar el análisis.",
"Derivada de Blood Pressure para análisis cuantitativo.",
"Derivada de Blood Pressure para análisis cuantitativo.",
"Variable auxiliar para regresión logística binaria."
),
stringsAsFactors = FALSE
)
revision_variables
## Variable Tipo
## 1 Person ID Identificador
## 2 Gender Categórica nominal
## 3 Age Cuantitativa discreta
## 4 Occupation Categórica nominal
## 5 Sleep Duration Cuantitativa continua
## 6 Quality of Sleep Cuantitativa discreta/ordinal
## 7 Physical Activity Level Cuantitativa discreta
## 8 Stress Level Cuantitativa discreta/ordinal
## 9 BMI Category Categórica nominal
## 10 Blood Pressure Texto compuesto
## 11 Heart Rate Cuantitativa discreta
## 12 Daily Steps Cuantitativa discreta
## 13 Sleep Disorder Categórica nominal
## 14 Systolic Cuantitativa discreta
## 15 Diastolic Cuantitativa discreta
## 16 Sleep Disorder Binary Categórica binaria
## Observacion
## 1 Sirve como identificador; no se recomienda para análisis sustantivo.
## 2 Permite comparaciones por género.
## 3 Adecuada para análisis descriptivo y relaciones con sueño y presión arterial.
## 4 Útil para comparaciones entre grupos ocupacionales.
## 5 Variable central del estudio; se relaciona con estrés y calidad del sueño.
## 6 Puede ser tratada como ordinal o numérica discreta.
## 7 Permite analizar el comportamiento físico diario.
## 8 Variable de interés por su relación con salud y sueño.
## 9 Conviene unificar categorías antes del análisis.
## 10 Debe descomponerse en sistólica y diastólica.
## 11 Indica condición fisiológica relevante.
## 12 Aproxima el nivel de actividad cotidiana.
## 13 Se sustituyen los NA por 'No Disorder' para facilitar el análisis.
## 14 Derivada de Blood Pressure para análisis cuantitativo.
## 15 Derivada de Blood Pressure para análisis cuantitativo.
## 16 Variable auxiliar para regresión logística binaria.
La variable Person ID cumple una función exclusivamente
identificadora y, por tanto, no debe emplearse como variable explicativa
ni como variable respuesta en modelos estadísticos. Las variables
Gender, Occupation, BMI Category
y Sleep Disorder son categóricas y resultan apropiadas para
análisis de frecuencias, proporciones y asociaciones. Por su parte,
Age, Sleep Duration,
Quality of Sleep, Physical Activity Level,
Stress Level, Heart Rate y
Daily Steps permiten análisis descriptivos cuantitativos,
evaluación de normalidad y modelado. Finalmente,
Blood Pressure requiere una transformación previa, pues su
estructura original no es adecuada para análisis numérico directo; por
ello se descompone en Systolic y
Diastolic.
La variable Person ID es un identificador. No se
recomienda construir gráficos analíticos con ella, ya que su función es
únicamente distinguir registros. Su utilidad radica en la detección de
duplicados y en la trazabilidad de observaciones.
# Verificación simple de duplicados en el identificador
sum(duplicated(datos$Person.ID))
## [1] 0
Interpretación: si el valor anterior es mayor que cero, existirían identificadores repetidos, lo cual ameritaría una revisión de calidad de datos.
La variable Gender es categórica nominal. Las
visualizaciones más adecuadas son el gráfico de barras, el gráfico de
pastel y las barras apiladas con otra variable categórica.
ggplot(datos, aes(x = Gender)) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Distribución de Gender",
x = "Género", y = "Frecuencia") +
theme_minimal()
Interpretación: este gráfico permite identificar la composición de la muestra según género y verificar si existe equilibrio o predominio de alguna categoría.
tabla_gender <- preparar_pastel(datos$Gender)
ggplot(tabla_gender, aes(x = "", y = Proporcion, fill = Categoria)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") +
geom_text(aes(label = Etiqueta),
position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Proporción de Gender", fill = "Género") +
theme_void()
Interpretación: resume la participación relativa de cada género dentro del conjunto de datos; cada sector muestra directamente el porcentaje correspondiente.
ggplot(datos, aes(x = Gender, fill = Sleep.Disorder)) +
geom_bar(position = "fill") +
labs(title = "Proporción de Sleep Disorder según Gender",
x = "Género", y = "Proporción", fill = "Sleep Disorder") +
theme_minimal()
Interpretación: permite examinar cómo cambia la proporción de trastornos del sueño dentro de cada grupo de género.
La variable Age es cuantitativa discreta. Se recomienda
representarla con histograma, boxplot, densidad y gráficos comparativos
por grupos.
ggplot(datos, aes(x = Age)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Age", x = "Edad", y = "Frecuencia") +
theme_minimal()
Interpretación: permite observar la concentración de edades, la forma de la distribución y posibles agrupamientos.
ggplot(datos, aes(y = Age)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Age", y = "Edad") +
theme_minimal()
Interpretación: resume la posición central, la dispersión y la presencia de posibles valores atípicos.
ggplot(datos, aes(x = Age)) +
geom_density(fill = "orange", alpha = 0.4) +
labs(title = "Densidad de Age", x = "Edad", y = "Densidad") +
theme_minimal()
Interpretación: suaviza la distribución y facilita la identificación de asimetrías.
ggplot(datos, aes(x = Gender, y = Age, fill = Gender)) +
geom_boxplot() +
labs(title = "Age por Gender", x = "Género", y = "Edad") +
theme_minimal()
Interpretación: permite comparar la distribución de la edad según género.
La variable Occupation es categórica nominal con varias
categorías, por lo que conviene emplear gráficos de barras horizontales,
barras ordenadas y análisis cruzados con otras variables
categóricas.
ggplot(datos, aes(x = Occupation)) +
geom_bar(fill = "steelblue", color = "black") +
coord_flip() +
labs(title = "Frecuencia de Occupation",
x = "Ocupación", y = "Frecuencia") +
theme_minimal()
Interpretación: facilita la lectura de categorías cuando las etiquetas son largas o numerosas.
frecuencias_ocup <- table(datos$Occupation)
niveles_ordenados <- names(sort(frecuencias_ocup, decreasing = TRUE))
datos$Occupation.Ordenada <- factor(datos$Occupation, levels = niveles_ordenados)
ggplot(datos, aes(x = Occupation.Ordenada)) +
geom_bar(fill = "darkcyan", color = "black") +
coord_flip() +
labs(title = "Occupation ordenada por frecuencia",
x = "Ocupación", y = "Frecuencia") +
theme_minimal()
Interpretación: muestra cuáles ocupaciones tienen mayor y menor presencia en la muestra.
ggplot(datos, aes(x = Occupation.Ordenada, fill = Gender)) +
geom_bar(position = "fill") +
coord_flip() +
labs(title = "Proporción de Gender según Occupation",
x = "Ocupación", y = "Proporción", fill = "Género") +
theme_minimal()
Interpretación: evidencia la composición proporcional por género dentro de cada ocupación.
tabla_ocup_gender <- as.data.frame(table(datos$Occupation, datos$Gender))
colnames(tabla_ocup_gender) <- c("Occupation", "Gender", "Frecuencia")
ggplot(tabla_ocup_gender, aes(x = Gender, y = Occupation, fill = Frecuencia)) +
geom_tile(color = "white") +
labs(title = "Mapa de calor: Occupation vs Gender",
x = "Género", y = "Ocupación", fill = "Frecuencia") +
theme_minimal()
Interpretación: proporciona una lectura rápida de la concentración de frecuencias entre ocupación y género.
La variable Sleep Duration es cuantitativa continua. Se
recomienda trabajar con histograma, boxplot, densidad y gráficos de
dispersión.
ggplot(datos, aes(x = Sleep.Duration)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Sleep Duration",
x = "Horas de sueño", y = "Frecuencia") +
theme_minimal()
Interpretación: permite identificar el rango habitual de duración del sueño en la muestra.
ggplot(datos, aes(y = Sleep.Duration)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Sleep Duration", y = "Horas de sueño") +
theme_minimal()
Interpretación: resume la mediana, la variabilidad y la presencia de observaciones extremas.
ggplot(datos, aes(x = Sleep.Duration)) +
geom_density(fill = "orange", alpha = 0.4) +
labs(title = "Densidad de Sleep Duration",
x = "Horas de sueño", y = "Densidad") +
theme_minimal()
Interpretación: ayuda a establecer si la distribución es aproximadamente simétrica o si presenta sesgo.
ggplot(datos, aes(x = Gender, y = Sleep.Duration, fill = Gender)) +
geom_boxplot() +
labs(title = "Sleep Duration por Gender",
x = "Género", y = "Horas de sueño") +
theme_minimal()
Interpretación: compara la duración del sueño entre grupos de género.
ggplot(datos, aes(x = Sleep.Duration, y = Stress.Level)) +
geom_point(color = "blue") +
labs(title = "Sleep Duration vs Stress Level",
x = "Horas de sueño", y = "Nivel de estrés") +
theme_minimal()
Interpretación: permite explorar la relación esperada entre menor sueño y mayor estrés.
La variable Quality of Sleep puede tratarse como
cuantitativa discreta u ordinal. Se recomiendan gráficos de barras,
histograma, boxplot y dispersiones con variables relacionadas.
ggplot(datos, aes(x = factor(Quality.of.Sleep))) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Frecuencia de Quality of Sleep",
x = "Nivel de calidad del sueño", y = "Frecuencia") +
theme_minimal()
Interpretación: permite conocer qué niveles de calidad del sueño predominan en la base.
ggplot(datos, aes(x = Quality.of.Sleep)) +
geom_histogram(bins = 8, fill = "skyblue", color = "black") +
labs(title = "Distribución de Quality of Sleep",
x = "Calidad del sueño", y = "Frecuencia") +
theme_minimal()
Interpretación: muestra la forma general de la distribución.
ggplot(datos, aes(y = Quality.of.Sleep)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Quality of Sleep", y = "Calidad del sueño") +
theme_minimal()
Interpretación: resume posición central y variabilidad de la calidad del sueño.
ggplot(datos, aes(x = Gender, y = Quality.of.Sleep, fill = Gender)) +
geom_boxplot() +
labs(title = "Quality of Sleep por Gender",
x = "Género", y = "Calidad del sueño") +
theme_minimal()
Interpretación: permite evaluar si la calidad del sueño cambia entre géneros.
ggplot(datos, aes(x = Sleep.Duration, y = Quality.of.Sleep)) +
geom_point(color = "darkblue") +
labs(title = "Sleep Duration vs Quality of Sleep",
x = "Horas de sueño", y = "Calidad del sueño") +
theme_minimal()
Interpretación: se espera una asociación positiva, de modo que una mayor duración del sueño tienda a relacionarse con mejor calidad percibida.
La variable Physical Activity Level es cuantitativa
discreta. Se recomienda representar su distribución y sus relaciones con
pasos diarios y sueño.
ggplot(datos, aes(x = Physical.Activity.Level)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Physical Activity Level",
x = "Nivel de actividad física", y = "Frecuencia") +
theme_minimal()
Interpretación: describe cómo se distribuyen los niveles de actividad física en la muestra.
ggplot(datos, aes(x = factor(Physical.Activity.Level))) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Frecuencia de Physical Activity Level",
x = "Nivel de actividad física", y = "Frecuencia") +
theme_minimal()
Interpretación: es útil cuando se desea tratar la variable como discreta con pocos niveles observados.
ggplot(datos, aes(y = Physical.Activity.Level)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Physical Activity Level",
y = "Nivel de actividad física") +
theme_minimal()
Interpretación: resume mediana, dispersión y posibles valores extremos.
ggplot(datos, aes(x = Gender, y = Physical.Activity.Level, fill = Gender)) +
geom_boxplot() +
labs(title = "Physical Activity Level por Gender",
x = "Género", y = "Nivel de actividad física") +
theme_minimal()
Interpretación: compara la actividad física entre géneros.
ggplot(datos, aes(x = Physical.Activity.Level, y = Daily.Steps)) +
geom_point(color = "blue") +
labs(title = "Physical Activity Level vs Daily Steps",
x = "Nivel de actividad física", y = "Pasos diarios") +
theme_minimal()
Interpretación: se espera una relación positiva entre el nivel de actividad física y los pasos diarios.
La variable Stress Level es cuantitativa discreta con
interpretación ordinal. Se recomienda combinar barras, histograma,
boxplot y dispersiones.
ggplot(datos, aes(x = factor(Stress.Level))) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Frecuencia de Stress Level",
x = "Nivel de estrés", y = "Frecuencia") +
theme_minimal()
Interpretación: permite identificar cuáles niveles de estrés se presentan con mayor frecuencia.
ggplot(datos, aes(x = Stress.Level)) +
geom_histogram(bins = 8, fill = "skyblue", color = "black") +
labs(title = "Distribución de Stress Level",
x = "Nivel de estrés", y = "Frecuencia") +
theme_minimal()
Interpretación: resume la forma general de la distribución.
ggplot(datos, aes(y = Stress.Level)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Stress Level", y = "Nivel de estrés") +
theme_minimal()
Interpretación: sintetiza variabilidad y valores atípicos.
ggplot(datos, aes(x = Gender, y = Stress.Level, fill = Gender)) +
geom_boxplot() +
labs(title = "Stress Level por Gender",
x = "Género", y = "Nivel de estrés") +
theme_minimal()
Interpretación: permite identificar si el estrés tiende a diferir según género.
ggplot(datos, aes(x = Sleep.Duration, y = Stress.Level)) +
geom_point(color = "red") +
labs(title = "Sleep Duration vs Stress Level",
x = "Horas de sueño", y = "Nivel de estrés") +
theme_minimal()
Interpretación: se espera una tendencia inversa, donde menor tiempo de sueño se asocie con mayor estrés.
La variable BMI Category es categórica nominal. Se
recomienda trabajar con barras, pastel, barras apiladas y gráficos de
asociación.
ggplot(datos, aes(x = BMI.Category)) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Frecuencia de BMI Category",
x = "Categoría BMI", y = "Frecuencia") +
theme_minimal()
Interpretación: permite identificar la categoría corporal predominante en la muestra.
tabla_bmi <- preparar_pastel(datos$BMI.Category)
ggplot(tabla_bmi, aes(x = "", y = Proporcion, fill = Categoria)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") +
geom_text(aes(label = Etiqueta),
position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Proporción de BMI Category", fill = "BMI") +
theme_void()
Interpretación: resume la distribución relativa de las categorías de IMC y presenta el porcentaje directamente en cada sector.
ggplot(datos, aes(x = BMI.Category, fill = Gender)) +
geom_bar(position = "fill") +
labs(title = "Proporción de Gender por BMI Category",
x = "Categoría BMI", y = "Proporción", fill = "Género") +
theme_minimal()
Interpretación: facilita la comparación proporcional de la composición por género dentro de cada categoría corporal.
ggplot(datos, aes(x = BMI.Category, fill = Sleep.Disorder)) +
geom_bar(position = "fill") +
labs(title = "Proporción de Sleep Disorder por BMI Category",
x = "Categoría BMI", y = "Proporción", fill = "Sleep Disorder") +
theme_minimal()
Interpretación: permite explorar la composición proporcional de trastornos del sueño dentro de cada categoría corporal.
La variable original Blood Pressure es una cadena de
texto y por ello no debe analizarse directamente como cuantitativa. Las
visualizaciones recomendadas se realizan sobre las variables derivadas
Systolic y Diastolic.
ggplot(datos, aes(x = Systolic)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Systolic",
x = "Presión sistólica", y = "Frecuencia") +
theme_minimal()
Interpretación: describe la distribución de la presión arterial sistólica.
ggplot(datos, aes(x = Diastolic)) +
geom_histogram(bins = 10, fill = "orange", color = "black") +
labs(title = "Distribución de Diastolic",
x = "Presión diastólica", y = "Frecuencia") +
theme_minimal()
Interpretación: describe la distribución de la presión arterial diastólica.
ggplot(datos, aes(x = Systolic, y = Diastolic)) +
geom_point(color = "blue") +
labs(title = "Relación entre Systolic y Diastolic",
x = "Presión sistólica", y = "Presión diastólica") +
theme_minimal()
Interpretación: permite examinar la relación fisiológica entre ambas medidas de presión arterial.
ggplot(datos, aes(x = Gender, y = Systolic, fill = Gender)) +
geom_boxplot() +
labs(title = "Systolic por Gender",
x = "Género", y = "Presión sistólica") +
theme_minimal()
Interpretación: facilita la comparación de la presión sistólica entre géneros.
La variable Heart Rate es cuantitativa discreta y
resulta apropiada para histogramas, boxplots, densidades y gráficos de
dispersión.
ggplot(datos, aes(x = Heart.Rate)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Heart Rate",
x = "Frecuencia cardíaca", y = "Frecuencia") +
theme_minimal()
Interpretación: muestra la concentración de frecuencias cardíacas observadas.
ggplot(datos, aes(y = Heart.Rate)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Heart Rate", y = "Frecuencia cardíaca") +
theme_minimal()
Interpretación: resume el centro, la dispersión y los posibles valores atípicos.
ggplot(datos, aes(x = Heart.Rate)) +
geom_density(fill = "orange", alpha = 0.4) +
labs(title = "Densidad de Heart Rate",
x = "Frecuencia cardíaca", y = "Densidad") +
theme_minimal()
Interpretación: permite examinar la forma de la distribución.
ggplot(datos, aes(x = Stress.Level, y = Heart.Rate)) +
geom_point(color = "red") +
labs(title = "Stress Level vs Heart Rate",
x = "Nivel de estrés", y = "Frecuencia cardíaca") +
theme_minimal()
Interpretación: ayuda a evaluar la posible asociación positiva entre estrés y frecuencia cardíaca.
La variable Daily Steps es cuantitativa discreta y
representa un indicador de actividad cotidiana.
ggplot(datos, aes(x = Daily.Steps)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución de Daily Steps",
x = "Pasos diarios", y = "Frecuencia") +
theme_minimal()
Interpretación: permite identificar el rango habitual de pasos realizados por los participantes.
ggplot(datos, aes(y = Daily.Steps)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot de Daily Steps", y = "Pasos diarios") +
theme_minimal()
Interpretación: resume la dispersión y la presencia de individuos particularmente activos o sedentarios.
ggplot(datos, aes(x = Daily.Steps)) +
geom_density(fill = "orange", alpha = 0.4) +
labs(title = "Densidad de Daily Steps",
x = "Pasos diarios", y = "Densidad") +
theme_minimal()
Interpretación: facilita la lectura de la forma de la distribución.
ggplot(datos, aes(x = Physical.Activity.Level, y = Daily.Steps)) +
geom_point(color = "blue") +
labs(title = "Physical Activity Level vs Daily Steps",
x = "Nivel de actividad física", y = "Pasos diarios") +
theme_minimal()
Interpretación: se espera una relación positiva entre ambas variables, dado que ambas miden actividad física desde perspectivas complementarias.
La variable Sleep Disorder es categórica nominal. Sus
representaciones más útiles son barras, pastel y análisis cruzados con
otras variables categóricas.
ggplot(datos, aes(x = Sleep.Disorder)) +
geom_bar(fill = "steelblue", color = "black") +
labs(title = "Frecuencia de Sleep Disorder",
x = "Trastorno del sueño", y = "Frecuencia") +
theme_minimal()
Interpretación: permite establecer la frecuencia de ausencia de trastorno, insomnio y apnea del sueño.
tabla_sd <- preparar_pastel(datos$Sleep.Disorder)
ggplot(tabla_sd, aes(x = "", y = Proporcion, fill = Categoria)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") +
geom_text(aes(label = Etiqueta),
position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Proporción de Sleep Disorder", fill = "Sleep Disorder") +
theme_void()
Interpretación: resume la participación relativa de cada categoría de trastorno del sueño e incluye el porcentaje en cada sector.
ggplot(datos, aes(x = Gender, fill = Sleep.Disorder)) +
geom_bar(position = "fill") +
labs(title = "Proporción de Sleep Disorder por Gender",
x = "Género", y = "Proporción", fill = "Sleep Disorder") +
theme_minimal()
Interpretación: permite explorar cómo varía la composición proporcional de trastornos del sueño entre hombres y mujeres.
ggplot(datos, aes(x = BMI.Category, fill = Sleep.Disorder)) +
geom_bar(position = "fill") +
labs(title = "Proporción de Sleep Disorder por BMI Category",
x = "Categoría BMI", y = "Proporción", fill = "Sleep Disorder") +
theme_minimal()
Interpretación: ayuda a estudiar la composición proporcional de trastornos del sueño según condición corporal.
La evaluación de normalidad se realiza sobre las variables cuantitativas que, por su naturaleza, podrían ser consideradas en técnicas paramétricas. Debe tenerse presente que la prueba de Shapiro-Wilk es sensible al tamaño muestral; por ello se complementa con la inspección visual del gráfico QQ.
Las variables consideradas en esta sección son: Age,
Sleep Duration, Quality of Sleep,
Physical Activity Level, Stress Level,
Heart Rate, Daily Steps, Systolic
y Diastolic. La variable Person ID no se
evalúa por su carácter identificador y las variables categóricas quedan
excluidas.
variables_normalidad <- c(
"Age", "Sleep.Duration", "Quality.of.Sleep", "Physical.Activity.Level",
"Stress.Level", "Heart.Rate", "Daily.Steps", "Systolic", "Diastolic"
)
resultados_shapiro <- data.frame(
Variable = character(),
W = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE
)
for (v in variables_normalidad) {
prueba <- shapiro.test(datos[[v]])
resultados_shapiro <- rbind(
resultados_shapiro,
data.frame(Variable = v, W = as.numeric(prueba$statistic), p_value = prueba$p.value)
)
}
resultados_shapiro
## Variable W p_value
## 1 Age 0.9580017 7.416837e-09
## 2 Sleep.Duration 0.9357678 1.267828e-11
## 3 Quality.of.Sleep 0.8938632 1.881529e-15
## 4 Physical.Activity.Level 0.8994274 5.176356e-15
## 5 Stress.Level 0.8908905 1.112608e-15
## 6 Heart.Rate 0.8825502 2.684952e-16
## 7 Daily.Steps 0.9368167 1.653179e-11
## 8 Systolic 0.9246805 9.010577e-13
## 9 Diastolic 0.8940533 1.946526e-15
Interpretación general: si el valor-p es menor que 0.05, se rechaza la hipótesis de normalidad. Sin embargo, esta conclusión debe complementarse con la inspección del gráfico QQ y con el contexto del modelado posterior.
par(mfrow = c(3, 3))
for (v in variables_normalidad) {
qqnorm(datos[[v]], main = paste("QQ Plot -", v))
qqline(datos[[v]], col = 2, lwd = 2)
}
par(mfrow = c(1, 1))
Interpretación general: cuando los puntos siguen aproximadamente la línea de referencia, la distribución se aproxima a la normalidad. Desviaciones sistemáticas en los extremos o curvaturas marcadas sugieren asimetría, colas pesadas o ausencia de normalidad.
En esta base, varias variables son discretas u ordinales, por lo que la normalidad perfecta no necesariamente debe esperarse. No obstante, la evaluación sigue siendo útil para decidir entre enfoques paramétricos y no paramétricos, así como para revisar supuestos de residuos en modelos de regresión.
En esta sección se proponen modelos coherentes con la estructura de
la base de datos. Se excluye Person ID del modelado por su
función de identificador.
Se propone un modelo de regresión lineal múltiple donde la variable
respuesta es Quality of Sleep. Esta elección es razonable
porque dicha variable resume el resultado principal de interés y puede
explicarse a partir de duración del sueño, estrés, actividad física,
frecuencia cardíaca, edad, género y categoría BMI.
modelo_quality <- lm(
Quality.of.Sleep ~ Sleep.Duration + Stress.Level + Physical.Activity.Level +
Heart.Rate + Daily.Steps + Age + Gender + BMI.Category,
data = datos
)
summary(modelo_quality)
##
## Call:
## lm(formula = Quality.of.Sleep ~ Sleep.Duration + Stress.Level +
## Physical.Activity.Level + Heart.Rate + Daily.Steps + Age +
## Gender + BMI.Category, data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.02977 -0.15531 -0.05828 0.18686 1.02552
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.1431902 0.6401619 9.596 < 2e-16 ***
## Sleep.Duration 0.1714409 0.0480921 3.565 0.000413 ***
## Stress.Level -0.4326496 0.0267523 -16.172 < 2e-16 ***
## Physical.Activity.Level 0.0027118 0.0017153 1.581 0.114755
## Heart.Rate -0.0028352 0.0093115 -0.304 0.760935
## Daily.Steps 0.0000547 0.0000220 2.486 0.013352 *
## Age 0.0510263 0.0032827 15.544 < 2e-16 ***
## GenderMale 0.2342816 0.0463897 5.050 6.99e-07 ***
## BMI.CategoryObese -0.7135524 0.1618490 -4.409 1.37e-05 ***
## BMI.CategoryOverweight -0.7820835 0.0555258 -14.085 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2907 on 364 degrees of freedom
## Multiple R-squared: 0.9424, Adjusted R-squared: 0.941
## F-statistic: 662.2 on 9 and 364 DF, p-value: < 2.2e-16
Interpretación sugerida: los coeficientes indican el cambio esperado
en la calidad del sueño ante una variación unitaria en cada predictor,
manteniendo constantes las demás variables. Resultan especialmente
relevantes los signos y significancia de Sleep.Duration,
Stress.Level y Physical.Activity.Level.
par(mfrow = c(2, 2))
plot(modelo_quality)
par(mfrow = c(1, 1))
Interpretación: estos gráficos permiten evaluar linealidad, homocedasticidad, normalidad aproximada de residuos y observaciones influyentes.
En este segundo modelo, Heart Rate se toma como variable
respuesta por su importancia fisiológica. Se propone explicarla mediante
estrés, duración del sueño, actividad física, edad, presión sistólica y
categoría BMI.
modelo_hr <- lm(
Heart.Rate ~ Stress.Level + Sleep.Duration + Physical.Activity.Level +
Age + Systolic + BMI.Category,
data = datos
)
summary(modelo_hr)
##
## Call:
## lm(formula = Heart.Rate ~ Stress.Level + Sleep.Duration + Physical.Activity.Level +
## Age + Systolic + BMI.Category, data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.4840 -0.6615 -0.0760 0.5357 9.2881
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 57.718346 3.348700 17.236 < 2e-16 ***
## Stress.Level 1.735190 0.103300 16.798 < 2e-16 ***
## Sleep.Duration 0.742469 0.272882 2.721 0.00682 **
## Physical.Activity.Level 0.030933 0.005326 5.808 1.37e-08 ***
## Age -0.003867 0.021274 -0.182 0.85585
## Systolic -0.038667 0.023556 -1.641 0.10156
## BMI.CategoryObese 15.351578 0.706272 21.736 < 2e-16 ***
## BMI.CategoryOverweight 1.771813 0.362337 4.890 1.51e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.871 on 366 degrees of freedom
## Multiple R-squared: 0.7991, Adjusted R-squared: 0.7953
## F-statistic: 208 on 7 and 366 DF, p-value: < 2.2e-16
Interpretación sugerida: este modelo permite establecer cuáles variables se asocian con incrementos o reducciones en la frecuencia cardíaca.
par(mfrow = c(2, 2))
plot(modelo_hr)
par(mfrow = c(1, 1))
Interpretación: la validez del modelo depende en buena medida de que los residuos no presenten patrones sistemáticos severos.
Dado que Sleep Disorder es categórica con múltiples
clases, se construye una variable binaria auxiliar denominada
Sleep.Disorder.Binary, donde 0 representa ausencia de
trastorno y 1 representa presencia de algún trastorno del sueño. Esto
permite emplear una regresión logística binaria.
datos$Sleep.Disorder.Binary.Num <- ifelse(datos$Sleep.Disorder == "No Disorder", 0, 1)
modelo_logistico <- glm(
Sleep.Disorder.Binary.Num ~ Age + Gender + Sleep.Duration + Stress.Level +
Quality.of.Sleep + BMI.Category + Heart.Rate + Systolic,
data = datos,
family = binomial
)
summary(modelo_logistico)
##
## Call:
## glm(formula = Sleep.Disorder.Binary.Num ~ Age + Gender + Sleep.Duration +
## Stress.Level + Quality.of.Sleep + BMI.Category + Heart.Rate +
## Systolic, family = binomial, data = datos)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.657e+01 8.231e+05 0 1
## Age -1.025e-07 5.715e+03 0 1
## GenderMale -2.555e-07 5.887e+04 0 1
## Sleep.Duration 1.697e-06 5.912e+04 0 1
## Stress.Level -6.353e-08 3.853e+04 0 1
## Quality.of.Sleep 6.550e-07 5.895e+04 0 1
## BMI.CategoryObese -4.202e-06 2.076e+05 0 1
## BMI.CategoryOverweight -1.505e-06 8.451e+04 0 1
## Heart.Rate 9.207e-08 9.986e+03 0 1
## Systolic 7.855e-08 4.444e+03 0 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 0.0000e+00 on 373 degrees of freedom
## Residual deviance: 2.1698e-09 on 364 degrees of freedom
## AIC: 20
##
## Number of Fisher Scoring iterations: 25
Interpretación sugerida: los coeficientes positivos aumentan el logaritmo de la razón de probabilidades de presentar trastorno del sueño, mientras que los coeficientes negativos lo reducen.
exp(coef(modelo_logistico))
## (Intercept) Age GenderMale
## 3.447339e+11 9.999999e-01 9.999997e-01
## Sleep.Duration Stress.Level Quality.of.Sleep
## 1.000002e+00 9.999999e-01 1.000001e+00
## BMI.CategoryObese BMI.CategoryOverweight Heart.Rate
## 9.999958e-01 9.999985e-01 1.000000e+00
## Systolic
## 1.000000e+00
Interpretación: los valores mayores que 1 indican aumento en la razón de probabilidades, mientras que los menores que 1 sugieren un efecto protector o reductor sobre la probabilidad de presentar trastorno del sueño.
Antes del modelado es conveniente revisar las relaciones lineales entre variables cuantitativas.
vars_cor <- datos[, c(
"Age", "Sleep.Duration", "Quality.of.Sleep", "Physical.Activity.Level",
"Stress.Level", "Heart.Rate", "Daily.Steps", "Systolic", "Diastolic"
)]
mat_cor <- cor(vars_cor, use = "complete.obs")
mat_cor
## Age Sleep.Duration Quality.of.Sleep
## Age 1.0000000 0.34470936 0.47373388
## Sleep.Duration 0.3447094 1.00000000 0.88321300
## Quality.of.Sleep 0.4737339 0.88321300 1.00000000
## Physical.Activity.Level 0.1789927 0.21236031 0.19289645
## Stress.Level -0.4223445 -0.81102303 -0.89875203
## Heart.Rate -0.2256062 -0.51645489 -0.65986473
## Daily.Steps 0.0579734 -0.03953254 0.01679141
## Systolic 0.6058784 -0.18040628 -0.12163200
## Diastolic 0.5938389 -0.16656987 -0.11015093
## Physical.Activity.Level Stress.Level Heart.Rate
## Age 0.17899272 -0.42234448 -0.22560619
## Sleep.Duration 0.21236031 -0.81102303 -0.51645489
## Quality.of.Sleep 0.19289645 -0.89875203 -0.65986473
## Physical.Activity.Level 1.00000000 -0.03413446 0.13697098
## Stress.Level -0.03413446 1.00000000 0.67002646
## Heart.Rate 0.13697098 0.67002646 1.00000000
## Daily.Steps 0.77272305 0.18682895 -0.03030858
## Systolic 0.26541597 0.10281816 0.29414292
## Diastolic 0.38265068 0.09181104 0.27109222
## Daily.Steps Systolic Diastolic
## Age 0.05797340 0.6058784 0.59383892
## Sleep.Duration -0.03953254 -0.1804063 -0.16656987
## Quality.of.Sleep 0.01679141 -0.1216320 -0.11015093
## Physical.Activity.Level 0.77272305 0.2654160 0.38265068
## Stress.Level 0.18682895 0.1028182 0.09181104
## Heart.Rate -0.03030858 0.2941429 0.27109222
## Daily.Steps 1.00000000 0.1033422 0.24198597
## Systolic 0.10334222 1.0000000 0.97288499
## Diastolic 0.24198597 0.9728850 1.00000000
cor_df <- as.data.frame(as.table(mat_cor))
colnames(cor_df) <- c("Var1", "Var2", "Correlacion")
ggplot(cor_df, aes(x = Var1, y = Var2, fill = Correlacion)) +
geom_tile(color = "white") +
labs(title = "Mapa de calor de correlaciones",
x = "", y = "", fill = "Correlación") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Interpretación: este mapa permite identificar asociaciones lineales altas que pueden ser relevantes para la interpretación o para la detección de colinealidad entre predictores.
La revisión de variables evidencia que la base combina variables identificadoras, categóricas, cuantitativas y una variable compuesta que requiere transformación previa. Las visualizaciones recomendadas permiten estudiar adecuadamente la distribución, la dispersión y las asociaciones bivariadas según la naturaleza de cada variable. La sección de normalidad constituye un insumo para decidir la conveniencia de ciertos métodos paramétricos y para evaluar supuestos en los modelos. Finalmente, la sección de modelado muestra rutas analíticas coherentes: una regresión lineal para explicar la calidad del sueño, otra para la frecuencia cardíaca y una regresión logística para analizar la presencia de trastornos del sueño.
Desde una perspectiva aplicada, las variables más relevantes de la
base son Sleep Duration, Quality of Sleep,
Stress Level, Heart Rate,
BMI Category y las medidas de presión arterial. Estas
variables articulan de forma consistente el análisis descriptivo, la
evaluación de supuestos y el modelado estadístico.