age
: Edad del individuo en años.height_cm
: Altura en centímetros.weight_kg
: Peso en kilogramos.heart_rate
: Frecuencia cardíaca en reposo en latidos
por minuto.blood_pressure
: Presión arterial sistólica en
mmHg.sleep_hours
: Promedio de horas de sueño al día.nutrition_quality
: Puntuación de calidad nutricional
diaria entre 0 y 10.activity_index
: Puntuación del nivel de actividad
física entre 1 y 5.smokes
: ¿fuma?gender
: Género del individuo.is_fit
: Variable objetivo (la persona está en forma o
no).Se importan las librerías esenciales para facilitar el análisis que abarca la carga de datos, la evaluación estadística, la visualización, la transformación de datos, la fusión y la unión.
## Cargando paquete requerido: dplyr
## Warning: package 'dplyr' was built under R version 4.4.3
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Cargando paquete requerido: tibble
## Cargando paquete requerido: stringr
## Warning: package 'stringr' was built under R version 4.4.3
## Cargando paquete requerido: ggplot2
## Warning: package 'ggplot2' was built under R version 4.4.3
## Cargando paquete requerido: ggpubr
## Warning: package 'ggpubr' was built under R version 4.4.3
## Cargando paquete requerido: e1071
## Warning: package 'e1071' was built under R version 4.4.3
## Cargando paquete requerido: psych
## Warning: package 'psych' was built under R version 4.4.3
##
## Adjuntando el paquete: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
## Warning: package 'reshape2' was built under R version 4.4.1
## Warning: package 'Hmisc' was built under R version 4.4.3
##
## Adjuntando el paquete: 'Hmisc'
## The following object is masked from 'package:psych':
##
## describe
## The following object is masked from 'package:e1071':
##
## impute
## The following objects are masked from 'package:dplyr':
##
## src, summarize
## The following objects are masked from 'package:base':
##
## format.pval, units
## Warning: package 'Amelia' was built under R version 4.4.3
## Cargando paquete requerido: Rcpp
## ##
## ## Amelia II: Multiple Imputation
## ## (Version 1.8.3, built: 2024-11-07)
## ## Copyright (C) 2005-2025 James Honaker, Gary King and Matthew Blackwell
## ## Refer to http://gking.harvard.edu/amelia/ for more information
## ##
df = read.csv("C:/Users/johan/Downloads/data_eda/fitness_dataset.csv", sep=",", header=TRUE, fileEncoding = "UTF-8")
Se muestran las 5 primeras filas del DataFrame.
## age height_cm weight_kg heart_rate blood_pressure sleep_hours
## 1 56 152 65 69.6 117.0 NA
## 2 69 186 95 60.8 114.8 7.5
## 3 46 192 103 61.4 116.4 NA
## 4 32 189 83 60.2 130.1 7.0
## 5 60 175 99 58.1 115.8 8.0
## 6 25 172 85 81.2 119.2 7.7
## nutrition_quality activity_index smokes gender is_fit
## 1 2.37 3.97 no F 1
## 2 8.77 3.19 0 F 1
## 3 8.20 2.03 0 F 0
## 4 6.18 3.68 0 M 1
## 5 9.95 4.83 yes F 1
## 6 7.35 4.08 yes M 0
Se muestran las 5 últimas filas del DataFrame.
## age height_cm weight_kg heart_rate blood_pressure sleep_hours
## 1995 41 158 113 79.6 104.8 11.5
## 1996 52 173 98 60.7 106.1 NA
## 1997 61 186 74 51.4 123.8 9.4
## 1998 77 198 89 76.7 103.6 8.3
## 1999 62 190 63 80.7 115.9 6.7
## 2000 51 166 78 89.3 101.8 8.3
## nutrition_quality activity_index smokes gender is_fit
## 1995 3.96 1.85 yes M 0
## 1996 1.54 3.25 1 M 1
## 1997 8.63 3.15 no M 1
## 1998 1.98 3.36 yes M 0
## 1999 9.21 2.39 1 F 0
## 2000 4.42 1.02 1 M 0
Se presenta un resumen detallado de todas las variables del dataset, incluyendo el tipo de dato (entero, punto flotante o carácter) lo que permite evaluar la integridad y estructura de los datos para su posterior procesamiento.
## Rows: 2,000
## Columns: 11
## $ age <int> 56, 69, 46, 32, 60, 25, 78, 38, 56, 75, 36, 40, 28, …
## $ height_cm <int> 152, 186, 192, 189, 175, 172, 193, 188, 164, 198, 15…
## $ weight_kg <int> 65, 95, 103, 83, 99, 85, 83, 57, 108, 55, 63, 55, 90…
## $ heart_rate <dbl> 69.6, 60.8, 61.4, 60.2, 58.1, 81.2, 79.6, 81.2, 70.1…
## $ blood_pressure <dbl> 117.0, 114.8, 116.4, 130.1, 115.8, 119.2, 132.5, 110…
## $ sleep_hours <dbl> NA, 7.5, NA, 7.0, 8.0, 7.7, 7.4, 6.6, 9.1, 8.1, 5.9,…
## $ nutrition_quality <dbl> 2.37, 8.77, 8.20, 6.18, 9.95, 7.35, 2.16, 8.47, 4.15…
## $ activity_index <dbl> 3.97, 3.19, 2.03, 3.68, 4.83, 4.08, 3.42, 4.96, 2.06…
## $ smokes <chr> "no", "0", "0", "0", "yes", "yes", "yes", "0", "no",…
## $ gender <chr> "F", "F", "F", "M", "F", "M", "F", "M", "F", "F", "M…
## $ is_fit <int> 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0…
Interpretación del Dataset:
El dataset presentado contiene 2,000 observaciones y 11 variables, que incluyen una combinación de tipos de datos numéricos (enteros y de punto flotante) y de tipo carácter.
Las variables numéricas abarcan características como edad
(age
), altura (height_cm
), peso
(weight_kg
), frecuencia cardíaca (heart_rate
),
presión arterial (blood_pressure
), horas de sueño
(sleep_hours
), calidad de nutrición
(nutrition_quality
) e índice de actividad
(activity_index
), donde algunas presentan valores faltantes
(NA) en sleep_hours
.
Las variables cualitativas sonsmokes
(hábito de
fumar) y gender (género
), mientras que la variable objetivo
is_fit
(indicador binario de condición física) está
codificada como entero.
La estructura sugiere que el dataset está diseñado para analizar
relaciones entre factores de salud y estilo de vida, aunque se observan
inconsistencias en smokes
(valores posiblemente erróneos),
lo que podría requerir limpieza previa al análisis.
Se calcula el número de valores faltantes para cada variable del DataFrame.
## age height_cm weight_kg heart_rate
## 0 0 0 0
## blood_pressure sleep_hours nutrition_quality activity_index
## 0 160 0 0
## smokes gender is_fit
## 0 0 0
Interpretación de los Valores Faltantes:
El análisis de valores faltantes en el dataset revela que la variable
sleep_hours
presenta 160 NA (8% del total de observaciones
de esa columna), lo que indica una proporción significativa de datos
ausentes que podría afectar los análisis relacionados con patrones de
sueño.
El resto de las variables, incluyendo indicadores de salud como
presión arterial (blood_pressure
), calidad nutricional
(nutrition_quality
), y variables demográficas como género
(gender
), no contienen valores faltantes.
Esta estructura sugiere que el dataset está mayormente completo, excepto por la variable de sueño, lo que podría requerir estrategias como imputación o exclusión controlada para evitar sesgos en estudios posteriores.
Se calcula el número de valores únicos para cada variable del DataFrame.
## age height_cm weight_kg heart_rate
## 62 50 80 484
## blood_pressure sleep_hours nutrition_quality activity_index
## 563 80 866 398
## smokes gender is_fit
## 4 2 2
Interpretación de los Valores únicos:
Variables continuas: heart_rate
(484 únicos),
blood_pressure
(563), nutrition_quality
(866)
y activity_index
(398) presentan alta granularidad, lo que
sugiere mediciones precisas o decimales. sleep_hours
(80
únicos) también refleja variabilidad, aunque con menos detalle.
Variables discretas: age
(62 únicos),
height_cm
(50) y weight_kg
(80) indican rangos
demográficos y físicos esperados en una muestra de 2,000
observaciones.
Variables categóricas: smokes
tiene 4 categorías
(posiblemente incluyendo errores), gender
y
is_fit
son binarias (2 únicos cada una), lo que confirma su
naturaleza dicotómica.
Esta estructura resalta la adecuación del dataset para análisis
estadísticos, aunque es necesario revisar las categorías de
smokes
para corregir inconsistencias. La alta cardinalidad
en variables continuas sugiere riqueza de datos para modelado
predictivo.
La variable smokes
tiene 4 valores únicos, lo cual es
inesperado, ya que se espera que sea una variable binaria que represente
si una persona fuma o no. Entonces, se identifican los valores
inesperados.
## [1] "no" "0" "yes" "1"
Se estandarizan las variables smokes
e
is_fit
para mejorar la legibilidad y la coherencia de los
datos.
La variable is_fit
se encontraba codificada con los
valores 0 y 1, que se reemplazan por “no” y “yes”, respectivamente, para
hacerla más comprensible.
La variable smokes
contenía cuatro valores únicos:
0, 1, “no” y “yes”. Para consolidar esta información y evitar errores en
el análisis, se unifican todos los valores a dos categorías: 0 se
reemplaza por “no” y 1 por “yes”.
df$smokes = str_replace(df$smokes, "0", "no")
df$smokes = str_replace(df$smokes, "1", "yes")
df$is_fit = str_replace(df$is_fit, "0", "no")
df$is_fit = str_replace(df$is_fit, "1", "yes")
Se transforman las variables tipo carácter a factor
.
El Análisis Univariado es la primera fase del análisis exploratorio de datos. Se enfoca en el estudio individual de cada variable para entender su distribución, características y valores atípicos. Esto permite identificar patrones y la calidad de los datos antes de un análisis más complejo.
Se genera un doble gráfico para cada variable binaria, permitiendo comparar su distribución mediante:
color = (c("orange", "lightblue"))
fig1 = ggplot(data=df, aes(x=smokes)) +
geom_bar(fill = color) +
labs(title = "Frecuencia de smokes", y = "Frecuencia", x = "Categorias") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = ..count..), stat = "count", vjust = 2, colour = "black")
fig2 = ggplot(data=df, aes(x=gender)) +
geom_bar(fill = color) +
labs(title = "Frecuencia de gender", y = "Frecuencia", x = "Categorias") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = ..count..), stat = "count", vjust = 2, colour = "black")
fig3 = ggplot(data=df, aes(x=is_fit)) +
geom_bar(fill = color) +
labs(title = "Frecuencia de is_fit", y = "Frecuencia", x = "Categorias") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = ..count..), stat = "count", vjust = 2, colour = "black")
ggarrange(fig1,fig2, fig3, ncol=3 ,nrow=1)
## Warning: The dot-dot notation (`..count..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(count)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
fig1 = ggplot(data = df, aes(x = "", fill = smokes)) +
geom_bar(width = 1, color = "white") +
coord_polar(theta = "y") +
labs(title = "Distribucion de smokes", x = NULL, y = NULL) + theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = paste0(round(..count.. / sum(..count..) * 100, 1), "%)")),stat = "count", position = position_stack(vjust = 0.5), color = "black") +
scale_fill_manual(values = color)
fig2 = ggplot(data = df, aes(x = "", fill = gender)) +
geom_bar(width = 1, color = "white") +
coord_polar(theta = "y") +
labs(title = "Distribucion de gender", x = NULL, y = NULL) + theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = paste0(round(..count.. / sum(..count..) * 100, 1), "%)")),stat = "count", position = position_stack(vjust = 0.5), color = "black") +
scale_fill_manual(values = color)
fig3 = ggplot(data = df, aes(x = "", fill = is_fit)) +
geom_bar(width = 1, color = "white") +
coord_polar(theta = "y") +
labs(title = "Distribucion de is_fit", x = NULL, y = NULL) + theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = paste0(round(..count.. / sum(..count..) * 100, 1), "%)")),stat = "count", position = position_stack(vjust = 0.5), color = "black") +
scale_fill_manual(values = color)
ggarrange(fig1, fig2, fig3, ncol=3, nrow=1)
Interpretación de las Variables Binarias:
En cuanto al hábito de fumar, se observa que el 54.9% de las personas no fuma, frente al 45.1% que sí lo hace, con una diferencia moderada entre ambos grupos (1,099 vs. 901 individuos).
En la variable género, la distribución es bastante equilibrada, con un 51.5% de mujeres y un 48.5% de hombres (1,030 vs. 970 personas).
Por último, en cuanto a la condición física, un 60.1% de los participantes no se considera en forma, mientras que el 40% sí lo está (1,201 vs. 799 personas), evidenciando una mayor diferencia entre categorías respecto a las otras variables.
En conjunto, estos resultados permiten apreciar que las proporciones
se mantienen cercanas al equilibrio en smokes
y
gender
, pero en is_fit
predomina claramente la
categoría “no”.
Se visualiza algunos estadísticos descriptivos para las variables númericas discretas.
## age height_cm weight_kg
## Min. :18.00 Min. :150.0 Min. : 30.00
## 1st Qu.:34.00 1st Qu.:162.0 1st Qu.: 64.00
## Median :49.00 Median :174.0 Median : 83.00
## Mean :49.11 Mean :174.5 Mean : 83.54
## 3rd Qu.:65.00 3rd Qu.:187.0 3rd Qu.:102.00
## Max. :79.00 Max. :199.0 Max. :250.00
Interpretación de las Variables Númericas Discretas:
En cuanto a age
, la edad de los participantes oscila
entre 18 y 79 años, con la mayoría concentrada entre 34 y 65
años.
La estatura (height_cm
) varía entre 150 y 199 cm,
siendo más común observar valores en el rango de 162 a 187 cm.
Finalmente, el peso (weight_kg
) presenta un rango
amplio de 30 a 250 kg, con mayor concentración entre 64 y 102
kg.
Estos resultados ofrecen una visión general del rango y concentración de cada variable.
Se genera un histograma para visualizar la distribución de frecuencias y la dispersión de los datos. Además se evalua:
Asimetría:
skew = 0
: Distribución simétrica (valores aceptables
skew \(\in (-1,1)\)).skew > 0
: Mayor peso en la cola izquierda de la
distribución (sesgo positivo).skew < 0
: Mayor peso en la cola derecha de la
distribución (sesgo negativo).Kurtosis: Determina si una distribución tiene colas gruesas con respecto a la distribución normal. Proporciona información sobre la forma de una distribución de frecuencias.
kurtosis = 3
: se denomina mesocúrtica (distribución
normal).kurtosis < 3
: se denomina platicúrtica (distribución
con colas menos gruesas que la normal).kurtosis > 3
: se denomina leptocúrtica (distribución
con colas más gruesas que la normal) y significa que trata de producir
más valores atípicos que la distribución normal.for (i in 1:3) {
nombre_col = names(df)[i]
a = kurtosis(df[[nombre_col]])
b = skew(df[[nombre_col]])
print(paste("Kurtosis:", round(a, 2)))
print(paste("Skew:", round(b, 2)))
fig1 = ggplot(data = df, aes(x = .data[[nombre_col]])) +
geom_bar(fill = "lightblue", color = "white") +
labs(title = paste("Frecuencias de", nombre_col), x = "Categorias", y = "Frecuencias")+ theme_bw() + theme(plot.title = element_text(hjust = 0.5))
print(fig1)
}
## [1] "Kurtosis: -1.17"
## [1] "Skew: -0.04"
## [1] "Kurtosis: -1.19"
## [1] "Skew: 0.01"
## [1] "Kurtosis: 6.72"
## [1] "Skew: 1.43"
Interpretación de las Variables Númericas Discretas:
El análisis de las distribuciones para age
,
height_cm
y weight_kg
muestra comportamientos
diferenciados.
En el caso de age
, la distribución es relativamente
uniforme a lo largo del rango de edades, con un sesgo cercano a cero
(-0.0378) y una curtosis negativa (-1.1698) que indica colas más ligeras
que las de una distribución normal.
Para height_cm
, también se observa una distribución
homogénea con un sesgo prácticamente nulo (0.0103) y una curtosis
negativa (-1.1921), lo que sugiere una menor concentración en los
extremos y mayor dispersión en torno a la media.
En cambio, weight_kg
presenta un patrón distinto,
con un sesgo positivo (1.4291) que indica una concentración de valores
hacia el extremo inferior y una cola más larga hacia la derecha, lo que
coincide con la presencia de valores atípicos altos; además, su curtosis
positiva elevada (6.7219) revela colas pesadas y una mayor presencia de
valores extremos en comparación con la normalidad.
Estos resultados sugieren que, mientras la edad y la estatura se distribuyen de forma más equilibrada, el peso muestra asimetría y alta concentración en torno a ciertos valores, con casos extremos que podrían influir en análisis posteriores.
Se genera un un boxplot para visualizar la distribución e identificar outliers (puntos fuera de los bigotes) y la dispersión de los datos. Además se evalua:
for (i in 1:3) {
nombre_col = names(df)[i]
media = mean(df[[nombre_col]])
desviacion = sd(df[[nombre_col]])
coef_variacion = (desviacion / media) * 100
print(paste("El coeficiente de variacion es: ", round(coef_variacion, 2), "%"))
fig2 = ggplot(data = df, aes(x = .data[[nombre_col]])) +
geom_boxplot(fill = "orange", color = "black") + labs(title = paste("Dispersion de", nombre_col), x = "Categorias") + theme_bw() + theme(plot.title = element_text(hjust = 0.5))
print(fig2)
}
## [1] "El coeficiente de variacion es: 36.5 %"
## [1] "El coeficiente de variacion es: 8.23 %"
## [1] "El coeficiente de variacion es: 30.95 %"
Interpretación de las Variables Númericas Discretas:
En el caso de la variable age
, con un coeficiente de
variación del 36.5%, se observa una dispersión moderada respecto a su
media, sin presencia aparente de valores atípicos, lo que indica una
distribución relativamente homogénea.
Para height_cm
, el coeficiente de variación es de
8.23%, lo que evidencia una variabilidad baja y una mayor concentración
de los valores en torno al promedio, sin indicios de outliers.
En contraste, weight_kg
presenta un coeficiente de
variación de 30.95%, revelando una dispersión moderada-alta, además de
la presencia de varios valores atípicos hacia el extremo superior, lo
que sugiere la existencia de casos particulares con pesos
significativamente mayores al resto de la población.
Estos patrones de dispersión y variabilidad son relevantes para comprender la homogeneidad y las posibles anomalías dentro de cada variable antes de realizar análisis estadísticos más complejos.
Se visualiza algunos estadísticos descriptivos para las variables númericas continuas.
## heart_rate blood_pressure sleep_hours nutrition_quality
## Min. : 45.00 Min. : 90.0 Min. : 4.000 Min. : 0.000
## 1st Qu.: 62.10 1st Qu.:109.7 1st Qu.: 6.500 1st Qu.: 2.547
## Median : 70.25 Median :120.0 Median : 7.500 Median : 5.065
## Mean : 70.29 Mean :119.9 Mean : 7.513 Mean : 5.035
## 3rd Qu.: 78.42 3rd Qu.:129.8 3rd Qu.: 8.600 3rd Qu.: 7.470
## Max. :118.60 Max. :171.2 Max. :12.000 Max. :10.000
## NA's :160
## activity_index
## Min. :1.000
## 1st Qu.:2.038
## Median :2.980
## Mean :2.999
## 3rd Qu.:3.950
## Max. :4.990
##
Interpretación de las Variables Númericas Continuas:
En cuanto a la frecuencia cardíaca (heart_rate
) se
ubica entre 45 y 118.6 latidos por minuto, siendo más habitual encontrar
valores entre 62.1 y 78.4 lpm.
La presión arterial (blood_pressure
) oscila entre 90
y 171.2 mmHg, concentrándose principalmente entre 109.7 y 129.8
mmHg.
En cuanto a las horas de sueño (sleep_hours
), se
registran entre 4 y 12 horas diarias, con la mayoría de los casos entre
6.5 y 8.6 horas, aunque con 160 valores perdidos.
La calidad de la nutrición (nutrition_quality
) varía
de 0 a 10 puntos, con mayor frecuencia entre 2.547 y 7.470
puntos.
Finalmente, el índice de actividad física
(activity_index
) presenta valores entre 1 y 4.99, siendo
más habitual encontrarlos entre 2.038 y 3.950 puntos.
Estos resultados ofrecen una visión general del rango y concentración de cada variable.
Se genera un histograma para visualizar la distribución de frecuencias y la dispersión de los datos. Además se evalua:
Asimetría:
skew = 0
: Distribución simétrica (valores aceptables
skew \(\in (-1,1)\)).skew > 0
: Mayor peso en la cola izquierda de la
distribución (sesgo positivo).skew < 0
: Mayor peso en la cola derecha de la
distribución (sesgo negativo).Kurtosis: Determina si una distribución tiene colas gruesas con respecto a la distribución normal. Proporciona información sobre la forma de una distribución de frecuencias.
kurtosis = 3
: se denomina mesocúrtica (distribución
normal).kurtosis < 3
: se denomina platicúrtica (distribución
con colas menos gruesas que la normal).kurtosis > 3
: se denomina leptocúrtica (distribución
con colas más gruesas que la normal) y significa que trata de producir
más valores atípicos que la distribución normal.for (i in 4:8) {
nombre_col = names(df)[i]
a = kurtosis(df[[nombre_col]], na.rm = TRUE)
b <- skew(df[[nombre_col]], na.rm = TRUE)
print(paste("Kurtosis:", round(a, 2)))
print(paste("Skew:", round(b, 2)))
fig1 = ggplot(data = df, aes(x = .data[[nombre_col]])) + geom_histogram(fill = "lightblue", bins = 30, color = "white", na.rm = TRUE) + labs(title = paste("Histograma de", nombre_col), x = "Categorias", y = "Frecuencia") + theme_bw() + theme(plot.title = element_text(hjust = 0.5))
print(fig1)
}
## [1] "Kurtosis: -0.13"
## [1] "Skew: 0.15"
## [1] "Kurtosis: -0.27"
## [1] "Skew: 0.1"
## [1] "Kurtosis: -0.21"
## [1] "Skew: -0.02"
## [1] "Kurtosis: -1.2"
## [1] "Skew: 0.01"
## [1] "Kurtosis: -1.16"
## [1] "Skew: 0.04"
Interpretación de las Variables Númericas Continuas:
Los histogramas y las medidas de forma (kurtosis y asimetría) indican que las variables analizadas presentan distribuciones cercanas a la normalidad, aunque con algunas particularidades.
Frecuencia Cardíaca (heart_rate
): La distribución de
la frecuencia cardíaca se asemeja a una campana de Gauss (distribución
normal). Esto se evidencia por la concentración de datos en el centro y
una disminución gradual hacia los extremos. Con un valor de asimetría
(Skew) de 0.15, la distribución está ligeramente sesgada a la derecha,
lo que significa que hay una pequeña “cola” de valores más altos. La
curtosis de -0.13, cercana a cero, indica una curva mesocúrtica (similar
a la normal), lo que sugiere que la forma del pico y las colas no son
inusualmente pronunciadas ni planas.
Presión Arterial (blood_pressure
): Al igual que la
frecuencia cardíaca, esta variable muestra una distribución que se
aproxima a una distribución normal. El coeficiente de asimetría de 0.1
es muy cercano a cero, indicando una distribución casi simétrica. La
curtosis de -0.27 también está cerca de cero, lo que refuerza la idea de
una forma de campana normal (mesocúrtica), sin picos ni colas
particularmente extremos.
Horas de Sueño (sleep_hours
): La distribución de las
horas de sueño es una campana de Gauss bastante clara, con la mayoría de
las personas durmiendo entre 6 y 8 horas. El coeficiente de asimetría de
-0.02 es extremadamente cercano a cero, lo que indica una distribución
prácticamente simétrica. La curtosis de -0.21 también sugiere una
distribución mesocúrtica, similar a la normal.
Índice de Actividad (activity_index
): El histograma
del índice de actividad muestra una distribución más uniforme, sin un
pico central claro. Los datos se distribuyen de manera más equitativa a
lo largo de las categorías. Un coeficiente de asimetría (Skew) de 0.04
está muy cerca de cero, lo que confirma que la distribución es
simétrica. Sin embargo, la curtosis de -1.16 es notablemente negativa,
lo que indica una curva platicúrtica. Esto significa que la distribución
es más “plana” que una distribución normal, con menos datos concentrados
en el centro y colas más ligeras.
Calidad Nutricional (nutrition_quality
): Al igual que el
índice de actividad, esta variable presenta una distribución que se
acerca a una distribución uniforme. El coeficiente de asimetría de 0.01
indica una simetría casi perfecta. La curtosis de -1.2, al ser un valor
negativo y relativamente grande en magnitud, confirma que la
distribución es platicúrtica; esto quiere decir que los datos están
distribuidos de manera más homogénea a lo largo de todo el rango, sin
una alta concentración en un punto específico.
En resumen, las variables de frecuencia cardíaca, presión arterial y horas de sueño siguen una distribución que se aproxima a la normal (con una forma de campana y una simetría alta), lo que sugiere que la mayoría de los individuos se encuentran en un rango promedio. Por otro lado, el índice de actividad y la calidad nutricional tienen distribuciones más planas o uniformes (platicúrticas), indicando una mayor variabilidad y una ausencia de un valor central predominante en la población estudiada.
Se genera un un boxplot para visualizar la distribución e identificar outliers (puntos fuera de los bigotes) y la dispersión de los datos. Además se evalua:
for (i in 4:8) {
nombre_col = names(df)[i]
media = mean(df[[nombre_col]], na.rm = TRUE)
desviacion = sd(df[[nombre_col]], na.rm = TRUE)
coef_variacion = (desviacion / media) * 100
print(paste("El coeficiente de variacion es: ", round(coef_variacion, 2), "%"))
fig2 = ggplot(data = df, aes(x = .data[[nombre_col]])) +
geom_boxplot(fill = "orange", color = "black", na.rm = TRUE) + labs(title = paste("Dispersion de", nombre_col), x = "Categorias") + theme_bw() + theme(plot.title = element_text(hjust = 0.5))
print(fig2)
}
## [1] "El coeficiente de variacion es: 16.85 %"
## [1] "El coeficiente de variacion es: 12.16 %"
## [1] "El coeficiente de variacion es: 19.99 %"
## [1] "El coeficiente de variacion es: 56.88 %"
## [1] "El coeficiente de variacion es: 37.89 %"
Interpretación de las Variables Númericas Continuas:
Presión Arterial (12.16%): Muestra la menor variabilidad. Los datos están muy concentrados, lo que podría indicar una población con niveles de presión arterial bastante estables. Sin embargo, los valores atípicos sugieren que hay individuos con lecturas inusualmente altas.
Frecuencia Cardíaca (16.85%): También presenta una dispersión baja. La mayoría de los datos se encuentran en un rango estrecho, pero al igual que la presión arterial, hay valores atípicos que podrían ser de personas con frecuencias cardíacas más elevadas de lo normal.
Horas de Sueño (19.99%): Presenta una dispersión moderada, lo cual es de esperar ya que los patrones de sueño pueden variar considerablemente entre individuos. El gráfico no muestra atípicos, lo que sugiere que todos los participantes tienen un rango de horas de sueño dentro de una distribución relativamente normal.
Índice de Actividad (37.89%): Tiene una dispersión alta, lo que indica que el nivel de actividad física es muy diverso en la población estudiada, con personas que varían mucho en su nivel de ejercicio.
Calidad Nutricional (56.88%): Es la variable con la mayor dispersión. Este alto coeficiente de variación sugiere una heterogeneidad significativa en los hábitos alimenticios o en la calidad de la nutrición dentro de la muestra, con algunos individuos teniendo una dieta mucho mejor que otros. El gráfico de caja muestra un rango intercuartílico amplio, reflejando esta variabilidad.
El análisis bivariado es la segunda fase del análisis exploratorio de datos. Se enfoca en las relaciones entre dos variables para obtener datos estadísticos sobre sus influencias mutuas.
Se generan graficos de barras para analizar la relación entre el conjunto de variables binarias y la variable estado de forma con el fin de identificar qué variables binarias están asociadas en mayores proporciones.
for (i in 9:10) {
nombre_col <- names(df)[i]
df_summary <- df %>%
group_by(.data[[nombre_col]]) %>%
summarise(
pct_yes = mean(is_fit == "yes") * 100,
.groups = "drop"
)
fig <- ggplot(df_summary, aes(x = .data[[nombre_col]], y = pct_yes, fill = .data[[nombre_col]])) +
geom_bar(stat = "identity", width = 0.8, color = "black") +
scale_fill_manual(values = c("orange", "lightblue")) +
labs(
title = paste(nombre_col, "vs is_fit"), x = "Categorias",
y = "Porcentaje en buen estado de forma (%)",
fill = nombre_col
) +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(
aes(label = sprintf("%.1f%%", pct_yes)),
vjust = 2,
color = "black"
) +
scale_y_continuous(limits = c(0, 100))
print(fig)
}
Interpretación:
Estos gráficos de barras comparan el porcentaje de personas en buen
estado de forma (is_fit
) con dos variables categóricas:
género (gender
) y si fuman (smokes
).
El primer gráfico (smokes
vs is_fit
)
ilustra una correlación significativa entre el hábito de fumar y el
estado de forma. Un impresionante 53.3% de las personas que no fuman
están en buen estado de forma. Por el contrario, este porcentaje cae
drásticamente a solo el 23.6% entre las personas que sí fuman. Esta
diferencia subraya la fuerte asociación negativa entre el tabaquismo y
el estado físico, donde las personas que no fuman tienen más del doble
de probabilidades de estar en buen estado de forma que las que sí lo
hacen.
El segundo gráfico (gender
vs is_fit
)
muestra que el 47.2% de los hombres (M) están en buen estado de forma,
en comparación con solo el 33.1% de las mujeres (F). Esto indica una
diferencia modesta, sugiriendo que, dentro de esta muestra, los hombres
tienen una mayor probabilidad de estar en buen estado de forma física
que las mujeres.
La muestra analizada indica que los hombres están en mejor estado físico que las mujeres y, de manera más contundente, las personas que no fuman tienen un estado de forma significativamente mejor que las personas fumadoras.
Se generan graficos de barras para analizar la relación entre variables númericas discretas y el estado de forma en la población estudiada. Con el fin de identificar qué variables presentan mayores proporciones.
for (i in 1:3) {
nombre_col <- names(df)[i]
min_val <- floor(min(df[[nombre_col]]))
max_val <- ceiling(max(df[[nombre_col]]))
breaks <- seq(min_val, max_val, by = 5)
if (max_val > tail(breaks, 1)) {
breaks <- c(breaks, tail(breaks, 1) + 5)
}
df_summary <- df %>%
mutate(
grupo = cut(
.data[[nombre_col]],
breaks = breaks,
include.lowest = TRUE,
right = FALSE,
labels = paste0(breaks[-length(breaks)], "-", breaks[-1])
)
) %>%
group_by(grupo) %>%
summarise(
pct_yes = mean(is_fit == "yes") * 100,
.groups = "drop"
) %>%
mutate(
centro = sapply(strsplit(as.character(grupo), "-"), function(x) mean(as.numeric(x)))
)
fig <- ggplot(df_summary, aes(x = grupo, y = pct_yes)) +
geom_col(fill = "lightblue", color = "white", width = 0.7) +
geom_line(aes(group = 1), color = "orange", linewidth = 1) +
labs(
title = paste(nombre_col,"vs is_fit"),
x = "Rangos de 5 unidades",
y = "Porcentaje en buen estado de forma(%)"
) +
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 45, hjust = 1)
) +
scale_y_continuous(limits = c(0, 100))
print(fig)
}
Interpretación:
El gráfico age
vs is_fit
muestra una
tendencia descendente en el porcentaje de personas en buen estado de
forma a medida que aumenta la edad. Las personas más jóvenes, en el
rango de 18-23 años, tienen el porcentaje más alto de buen estado de
forma, superando el 60%. Este porcentaje disminuye progresivamente hasta
alcanzar su punto más bajo en los rangos de edad más avanzada, lo que
sugiere que la capacidad física o la dedicación al ejercicio tiende a
disminuir con los años.
El gráfico weight_kg
vs is_fit
ilustra
una relación interesante con el peso. Se observa que el porcentaje de
personas en buen estado de forma aumenta significativamente en los
rangos de peso intermedios, alcanzando su pico entre los 60 y 95 kg. Sin
embargo, en los rangos de peso más bajos (30-40 kg) y más altos (100+
kg), el porcentaje de personas en buen estado de forma disminuye
considerablemente, lo que podría indicar que tanto el bajo peso como el
sobrepeso/obesidad están asociados negativamente con el buen estado
físico.
El gráfico height_cm
vs is_fit
muestra
una tendencia poco pronunciada de aumento en el porcentaje de personas
en buen estado de forma a medida que la altura incrementa. A partir de
los 170 cm, el porcentaje se mantiene relativamente alto y estable,
alcanzando su punto máximo en los rangos de altura de 180-195
cm.
En resumen, el análisis de las variables demográficas y antropométricas revela que el buen estado de forma está más asociado con los individuos más jóvenes, con un peso en el rango intermedio y una altura superior al promedio. Estas tendencias sugieren la importancia de la edad, el peso y la altura como factores predictivos del estado físico en la población estudiada.
Se generan histogramas para analizar la relación entre variables númericas continuas y el estado de forma en la población estudiada. Con el fin de identificar qué variables presentan mayores proporciones.
for (i in 4:8) {
nombre_col <- names(df)[i]
df_filtered <- df %>% filter(!is.na(.data[[nombre_col]]))
fig <- ggplot(df_filtered, aes(x = .data[[nombre_col]], fill = is_fit)) +
geom_histogram(aes(y = after_stat(count)/sum(after_stat(count))*100),
position = "identity", bins = 30, color = "white") +
labs(title = paste(nombre_col, "vs is_fit"),
x = "Categorias", y = "Porcentaje (%)") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5))
print(fig)
}
Interpretación:
Frecuencia Cardíaca (heart_rate
): En el gráfico
heart_rate
vs is_fit
, se observa que el
porcentaje de personas en buen estado de forma (color azul) es
significativamente mayor en el rango de frecuencias cardíacas más bajas,
especialmente entre las categorías de 50 y 80. A medida que la
frecuencia cardíaca aumenta, el porcentaje de personas en buen estado de
forma disminuye, y el porcentaje de personas que no están en forma
(color salmón) se hace dominante. Esto sugiere una fuerte asociación
inversa: una frecuencia cardíaca cercana al promedio está relacionada
con un mejor estado físico.
Presión Arterial (blood_pressure
): El gráfico
blood_pressure
vs is_fit
muestra un patrón
similar. Las personas en buen estado de forma (azul) representan un
porcentaje mayor en los rangos de presión arterial más bajos (alrededor
de 100-120). A partir de la categoría 125, el porcentaje de personas que
no están en buen estado de forma (salmón) comienza a aumentar y se
vuelve dominante en los rangos de presión arterial más altos. Esto
indica que una presión arterial cercana al promedio se asocia
positivamente con un buen estado de forma.
Horas de Sueño (sleep_hours
): En el gráfico
sleep_hours
vs is_fit
, el porcentaje de
personas en buen estado de forma (azul) es más alto en las categorías de
horas de sueño intermedias, especialmente alrededor de 7 a 9 horas. En
los extremos, tanto en rangos de sueño muy bajos (4-5 horas) como en
rangos altos (10-12 horas), el porcentaje de personas que no están en
buen estado de forma (salmón) aumenta. Esto sugiere que dormir una
cantidad adecuada de horas es más propicio para un buen estado físico
que dormir muy poco o en exceso.
Índice de Actividad (activity_index
): El gráfico
activity_index
vs is_fit
muestra una
correlación muy clara. El porcentaje de personas en buen estado de forma
(azul) aumenta drásticamente a medida que el índice de actividad sube,
especialmente a partir de la categoría 3. En las categorías de índice de
actividad más bajas (1 y 2), la gran mayoría de las personas no están en
buen estado de forma. Esto establece una fuerte relación directa: a
mayor índice de actividad, mayor es la probabilidad de estar en buen
estado de forma.
Calidad Nutricional (nutrition_quality
): Por último,
el gráfico nutrition_quality
vs is_fit
revela
una tendencia similar a la del índice de actividad. El porcentaje de
personas en buen estado de forma (azul) incrementa notablemente a medida
que la calidad nutricional mejora (índices más altos). En los rangos más
bajos (0 a 3), el porcentaje de personas en buen estado de forma es
mínimo, mientras que en los rangos más altos (8 a 10) se convierte en la
categoría predominante. Esto demuestra una clara asociación positiva:
una mejor calidad nutricional está fuertemente ligada a un buen estado
físico.
El análisis multivariado nos permite examinar simultáneamente las relaciones entre múltiples variables, revelando patrones complejos que no son evidentes en los análisis univariados o bivariados.
Se genera un heatmap de correlación de Pearson el cual nos permitira visualizar relaciones de dos o mas variables de manera compacta, destacando asociaciones lineales fuertes (positivas o negativas) entre las variables numéricas del dataset, a demas, nos permitira detectar posibles multicolinealidades y o entender la estructura de los datos.
df_cor <- df %>%
select(age, height_cm, weight_kg, heart_rate,
blood_pressure, sleep_hours,
nutrition_quality, activity_index, is_fit) %>%
mutate(is_fit = ifelse(is_fit == "yes", 1, 0))
cor_matrix <- cor(df_cor, use = "complete.obs")
ggplot(melt(cor_matrix), aes(Var1, Var2, fill = value)) +
geom_tile(color = "white", linewidth = 0.7) +
geom_text(aes(label = round(value, 2)),
color = "black", size = 3.5) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1, 1)) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
panel.grid = element_blank()) +
labs(title = "Matriz de Correlación",
x = "",
y = "",
fill = "Correlación") +
coord_fixed()
Interpretación
Estado físico (is_fit
): En el gráfico de
correlaciones se observa una correlación positiva moderada (0.35) entre
(is_fit
) y (activity_index
), así como una
correlación positiva moderada (0.26) entre (is_fit
) y
(nutrition_quality
). Esto sugiere que las personas con un
mayor nivel de actividad física y una mejor calidad nutricional tienden
a ser clasificadas como fit. Asimismo, se aprecia una
correlación negativa débil (-0.22) con (age
), lo que indica
que, a mayor edad, existe una ligera tendencia a presentar un menor
estado físico.
(Correlaciones casi nulas:
): Horas de sueño
(sleep_hours
), presión arterial
(blood_pressure
), frecuencia cardiaca
(heart_rate
), peso (weight_kg
) y altura
(height_cm
) presentan correlaciones muy cercanas a 0 con la
mayoria de las variables, por lo que no hay relaciones lineales fuertes
entre ellas.
Calidad de los datos
smokes)
(unificada a
“yes”/“no”) y (is_fit
) (convertida a factor).Sleep_hours
Distribución de variables clave
(is_fit
) está desbalanceada (60% “no” vs 40% “yes”),
lo que podría afectar modelos predictivos.
(Weight_kg
) muestra sesgo positivo (+1.43) y alta
curtosis (6.72), con valores atípicos en pesos altos.
Variables como (heart_rate
),
(blood_pressure
) y (sleep_hours
) siguen
distribución normal, mientras (activity_index
) y
(nutrition_quality
) son más uniformes.
Relaciones relevantes con el target (is_fit)
Fumadores (smokes=yes
) tienen solo 23.6% de
probabilidad de estar en forma vs 53.3% en no fumadores.
Hombres (gender=M
) muestran mayor tasa de condición
física (47.2%) que mujeres (33.1%).
(activity_index
) y (nutrition_quality
)
correlacionan positivamente con is_fit (0.35 y 0.26), siendo los
predictores más fuertes.
Edad avanzada y peso extremo (bajo/alto) reducen la probabilidad de estar en forma.
Hallazgos multivariados
Correlación positiva moderada (0.26) entre
(activity_index
) y (nutrition_quality
),
sugiriendo que actividad física y buena alimentación coexisten.
Variables como (blood_pressure
) y
(sleep_hours
) no muestran correlación lineal fuerte con la
variable objetivo, pero su distribución indica que valores extremos se
asocian a menor condición física.