El presente trabajo tiene como objetivo aplicar técnicas de análisis exploratorio de datos (EDA) utilizando el lenguaje de programación R, con el propósito de identificar relaciones entre variables y analizar un conjunto de datos para detectar patrones de distribución, valores atípicos (outliers) y posibles anomalías.
Se utiliza la base de datos Wine Quality (vino tinto), la cual contiene 1,599 observaciones y 12 variables.
BD <- read.csv("C:/Users/artur/OneDrive/Escritorio/Data/winequality-red.csv")
# estructura de la base de datos
str(BD)
## 'data.frame': 1599 obs. of 12 variables:
## $ fixed.acidity : num 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
## $ volatile.acidity : num 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
## $ citric.acid : num 0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
## $ residual.sugar : num 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
## $ chlorides : num 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
## $ free.sulfur.dioxide : num 11 25 15 17 11 13 15 15 9 17 ...
## $ total.sulfur.dioxide: num 34 67 54 60 34 40 59 21 18 102 ...
## $ density : num 0.998 0.997 0.997 0.998 0.998 ...
## $ pH : num 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
## $ sulphates : num 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
## $ alcohol : num 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
## $ quality : int 5 5 5 6 5 5 5 7 7 5 ...
Interpretación: la base de datos está compuesta por 1,599 filas (vinos) y 12 columnas, todas de tipo numérico. Al no existir variables de tipo texto o factor, todo el análisis visual se realizará con boxplots e histogramas.
# resumen estadístico de la base de datos
summary(BD)
## fixed.acidity volatile.acidity citric.acid residual.sugar
## Min. : 4.60 Min. :0.1200 Min. :0.000 Min. : 0.900
## 1st Qu.: 7.10 1st Qu.:0.3900 1st Qu.:0.090 1st Qu.: 1.900
## Median : 7.90 Median :0.5200 Median :0.260 Median : 2.200
## Mean : 8.32 Mean :0.5278 Mean :0.271 Mean : 2.539
## 3rd Qu.: 9.20 3rd Qu.:0.6400 3rd Qu.:0.420 3rd Qu.: 2.600
## Max. :15.90 Max. :1.5800 Max. :1.000 Max. :15.500
## chlorides free.sulfur.dioxide total.sulfur.dioxide density
## Min. :0.01200 Min. : 1.00 Min. : 6.00 Min. :0.9901
## 1st Qu.:0.07000 1st Qu.: 7.00 1st Qu.: 22.00 1st Qu.:0.9956
## Median :0.07900 Median :14.00 Median : 38.00 Median :0.9968
## Mean :0.08747 Mean :15.87 Mean : 46.47 Mean :0.9967
## 3rd Qu.:0.09000 3rd Qu.:21.00 3rd Qu.: 62.00 3rd Qu.:0.9978
## Max. :0.61100 Max. :72.00 Max. :289.00 Max. :1.0037
## pH sulphates alcohol quality
## Min. :2.740 Min. :0.3300 Min. : 8.40 Min. :3.000
## 1st Qu.:3.210 1st Qu.:0.5500 1st Qu.: 9.50 1st Qu.:5.000
## Median :3.310 Median :0.6200 Median :10.20 Median :6.000
## Mean :3.311 Mean :0.6581 Mean :10.42 Mean :5.636
## 3rd Qu.:3.400 3rd Qu.:0.7300 3rd Qu.:11.10 3rd Qu.:6.000
## Max. :4.010 Max. :2.0000 Max. :14.90 Max. :8.000
Interpretación: el resumen estadístico permite un primer diagnóstico:
quality (calidad) se concentra entre 5 y 6,
es decir, la mayoría de los vinos evaluados obtuvieron una calificación
intermedia; muy pocos vinos alcanzan calificaciones extremas (3 u
8).residual.sugar (azúcar residual) y
chlorides (cloruros) muestran una diferencia muy grande
entre su mediana y su valor máximo.density (densidad) y pH presentan rangos
muy estrechos y sus medias/medianas son casi idénticas.# nombre de cada atributo (se traducen al español para facilitar la lectura)
names(BD) <- c("acidez fija",
"acidez volatil",
"acido citrico",
"azucar residual",
"cloruros",
"dioxido azufre lib.",
"dioxido azufre tot",
"densidad",
"pH",
"sulfatos",
"alcohol",
"calidad")
Se usó una estructura for como bucle iterativo para
recorrer cada columna (atributo) de la base de datos y automatizar la
generación de boxplots e histogramas. Las variables numéricas se
dividieron en dos bloques de 6 para que los gráficos sean legibles.
BDN <- NULL
BDC <- NULL
columnas <- dim(BD)[2]
nombres_col <- colnames(BD)
# Primero identificamos qué columnas son numéricas y cuáles categóricas
for (i in 1:columnas) {
if (is.numeric(BD[ ,i]) == TRUE) {
BDN <- c(BDN, i)
} else {
BDC <- c(BDC, i)
}
}
# ===== BLOQUE 1: primeras 6 variables numéricas =====
bloque1 <- BDN[1:6]
par(mfrow = c(2, 6), mar = c(4,4,3,1))
for (i in bloque1) {
texto <- paste(nombres_col[i], "- Boxplot")
boxplot(BD[ ,i],
main = texto,
col = i,
cex.main = 0.9)
}
for (i in bloque1) {
texto <- paste(nombres_col[i], "- Histograma")
hist(BD[ ,i],
main = texto,
col = i,
xlab = nombres_col[i],
ylab = "frec",
cex.main = 0.9)
}
Interpretación del Bloque 1 (acidez fija, acidez volátil, ácido cítrico, azúcar residual, cloruros, dióxido de azufre libre):
En conjunto, este bloque evidencia que las variables de composición química “traza” (azúcar, cloruros, SO₂ libre) son las que más outliers y asimetría presentan, mientras que la acidez (fija y volátil) es más estable.
# ===== BLOQUE 2: últimas 6 variables numéricas =====
bloque2 <- BDN[7:length(BDN)]
par(mfrow = c(2, length(bloque2)), mar = c(4,4,3,1))
for (i in bloque2) {
texto <- paste(nombres_col[i], "- Box")
boxplot(BD[ ,i],
main = texto,
col = i,
cex.main = 0.9)
}
for (i in bloque2) {
texto <- paste(nombres_col[i], "- Hist")
hist(BD[ ,i],
main = texto,
col = i,
xlab = nombres_col[i],
ylab = "frec",
cex.main = 0.9)
}
Interpretación del Bloque 2 (dióxido de azufre total, densidad, pH, sulfatos, alcohol, calidad):
# ===== CATEGÓRICAS (pie charts), si las hay =====
if (length(BDC) > 0) {
par(mfrow = c(1, length(BDC)), mar = c(4,4,3,1))
for (i in BDC) {
texto <- paste(nombres_col[i])
pie(table(BD[ ,i]),
main = texto)
}
} else {
cat("No se generan gráficos de torta: las 12 variables de la base de datos son numéricas, no existen variables categóricas.")
}
## No se generan gráficos de torta: las 12 variables de la base de datos son numéricas, no existen variables categóricas.
##
analizar_columna <- function(df, col_name) {
variable <- df[[col_name]]
nombre <- col_name
cat("ANÁLISIS EXPLORATORIO PARA:", toupper(nombre), "\n")
print(summary(variable))
media <- mean(variable, na.rm = TRUE)
desv <- sd(variable, na.rm = TRUE)
cat("\nMedia:", media, "\n")
cat("Desviación estándar:", desv, "\n")
par(mfrow = c(1, 3))
hist(variable,
main = paste("Histograma:", nombre),
xlab = nombre,
ylab = "Frecuencia",
col = "lightblue",
border = "white")
boxplot(variable,
main = paste("Boxplot:", nombre),
ylab = nombre,
col = "lightpink")
x <- seq(min(variable, na.rm = TRUE),
max(variable, na.rm = TRUE),
length.out = 100)
y <- dnorm(x, mean = media, sd = desv)
plot(x, y,
type = "l",
main = paste("Densidad Normal:", nombre),
xlab = nombre,
ylab = "Densidad")
par(mfrow = c(1, 1))
}
analizar_columna(BD, "alcohol")
## ANÁLISIS EXPLORATORIO PARA: ALCOHOL
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.40 9.50 10.20 10.42 11.10 14.90
##
## Media: 10.42298
## Desviación estándar: 1.065668
Interpretación del Análisis Exploratorio de la variable Alcohol:
Estadísticos Descriptivos:El nivel de alcohol presenta un promedio (media) de 10.42% con una desviación estándar de 1.07%. La mediana se ubica en 10.20%, oscilando entre un valor mínimo de 8.40% y un máximo de 14.90%.
Histograma y Distribución: Presenta una ligera asimetría positiva (sesgada hacia la derecha), mostrando que la mayor concentración de datos se encuentra en los valores bajos y medios de alcohol (entre 9.0% y 11.0%).
Boxplot (Valores Atípicos): Muestra una distribución relativamente limpia, con muy pocos valores atípicos (outliers) detectados por encima del bigote superior (vinos con graduación alcohólica superior a 13.5%).
Ajuste a la Curva Normal: La curva teórica refleja adecuadamente la densidad de probabilidad centrada cerca de la media, confirmando que la variable es continua y adecuada para el modelado estadístico.
Nota: este bloque confirma lo observado en
str(BD) — al no existir variables categóricas, no se
generan gráficos de torta. Este resultado es el esperado para este
analisis exploratorio.
A partir del análisis exploratorio realizado sobre las 1,599 observaciones del conjunto de datos de Wine Quality (vino tinto), se concluye lo siguiente: