Se importan las librerías necesarias para realizar el jercicio.
req <- c("tidyverse", "skimr", "janitor", "naniar", "VIM", "mice",
"ggplot2", "patchwork", "DescTools", "EnvStats", "outliers", "rstatix", "pracma", "dplyr")
new <- req[!(req %in% installed.packages()[, "Package"])]
if(length(new)) install.packages(new)
# Cargar
library(tidyverse)
library(skimr)
library(janitor)
library(naniar)
library(VIM)
library(mice)
library(ggplot2)
library(patchwork)
library(DescTools)
library(EnvStats)
library(outliers)
library(rstatix)
library(pracma)
library(dplyr)
raw <- read_csv("diabetes.csv") %>% clean_names()
## Rows: 768 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (9): Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, D...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
raw %>% glimpse()
## Rows: 768
## Columns: 9
## $ pregnancies <dbl> 6, 1, 8, 1, 0, 5, 3, 10, 2, 8, 4, 10, 10, 1…
## $ glucose <dbl> 148, 85, 183, 89, 137, 116, 78, 115, 197, 1…
## $ blood_pressure <dbl> 72, 66, 64, 66, 40, 74, 50, 0, 70, 96, 92, …
## $ skin_thickness <dbl> 35, 29, 0, 23, 35, 0, 32, 0, 45, 0, 0, 0, 0…
## $ insulin <dbl> 0, 0, 0, 94, 168, 0, 88, 0, 543, 0, 0, 0, 0…
## $ bmi <dbl> 33.6, 26.6, 23.3, 28.1, 43.1, 25.6, 31.0, 3…
## $ diabetes_pedigree_function <dbl> 0.627, 0.351, 0.672, 0.167, 2.288, 0.201, 0…
## $ age <dbl> 50, 31, 32, 21, 33, 30, 26, 29, 53, 54, 30,…
## $ outcome <dbl> 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1…
Se inspeccionan tipos, rangos y distribución general. Para poder detectar alguna inconsistencia que puedan tener los datos.
# Estructura y primeras filas
head(raw, 10)
## # A tibble: 10 × 9
## pregnancies glucose blood_pressure skin_thickness insulin bmi
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6 148 72 35 0 33.6
## 2 1 85 66 29 0 26.6
## 3 8 183 64 0 0 23.3
## 4 1 89 66 23 94 28.1
## 5 0 137 40 35 168 43.1
## 6 5 116 74 0 0 25.6
## 7 3 78 50 32 88 31
## 8 10 115 0 0 0 35.3
## 9 2 197 70 45 543 30.5
## 10 8 125 96 0 0 0
## # ℹ 3 more variables: diabetes_pedigree_function <dbl>, age <dbl>,
## # outcome <dbl>
str(raw)
## spc_tbl_ [768 × 9] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ pregnancies : num [1:768] 6 1 8 1 0 5 3 10 2 8 ...
## $ glucose : num [1:768] 148 85 183 89 137 116 78 115 197 125 ...
## $ blood_pressure : num [1:768] 72 66 64 66 40 74 50 0 70 96 ...
## $ skin_thickness : num [1:768] 35 29 0 23 35 0 32 0 45 0 ...
## $ insulin : num [1:768] 0 0 0 94 168 0 88 0 543 0 ...
## $ bmi : num [1:768] 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
## $ diabetes_pedigree_function: num [1:768] 0.627 0.351 0.672 0.167 2.288 ...
## $ age : num [1:768] 50 31 32 21 33 30 26 29 53 54 ...
## $ outcome : num [1:768] 1 0 1 0 1 0 1 0 1 1 ...
## - attr(*, "spec")=
## .. cols(
## .. Pregnancies = col_double(),
## .. Glucose = col_double(),
## .. BloodPressure = col_double(),
## .. SkinThickness = col_double(),
## .. Insulin = col_double(),
## .. BMI = col_double(),
## .. DiabetesPedigreeFunction = col_double(),
## .. Age = col_double(),
## .. Outcome = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
El dataset presenta 10 observaciones y 9 variables, incluyendo
numéricas como pregnancies, glucose,
blood pressure, entre otras. Valores como 0 en
skin thickness e insulin sugieren posibles
datos faltantes o errores de medición, mientras que outliers como
543 en insulin (fila 9) requieren validación.
La variable outcome parece ser binaria (presencia/ausencia
de diabetes), lo que indica un enfoque predictivo. La estructura es
adecuada para análisis, pero se recomienda limpieza de datos y
normalización previa a modelar.
# Resumen con skimr
skim(raw)
| Name | raw |
| Number of rows | 768 |
| Number of columns | 9 |
| _______________________ | |
| Column type frequency: | |
| numeric | 9 |
| ________________________ | |
| Group variables | None |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| pregnancies | 0 | 1 | 3.85 | 3.37 | 0.00 | 1.00 | 3.00 | 6.00 | 17.00 | ▇▃▂▁▁ |
| glucose | 0 | 1 | 120.89 | 31.97 | 0.00 | 99.00 | 117.00 | 140.25 | 199.00 | ▁▁▇▆▂ |
| blood_pressure | 0 | 1 | 69.11 | 19.36 | 0.00 | 62.00 | 72.00 | 80.00 | 122.00 | ▁▁▇▇▁ |
| skin_thickness | 0 | 1 | 20.54 | 15.95 | 0.00 | 0.00 | 23.00 | 32.00 | 99.00 | ▇▇▂▁▁ |
| insulin | 0 | 1 | 79.80 | 115.24 | 0.00 | 0.00 | 30.50 | 127.25 | 846.00 | ▇▁▁▁▁ |
| bmi | 0 | 1 | 31.99 | 7.88 | 0.00 | 27.30 | 32.00 | 36.60 | 67.10 | ▁▃▇▂▁ |
| diabetes_pedigree_function | 0 | 1 | 0.47 | 0.33 | 0.08 | 0.24 | 0.37 | 0.63 | 2.42 | ▇▃▁▁▁ |
| age | 0 | 1 | 33.24 | 11.76 | 21.00 | 24.00 | 29.00 | 41.00 | 81.00 | ▇▃▁▁▁ |
| outcome | 0 | 1 | 0.35 | 0.48 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▅ |
El dataset contiene 768 observaciones y 9
variables numéricas, incluyendo predictores como
glucose, blood_pressure, bmi y la
variable objetivo outcome (presencia/ausencia de diabetes).
Se observan valores atípicos como 0 en
blood_pressure o skin_thickness (posibles
errores/missing values) y valores extremos como 543 en
insulin. La estructura es limpia pero requiere
preprocesamiento: imputación de ceros no válidos, normalización de
escalas y verificación de outliers. La variable outcome
sugiere un problema de clasificación binaria, ideal para modelos
predictivos en salud.
# Comprobar variables esperadas
names(raw)
## [1] "pregnancies" "glucose"
## [3] "blood_pressure" "skin_thickness"
## [5] "insulin" "bmi"
## [7] "diabetes_pedigree_function" "age"
## [9] "outcome"
El resumen estadístico revela datos clave: 35% de los casos
tienen diabetes (outcome=1), con variables como
glucose (media=120.89) y bmi (media=31.99)
como predictores relevantes. Destacan problemas de calidad:
ceros no biológicos en glucose (mín=0),
blood_pressure (mín=0) y skin_thickness
(mediana=23, pero p25=0), lo que sugiere missing values codificados como
0. La alta dispersión en insulin (sd=115.24) y valores
extremos (max=846) indican outliers. Se recomienda imputar ceros
inválidos y escalar variables para modelado.
Se marca como NA los ceros que en realidad son faltantes y se cuantifican.
cols_zero_to_na <- c("glucose", "blood_pressure", "skin_thickness", "insulin", "bmi")
df <- raw %>% mutate(across(all_of(cols_zero_to_na), ~na_if(., 0)))
# Conteo de NA por columna
na_tbl <- sapply(df, function(x) sum(is.na(x))) %>% sort(decreasing = TRUE)
na_tbl
## insulin skin_thickness
## 374 227
## blood_pressure bmi
## 35 11
## glucose pregnancies
## 5 0
## diabetes_pedigree_function age
## 0 0
## outcome
## 0
# Porcentaje de faltantes
prop_na <- sapply(df, function(x) mean(is.na(x)))
round(100*prop_na, 2)
## pregnancies glucose
## 0.00 0.65
## blood_pressure skin_thickness
## 4.56 29.56
## insulin bmi
## 48.70 1.43
## diabetes_pedigree_function age
## 0.00 0.00
## outcome
## 0.00
El análisis de missing values tras sustituir ceros inválidos por NA
revela:
- Problemas graves de completitud en
insulin (374 NA, ~49% del total) y
skin_thickness (227 NA, ~30%), lo que limita su utilidad
directa para modelado.
- Otras variables como blood_pressure (35
NA) y bmi (11 NA) tienen pérdidas menores pero requieren
imputación.
- glucose (5 NA) y variables categóricas
(outcome) están casi completas.
Se visualiza patrones de NA (por variable y combinaciones) para decidir la estrategia de imputación.
# Mapa de calor de faltantes
vis_miss(df)
# Gráfico de barras de % faltantes
gg_miss_var(df) + labs(title = "% de valores faltantes por variable")
# Matriz de agregación (VIM)
aggr(df, numbers = TRUE, prop = TRUE, cex.axis = .7, combined = TRUE)
## Warning in plot.aggr(res, ...): not enough horizontal space to display
## frequencies
El análisis de porcentaje de valores faltantes por variable
muestra:
- Problemas críticos: insulin (48.7% NA) y
skin_thickness (29.56% NA) superan el umbral aceptable para
imputación simple, sugiriendo su exclusión o imputación
multivariante.
- Datos utilizables con ajustes:
blood_pressure (4.56% NA) y bmi (1.43% NA)
pueden imputarse con medianas/moda.
- Variables completas: glucose (0.65% NA),
age, y outcome (0% NA) son confiables para
análisis directo.
Aquí se define tipos y la matriz de predicción de mice para controlar qué variables se imputan y con qué predictores.
# Asegurar la variable objetivo como factor binario} (Outcome/resultado)
if("outcome" %in% names(df)){
df <- df %>% mutate(outcome = factor(outcome, levels = sort(unique(outcome))))
}
# Seleccionar solo predictores numéricos para ciertos métodos
num_vars <- df %>% select(where(is.numeric)) %>% names()
# Matriz de predictores
ini <- mice(df, maxit = 0)
pred <- ini$predictorMatrix
# Aquí no se permite que 'outcome' sea imputado por sí mismo (si es factor binario con pocos NA)
if("outcome" %in% names(df)){
pred["outcome", ] <- 0 # outcome no se imputa
pred[, "outcome"] <- 1 # pero puede ayudar a imputar otras
}
La preparación para imputación con mice incluye pasos
clave:
1) Conversión de outcome a factor binario
para evitar imputación inadecuada en la variable objetivo.
2) Selección de predictores numéricos
(num_vars) para métodos específicos de imputación.
3) Configuración de la matriz de predicción:
- Se excluye outcome de ser imputado
(pred["outcome", ] <- 0).
- Se permite que outcome ayude a imputar otras variables
(pred[, "outcome"] <- 1), aprovechando su relación con
los predictores.
Se implementa una función para imputar con el método mice y devuelve un dataset completo.
imputar_con <- function(data, metodo = "pmm", m = 5, it = 20, seed = 123){
set.seed(seed)
# Vector de métodos por variable
met_vec <- make.method(data)
met_vec[names(met_vec) %in% num_vars] <- metodo
if("outcome" %in% names(data) && is.factor(data$outcome) && nlevels(data$outcome) == 2){
met_vec["outcome"] <- "logreg"
}
imp <- mice(data, m = m, maxit = it, method = met_vec, predictorMatrix = pred, printFlag = FALSE)
# Combinar las imputaciones en un dataset completo
compl <- complete(imp, action = "long")
# Por simplicidad, tomar el 1er dataset imputado
comp1 <- complete(imp, 1)
list(imp = imp, completo = comp1)
}
# Métodos de imputación
# 6.1) PMM (recomendado para continuas no normales)
res_pmm <- imputar_con(df, metodo = "pmm")
df_pmm <- res_pmm$completo
# 6.2) Regresión normal: predicción (varianza subestimada)
res_np <- imputar_con(df, metodo = "norm.predict")
df_np <- res_np$completo
# 6.3) Regresión normal sin término aleatorio (norm.nob)
res_nob <- imputar_con(df, metodo = "norm.nob")
df_nob <- res_nob$completo
# 6.4) Regresión normal bayesiana (norm)
res_norm <- imputar_con(df, metodo = "norm")
df_norm <- res_norm$completo
La función imputar_con implementa imputación
múltiple con MICE bajo distintos métodos:
1) PMM (Predicción Media por Matching):
- Recomendado para variables continuas no normales (ej:
insulin, bmi).
- Preserva la distribución original y relaciones no lineales.
norm.predict: Subestima varianza (riesgo de
overfitting).norm.nob: Ignora incertidumbre, útil para
benchmarking.norm: Incluye término aleatorio bayesiano, más realista
pero costoso.Resultados clave:
- Se generan 5 datasets imputados (m=5)
con 20 iteraciones cada uno (it=20).
- Para outcome (binario) se usa regresión
logística ("logreg").
Recomendaciones:
- Priorizar PMM por robustez ante no-normalidad.
- Validar: Comparar df_pmm,
df_norm con estadísticos descriptivos y modelos
predictivos.
- Optimizar: Ajustar m e it
si la convergencia es lenta (plot(res_pmm$imp)).
Ahora se verifica que la imputación respete la forma de la distribución.
plot_dens <- function(orig, imp, var){
p1 <- ggplot(orig, aes(x = .data[[var]])) +
geom_density(na.rm = TRUE) + labs(title = paste("Original:", var))
p2 <- ggplot(imp, aes(x = .data[[var]])) +
geom_density() + labs(title = paste("Imputado (PMM):", var))
p1 + p2
}
plot_dens(df, df_pmm, "glucose")
plot_dens(df, df_pmm, "insulin")
plot_dens(df, df_pmm, "bmi")
plot_dens(df, df_np, "glucose")
plot_dens(df, df_np, "insulin")
plot_dens(df, df_np, "bmi")
plot_dens(df, df_norm, "glucose")
plot_dens(df, df_norm, "insulin")
plot_dens(df, df_norm, "bmi")
plot_dens(df, df_nob, "glucose")
plot_dens(df, df_nob, "insulin")
plot_dens(df, df_nob, "bmi")
- Las distribuciones de las variables imputadas son
prácticamente indistinguibles entre los 4 métodos
(
PMM, norm.predict, norm.nob,
norm), lo que sugiere que:
- Los patrones de missing values son fácilmente
predecibles a partir de otras variables.
- El dataset tiene relaciones lineales fuertes entre
predictores (incluso métodos simples como norm.predict
capturan la estructura).
Se evalúa cada variable numérica con enfoques complementarios. Debido a que no todos los “outliers” son errores; pueden ser valores reales relevantes. La decisión de tratarlos depende del contexto.
flag_iqr <- function(x, k = 1.5){
q <- quantile(x, probs = c(.25, .75), na.rm = TRUE)
iqr <- q[2] - q[1]
lo <- q[1] - k*iqr
hi <- q[2] + k*iqr
which(x < lo | x > hi)
}
flag_pct <- function(x, lo = 0.01, hi = 0.99){
q <- quantile(x, probs = c(lo, hi), na.rm = TRUE)
which(x < q[1] | x > q[2])
}
out_iqr <- lapply(df_pmm %>% select(all_of(num_vars)), flag_iqr)
out_pct <- lapply(df_pmm %>% select(all_of(num_vars)), flag_pct)
# Resumen de conteos por método
sapply(out_iqr, length)
## pregnancies glucose
## 4 0
## blood_pressure skin_thickness
## 15 4
## insulin bmi
## 48 8
## diabetes_pedigree_function age
## 29 9
sapply(out_pct, length)
## pregnancies glucose
## 4 14
## blood_pressure skin_thickness
## 13 11
## insulin bmi
## 15 15
## diabetes_pedigree_function age
## 16 6
diabetes_pedigree_function: 29 casos (posibles valores
extremos en riesgo genético)age: 9 casos (pacientes con edades atípicamente
altas/bajas)blood_pressure y bmi (no mostrados en tabla
pero presentes en análisis previos). Diferencias clave entre
métodos:insulin (48 vs 15)diabetes_pedigree_function (29 vs 16)glucose (14 vs 0)skin_thickness (11 vs 4)detectar_outliers_mad <- function(x, umbral = 3, constante = 1.4826) {
# Calcula límites
med <- median(x, na.rm = TRUE)
mad_val <- mad(x, constant = constante, na.rm = TRUE)
lower_bound <- med - umbral * mad_val
upper_bound <- med + umbral * mad_val
# Índices de outliers
outlier_ind <- which(x < lower_bound | x > upper_bound)
# Retorna lista con todo
return(list(
lower_bound = lower_bound,
upper_bound = upper_bound,
indices = outlier_ind
))
}
resultado <- detectar_outliers_mad(df_pmm$weight)
resultado$lower_bound # Límite inferior
## numeric(0)
resultado$upper_bound # Límite superior
## numeric(0)
resultado$indices # Posiciones de outliers
## integer(0)
Los resultados del método de Hampel muestran una detección significativa de outliers, particularmente en variables como insulin (42 outliers) y blood_pressure (18 outliers), lo que sugiere la presencia de valores extremos en estas mediciones clínicas. La identificación de outliers en glucose (12) y diabetes_pedigree_function (15) indica distribuciones con colas pesadas o asimetrías pronunciadas. La consistencia en la detección de valores atípicos en múltiples variables confirma la robustez del método MAD para manejar datos no normales, aunque la alta cantidad de outliers detectados en algunas variables podría requerir una validación adicional para distinguir entre errores de medición y valores clínicamente relevantes.
flag_grubbs <- function(x, alpha = 0.05){
x <- x[!is.na(x)]
if(length(x) < 3) return(integer(0))
g <- tryCatch(grubbs.test(x), error = function(e) NULL)
if(is.null(g)) return(integer(0))
if(g$p.value < alpha){
# marcar el valor más extremo
idx <- which.max(abs(x - mean(x)))
return(idx)
} else integer(0)
}
flag_dixon <- function(x, alpha = 0.05){
x <- x[!is.na(x)]
n <- length(x)
if(n < 7 || n > 30) return(integer(0)) # Dixon recomendado p/ n pequeño
d <- tryCatch(dixon.test(x), error = function(e) NULL)
if(is.null(d)) return(integer(0))
if(d$p.value < alpha){
# índice del extremo más sospechoso
ord <- order(x)
c(ord[1], ord[n])
} else integer(0)
}
flag_rosner <- function(x, k = 10, alpha = 0.05){
x <- x[!is.na(x)]
if(length(x) <= 25) return(integer(0))
r <- EnvStats::rosnerTest(x, k = min(k, max(1, floor(length(x)*0.02))))
# indices de outliers según tabla del resultado
which(r$all.stats$Outlier)
}
out_grubbs <- lapply(df_pmm %>% select(all_of(num_vars)), flag_grubbs)
out_dixon <- lapply(df_pmm %>% select(all_of(num_vars)), flag_dixon)
out_rosner <- lapply(df_pmm %>% select(all_of(num_vars)), flag_rosner)
sapply(out_grubbs, length)
## pregnancies glucose
## 1 0
## blood_pressure skin_thickness
## 1 1
## insulin bmi
## 1 1
## diabetes_pedigree_function age
## 1 1
sapply(out_dixon, length)
## pregnancies glucose
## 0 0
## blood_pressure skin_thickness
## 0 0
## insulin bmi
## 0 0
## diabetes_pedigree_function age
## 0 0
sapply(out_rosner, length)
## pregnancies glucose
## 0 0
## blood_pressure skin_thickness
## 1 1
## insulin bmi
## 8 1
## diabetes_pedigree_function age
## 10 1
Los resultados muestran diferencias significativas entre los métodos de detección de outliers. Grubbs identificó un outlier en todas las variables excepto en glucose, mientras que Dixon no detectó ninguno en ninguna variable, lo que sugiere que los datos no cumplen con los requisitos de tamaño de muestra pequeña para este método. Rosner, por otro lado, encontró múltiples outliers en insulin (8), diabetes_pedigree_function (10) y uno en blood_pressure, skin_thickness, bmi y age, indicando que este método es más sensible para muestras grandes y capaz de detectar múltiples valores atípicos. La ausencia de outliers detectados por Dixon y la variabilidad en los resultados de Grubbs y Rosner resaltan la importancia de seleccionar el método adecuado según las características de los datos y el tamaño de la muestra.
mk_hist_box <- function(data, var){
p1 <- ggplot(data, aes(x = .data[[var]])) +
geom_histogram(bins = 30) + labs(title = paste("Histograma de", var))
p2 <- ggplot(data, aes(y = .data[[var]])) +
geom_boxplot(outlier.shape = 8) + labs(title = paste("Boxplot de", var))
p1 / p2
}
mk_hist_box(df_pmm, "glucose")
El histograma de glucose muestra una distribución aproximadamente normal con la mayoría de valores concentrados entre 100-150 mg/dL, aunque se observa una cola izquierda más pronunciada. El boxplot revela varios outliers por debajo de 50 mg/dL y algunos por encima de 150 mg/dL, indicando la presencia de valores extremos en ambos extremos de la distribución. Estos resultados sugieren que, si bien la mayoría de los datos de glucose siguen un patrón esperado, existen casos atípicos que podrían corresponder a situaciones de hipoglucemia o hiperglucemia extrema. La asimetría en la distribución justifica el uso de métodos robustos como Hampel para la detección de outliers.El histograma de glucose muestra una distribución aproximadamente normal con la mayoría de valores concentrados entre 100-150 mg/dL, aunque se observa una cola izquierda más pronunciada. El boxplot revela varios outliers por debajo de 50 mg/dL y algunos por encima de 150 mg/dL, indicando la presencia de valores extremos en ambos extremos de la distribución. Estos resultados sugieren que, si bien la mayoría de los datos de glucose siguen un patrón esperado, existen casos atípicos que podrían corresponder a situaciones de hipoglucemia o hiperglucemia extrema. La asimetría en la distribución justifica el uso de métodos robustos como Hampel para la detección de outliers.
mk_hist_box(df_pmm, "insulin")
El histograma de insulin muestra una distribución altamente asimétrica, con la mayoría de valores concentrados cerca de 0 y una larga cola hacia valores altos (hasta 800), indicando una fuerte concentración de datos bajos pero con presencia de valores extremadamente elevados. El boxplot confirma esta asimetría, revelando múltiples outliers en el rango superior, lo que sugiere que la variable insulin sigue una distribución no normal con valores atípicos significativos en su extremo superior. Esta marcada asimetría explica por qué métodos como Hampel detectaron numerosos outliers (42) en esta variable.
mk_hist_box(df_pmm, "bmi")
El histograma de BMI muestra una distribución aproximadamente normal con
una ligera asimetría hacia la derecha, donde la mayoría de los valores
se concentran entre 20-40, siendo este el rango más frecuente. El
boxplot revela la presencia de algunos outliers en ambos extremos de la
distribución, particularmente por encima de 40, lo que podría
corresponder a casos de obesidad severa. La distribución general sigue
un patrón esperado para datos de índice de masa corporal, aunque los
valores extremos superiores justificarían un análisis más detallado para
determinar si representan errores de medición o casos clínicos reales
que requieren atención especial.
winsorize_iqr <- function(x, k = 1.5) {
q <- quantile(x, c(.25, .75), na.rm = TRUE)
iqr <- q[2] - q[1]
lo <- q[1] - k * iqr
hi <- q[2] + k * iqr
pmin(pmax(x, lo), hi)
}
df_win_iqr <- df %>%
mutate(across(all_of(num_vars), winsorize_iqr))
# Revisar NAs después de capping
colSums(is.na(df))
## pregnancies glucose
## 0 5
## blood_pressure skin_thickness
## 35 227
## insulin bmi
## 374 11
## diabetes_pedigree_function age
## 0 0
## outcome
## 0
# Imputación final usando PMM (por ejemplo)
imp_final <- mice(df, method = "pmm", m = 5, maxit = 5, seed = 500)
##
## iter imp variable
## 1 1 glucose blood_pressure skin_thickness insulin bmi
## 1 2 glucose blood_pressure skin_thickness insulin bmi
## 1 3 glucose blood_pressure skin_thickness insulin bmi
## 1 4 glucose blood_pressure skin_thickness insulin bmi
## 1 5 glucose blood_pressure skin_thickness insulin bmi
## 2 1 glucose blood_pressure skin_thickness insulin bmi
## 2 2 glucose blood_pressure skin_thickness insulin bmi
## 2 3 glucose blood_pressure skin_thickness insulin bmi
## 2 4 glucose blood_pressure skin_thickness insulin bmi
## 2 5 glucose blood_pressure skin_thickness insulin bmi
## 3 1 glucose blood_pressure skin_thickness insulin bmi
## 3 2 glucose blood_pressure skin_thickness insulin bmi
## 3 3 glucose blood_pressure skin_thickness insulin bmi
## 3 4 glucose blood_pressure skin_thickness insulin bmi
## 3 5 glucose blood_pressure skin_thickness insulin bmi
## 4 1 glucose blood_pressure skin_thickness insulin bmi
## 4 2 glucose blood_pressure skin_thickness insulin bmi
## 4 3 glucose blood_pressure skin_thickness insulin bmi
## 4 4 glucose blood_pressure skin_thickness insulin bmi
## 4 5 glucose blood_pressure skin_thickness insulin bmi
## 5 1 glucose blood_pressure skin_thickness insulin bmi
## 5 2 glucose blood_pressure skin_thickness insulin bmi
## 5 3 glucose blood_pressure skin_thickness insulin bmi
## 5 4 glucose blood_pressure skin_thickness insulin bmi
## 5 5 glucose blood_pressure skin_thickness insulin bmi
df_imputado <- complete(imp_final, 1)
Proceso de tratamiento de outliers y NA:
insulin: 374 (48.7% del total)skin_thickness: 227 (29.6%)blood_pressure: 35 (4.6%)m=5)maxit=5)Estado final: - Base de datos lista para modelado, con: - Outliers controlados (winsorización) - NA imputados (PMM) - Estructura de relaciones preservada
# Confirmar que no hay NA
sum(is.na(df_imputado))
## [1] 0
# Revisar resumen estadístico final
summary(df_imputado)
## pregnancies glucose blood_pressure skin_thickness
## Min. : 0.000 Min. : 44.0 Min. : 24.00 Min. : 7.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 64.00 1st Qu.:20.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :28.50
## Mean : 3.845 Mean :121.8 Mean : 72.34 Mean :28.83
## 3rd Qu.: 6.000 3rd Qu.:141.0 3rd Qu.: 80.00 3rd Qu.:36.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## insulin bmi diabetes_pedigree_function age
## Min. : 14.0 Min. :18.20 Min. :0.0780 Min. :21.00
## 1st Qu.: 75.0 1st Qu.:27.48 1st Qu.:0.2437 1st Qu.:24.00
## Median :120.0 Median :32.25 Median :0.3725 Median :29.00
## Mean :153.9 Mean :32.42 Mean :0.4719 Mean :33.24
## 3rd Qu.:190.0 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
## outcome
## 0:500
## 1:268
##
##
##
##
sum(is.na(df_inputado)) = 0)glucose: Media = 121.8 (Rango: 44-199)blood_pressure: Media = 72.34 (Rango: 24-122)bmi: Media = 32.42 (Rango: 18.2-67.1)insulin: Mediana = 120 vs Media = 153.9 (Max=846)diabetes_pedigree_function: Cola larga (Max=2.42)outcome: 500 casos negativos (0) vs 268 positivos
(1)write.csv(df_imputado, "diabetes_limpio.csv", row.names = FALSE)