Análisis descriptivo de la base de datos de cervezas
Tu nombre aquí
09 de agosto de 2026
Este informe analiza dos variables cualitativas (tipo y nacionalidad)
y dos variables cuantitativas (precio y calorías) de la base de datos de
cervezas beer2.csv, usada también en la Actividad 121. Para
las variables cualitativas se construye una tabla de frecuencia y se
identifica la moda. Para las variables cuantitativas se construye una
tabla de distribución de frecuencias por intervalos y se calculan los
indicadores estadísticos correspondientes.
library(data.table)
cerveza <- fread("beer2.csv")
dim(cerveza)
## [1] 1586614 15
str(cerveza)
## Classes 'data.table' and 'data.frame': 1586614 obs. of 15 variables:
## $ id : int 47986 48213 48215 47969 64883 52159 52159 52159 52159 52159 ...
## $ marca : chr "Vecchio Birraio" "Vecchio Birraio" "Vecchio Birraio" "Vecchio Birraio" ...
## $ precio : num 4.99 4.45 4.95 5.58 3.9 5.07 5.07 5.07 5.07 5.07 ...
## $ alcohol : num 13.8 16.9 17.7 13.8 20.7 ...
## $ carbohidratos : num 11.5 14.2 15 10.5 15.2 12.1 12.1 12.1 12.1 12.1 ...
## $ calorias : int 148 181 190 144 212 145 145 145 145 145 ...
## $ nacionalidad : chr "Canadá" "Canadá" "Canadá" "Canadá" ...
## $ calificacion : num 1.5 3 3 3 4 3 3.5 3 4 4.5 ...
## $ aroma : num 2 2.5 2.5 3 4.5 3.5 3.5 2.5 3 3.5 ...
## $ apariencia : num 2.5 3 3 3.5 4 3.5 3.5 3.5 3.5 5 ...
## $ paladar : num 1.5 3 3 2.5 4 3 4 2 3.5 4 ...
## $ sabor : num 1.5 3 3 3 4.5 3.5 4 3.5 4 4 ...
## $ nombre_cerveza: chr "Sausa Weizen" "Red Moon" "Black Horse Black Beer" "Sausa Pils" ...
## $ tipo : chr "clara artesanal" "cerveza normal y helada" "cerveza normal y helada" "lager importada" ...
## $ origen : chr "importada" "importada" "importada" "importada" ...
## - attr(*, ".internal.selfref")=<pointer: 0x000001550e14eb00>
La base tiene 1.586.614 registros. Las variables elegidas para este análisis son tipo y nacionalidad (cualitativas), y precio y calorías (cuantitativas).
tabla_tipo <- as.data.frame(table(cerveza$tipo))
names(tabla_tipo) <- c("tipo", "ni")
tabla_tipo <- tabla_tipo[order(-tabla_tipo$ni), ]
tabla_tipo$hi <- tabla_tipo$ni / nrow(cerveza)
tabla_tipo$Ni <- cumsum(tabla_tipo$ni)
tabla_tipo$Hi <- cumsum(tabla_tipo$hi)
knitr::kable(tabla_tipo, digits = 4, row.names = FALSE,
caption = "Tabla de frecuencia - tipo de cerveza")
| tipo | ni | hi | Ni | Hi |
|---|---|---|---|---|
| cerveza normal y helada | 839088 | 0.5289 | 839088 | 0.5289 |
| clara artesanal | 483464 | 0.3047 | 1322552 | 0.8336 |
| lager importada | 219194 | 0.1382 | 1541746 | 0.9717 |
| lager artesanal | 22725 | 0.0143 | 1564471 | 0.9860 |
| baja en calorías / sin alcohol | 22143 | 0.0140 | 1586614 | 1.0000 |
moda_tipo <- tabla_tipo$tipo[which.max(tabla_tipo$ni)]
moda_tipo
## [1] cerveza normal y helada
## 5 Levels: baja en calorías / sin alcohol ... lager importada
El tipo más común es “cerveza normal y helada”, con 839.088 registros, el 52.89% del total. Le sigue “clara artesanal” con el 30.47%. Entre estos dos tipos suman más del 83% de toda la base. Los tipos “lager artesanal” y “baja en calorías / sin alcohol” son los menos comunes, cada uno con menos del 1.5% de los datos. Esto muestra que la base está compuesta en su mayoría por cervezas de tipo normal, y que las variedades artesanales bajas en calorías son poco frecuentes.
tabla_nac <- as.data.frame(table(cerveza$nacionalidad))
names(tabla_nac) <- c("nacionalidad", "ni")
tabla_nac <- tabla_nac[order(-tabla_nac$ni), ]
tabla_nac$hi <- tabla_nac$ni / nrow(cerveza)
tabla_nac$Ni <- cumsum(tabla_nac$ni)
tabla_nac$Hi <- cumsum(tabla_nac$hi)
knitr::kable(tabla_nac, digits = 4, row.names = FALSE,
caption = "Tabla de frecuencia - nacionalidad")
| nacionalidad | ni | hi | Ni | Hi |
|---|---|---|---|---|
| Austria | 201941 | 0.1273 | 201941 | 0.1273 |
| Bélgica | 188677 | 0.1189 | 390618 | 0.2462 |
| Francia | 181574 | 0.1144 | 572192 | 0.3606 |
| Estados Unidos | 174165 | 0.1098 | 746357 | 0.4704 |
| Inglaterra | 162644 | 0.1025 | 909001 | 0.5729 |
| Canadá | 159508 | 0.1005 | 1068509 | 0.6735 |
| Japón | 155273 | 0.0979 | 1223782 | 0.7713 |
| Alemania | 121684 | 0.0767 | 1345466 | 0.8480 |
| Irlanda | 120742 | 0.0761 | 1466208 | 0.9241 |
| República Checa | 120406 | 0.0759 | 1586614 | 1.0000 |
moda_nac <- tabla_nac$nacionalidad[which.max(tabla_nac$ni)]
moda_nac
## [1] Austria
## 10 Levels: Alemania Austria Bélgica Canadá Estados Unidos ... República Checa
La nacionalidad con más registros es Austria, con el 12.73% del total, seguida de cerca por Bélgica (11.89%) y Francia (11.44%). La nacionalidad con menos registros es República Checa, con el 7.59%. A diferencia de la variable tipo, aquí no hay una categoría que domine claramente sobre las demás: las 10 nacionalidades tienen porcentajes bastante parecidos, todos entre el 7% y el 13%, lo que muestra que la base reúne cervezas de muchos países de forma bastante equilibrada.
calcular_indicadores <- function(x) {
n <- length(x)
minimo <- min(x)
maximo <- max(x)
media <- mean(x)
mediana <- median(x)
q1 <- as.numeric(quantile(x, 0.25))
q3 <- as.numeric(quantile(x, 0.75))
rango <- maximo - minimo
varianza <- var(x)
desv_est <- sd(x)
cv <- (desv_est / media) * 100
asimetria <- (sum((x - media)^3) / n) / (desv_est^3)
curtosis <- (sum((x - media)^4) / n) / (desv_est^4) - 3
data.frame(
n = n, minimo = minimo, maximo = maximo, media = media,
mediana = mediana, Q1 = q1, Q3 = q3, rango = rango,
varianza = varianza, desviacion = desv_est, CV_pct = cv,
asimetria = asimetria, curtosis = curtosis
)
}
construir_tabla_frecuencia <- function(x) {
n <- length(x)
k <- ceiling(1 + 3.322 * log10(n))
rango <- max(x) - min(x)
amplitud <- rango / k
limites <- seq(min(x), max(x), by = amplitud)
limites[length(limites)] <- max(x) + 1e-9
intervalos <- cut(x, breaks = limites, right = FALSE, include.lowest = TRUE)
tabla <- as.data.frame(table(intervalos))
names(tabla) <- c("intervalo", "ni")
tabla$Li <- limites[-length(limites)]
tabla$Ls <- limites[-1]
tabla$xi <- (tabla$Li + tabla$Ls) / 2
tabla$hi <- tabla$ni / n
tabla$Ni <- cumsum(tabla$ni)
tabla$Hi <- cumsum(tabla$hi)
tabla
}
indicadores_precio <- calcular_indicadores(cerveza$precio)
knitr::kable(indicadores_precio, digits = 3,
caption = "Indicadores estadísticos - precio")
| n | minimo | maximo | media | mediana | Q1 | Q3 | rango | varianza | desviacion | CV_pct | asimetria | curtosis |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1586614 | 2.37 | 7.72 | 5 | 5 | 4.36 | 5.64 | 5.35 | 0.784 | 0.885 | 17.708 | 0 | -0.5 |
tabla_precio <- construir_tabla_frecuencia(cerveza$precio)
knitr::kable(tabla_precio[, c("intervalo", "Li", "Ls", "xi", "ni", "hi", "Ni", "Hi")],
digits = 4, caption = "Tabla de distribución de frecuencias - precio")
| intervalo | Li | Ls | xi | ni | hi | Ni | Hi |
|---|---|---|---|---|---|---|---|
| [2.37,2.61) | 2.3700 | 2.6132 | 2.4916 | 674 | 0.0004 | 674 | 0.0004 |
| [2.61,2.86) | 2.6132 | 2.8564 | 2.7348 | 4067 | 0.0026 | 4741 | 0.0030 |
| [2.86,3.1) | 2.8564 | 3.0995 | 2.9780 | 12118 | 0.0076 | 16859 | 0.0106 |
| [3.1,3.34) | 3.0995 | 3.3427 | 3.2211 | 27506 | 0.0173 | 44365 | 0.0280 |
| [3.34,3.59) | 3.3427 | 3.5859 | 3.4643 | 45047 | 0.0284 | 89412 | 0.0564 |
| [3.59,3.83) | 3.5859 | 3.8291 | 3.7075 | 68328 | 0.0431 | 157740 | 0.0994 |
| [3.83,4.07) | 3.8291 | 4.0723 | 3.9507 | 97011 | 0.0611 | 254751 | 0.1606 |
| [4.07,4.32) | 4.0723 | 4.3155 | 4.1939 | 116909 | 0.0737 | 371660 | 0.2342 |
| [4.32,4.56) | 4.3155 | 4.5586 | 4.4370 | 136622 | 0.0861 | 508282 | 0.3204 |
| [4.56,4.8) | 4.5586 | 4.8018 | 4.6802 | 156811 | 0.0988 | 665093 | 0.4192 |
| [4.8,5.04) | 4.8018 | 5.0450 | 4.9234 | 157873 | 0.0995 | 822966 | 0.5187 |
| [5.04,5.29) | 5.0450 | 5.2882 | 5.1666 | 155878 | 0.0982 | 978844 | 0.6169 |
| [5.29,5.53) | 5.2882 | 5.5314 | 5.4098 | 152753 | 0.0963 | 1131597 | 0.7132 |
| [5.53,5.77) | 5.5314 | 5.7745 | 5.6530 | 130084 | 0.0820 | 1261681 | 0.7952 |
| [5.77,6.02) | 5.7745 | 6.0177 | 5.8961 | 108164 | 0.0682 | 1369845 | 0.8634 |
| [6.02,6.26) | 6.0177 | 6.2609 | 6.1393 | 87416 | 0.0551 | 1457261 | 0.9185 |
| [6.26,6.5) | 6.2609 | 6.5041 | 6.3825 | 59394 | 0.0374 | 1516655 | 0.9559 |
| [6.5,6.75) | 6.5041 | 6.7473 | 6.6257 | 37819 | 0.0238 | 1554474 | 0.9797 |
| [6.75,6.99) | 6.7473 | 6.9905 | 6.8689 | 21128 | 0.0133 | 1575602 | 0.9931 |
| [6.99,7.23) | 6.9905 | 7.2336 | 7.1120 | 8446 | 0.0053 | 1584048 | 0.9984 |
| [7.23,7.48) | 7.2336 | 7.4768 | 7.3552 | 2327 | 0.0015 | 1586375 | 0.9998 |
| [7.48,7.72] | 7.4768 | 7.7200 | 7.5984 | 239 | 0.0002 | 1586614 | 1.0000 |
intervalo_modal_precio <- tabla_precio[which.max(tabla_precio$ni), ]
intervalo_modal_precio
## intervalo ni Li Ls xi hi Ni Hi
## 11 [4.8,5.04) 157873 4.801818 5.045 4.923409 0.09950309 822966 0.5186933
hist(cerveza$precio, breaks = c(tabla_precio$Li, tail(tabla_precio$Ls, 1)),
col = "steelblue", border = "white",
main = "Distribución del precio", xlab = "precio", ylab = "Frecuencia absoluta")
abline(v = indicadores_precio$media, col = "red", lwd = 2, lty = 2)
legend("topright", legend = "Media", col = "red", lty = 2, lwd = 2)
El precio tiene una media de 5.00 y una mediana de 5.00, casi iguales, y una asimetría muy cerca de cero (-0.0005), lo que muestra que los datos están repartidos de forma pareja a los dos lados de la media. La curtosis negativa (-0.50) indica que la distribución es plana, sin un punto donde se junten muchos datos. El intervalo con más cervezas es el que va de 4.80 a 5.05, con cerca del 9.95% del total. El precio varía entre 2.37 y 7.72, con una variabilidad moderada (CV = 17.71%).
indicadores_calorias <- calcular_indicadores(cerveza$calorias)
knitr::kable(indicadores_calorias, digits = 3,
caption = "Indicadores estadísticos - calorías")
| n | minimo | maximo | media | mediana | Q1 | Q3 | rango | varianza | desviacion | CV_pct | asimetria | curtosis |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1586614 | 21 | 541 | 193.173 | 182 | 157 | 224 | 520 | 2168.646 | 46.569 | 24.107 | 0.915 | 1.318 |
tabla_calorias <- construir_tabla_frecuencia(cerveza$calorias)
knitr::kable(tabla_calorias[, c("intervalo", "Li", "Ls", "xi", "ni", "hi", "Ni", "Hi")],
digits = 4, caption = "Tabla de distribución de frecuencias - calorías")
| intervalo | Li | Ls | xi | ni | hi | Ni | Hi |
|---|---|---|---|---|---|---|---|
| [21,44.6) | 21.0000 | 44.6364 | 32.8182 | 1208 | 0.0008 | 1208 | 0.0008 |
| [44.6,68.3) | 44.6364 | 68.2727 | 56.4545 | 184 | 0.0001 | 1392 | 0.0009 |
| [68.3,91.9) | 68.2727 | 91.9091 | 80.0909 | 2217 | 0.0014 | 3609 | 0.0023 |
| [91.9,116) | 91.9091 | 115.5455 | 103.7273 | 7296 | 0.0046 | 10905 | 0.0069 |
| [116,139) | 115.5455 | 139.1818 | 127.3636 | 82993 | 0.0523 | 93898 | 0.0592 |
| [139,163) | 139.1818 | 162.8182 | 151.0000 | 419367 | 0.2643 | 513265 | 0.3235 |
| [163,186) | 162.8182 | 186.4545 | 174.6364 | 318845 | 0.2010 | 832110 | 0.5245 |
| [186,210) | 186.4545 | 210.0909 | 198.2727 | 245145 | 0.1545 | 1077255 | 0.6790 |
| [210,234) | 210.0909 | 233.7273 | 221.9091 | 181565 | 0.1144 | 1258820 | 0.7934 |
| [234,257) | 233.7273 | 257.3636 | 245.5455 | 168412 | 0.1061 | 1427232 | 0.8995 |
| [257,281) | 257.3636 | 281.0000 | 269.1818 | 97610 | 0.0615 | 1524842 | 0.9611 |
| [281,305) | 281.0000 | 304.6364 | 292.8182 | 35721 | 0.0225 | 1560563 | 0.9836 |
| [305,328) | 304.6364 | 328.2727 | 316.4545 | 9419 | 0.0059 | 1569982 | 0.9895 |
| [328,352) | 328.2727 | 351.9091 | 340.0909 | 7307 | 0.0046 | 1577289 | 0.9941 |
| [352,376) | 351.9091 | 375.5455 | 363.7273 | 2465 | 0.0016 | 1579754 | 0.9957 |
| [376,399) | 375.5455 | 399.1818 | 387.3636 | 6089 | 0.0038 | 1585843 | 0.9995 |
| [399,423) | 399.1818 | 422.8182 | 411.0000 | 49 | 0.0000 | 1585892 | 0.9995 |
| [423,446) | 422.8182 | 446.4545 | 434.6364 | 65 | 0.0000 | 1585957 | 0.9996 |
| [446,470) | 446.4545 | 470.0909 | 458.2727 | 460 | 0.0003 | 1586417 | 0.9999 |
| [470,494) | 470.0909 | 493.7273 | 481.9091 | 108 | 0.0001 | 1586525 | 0.9999 |
| [494,517) | 493.7273 | 517.3636 | 505.5455 | 10 | 0.0000 | 1586535 | 1.0000 |
| [517,541] | 517.3636 | 541.0000 | 529.1818 | 79 | 0.0000 | 1586614 | 1.0000 |
intervalo_modal_calorias <- tabla_calorias[which.max(tabla_calorias$ni), ]
intervalo_modal_calorias
## intervalo ni Li Ls xi hi Ni Hi
## 6 [139,163) 419367 139.1818 162.8182 151 0.2643157 513265 0.3234971
hist(cerveza$calorias, breaks = c(tabla_calorias$Li, tail(tabla_calorias$Ls, 1)),
col = "darkorange", border = "white",
main = "Distribución de las calorías", xlab = "calorías", ylab = "Frecuencia absoluta")
abline(v = indicadores_calorias$media, col = "red", lwd = 2, lty = 2)
legend("topright", legend = "Media", col = "red", lty = 2, lwd = 2)
Las calorías tienen una media de 193.17 y una mediana de 182, un poco más baja que la media, lo que ya avisa que hay valores altos que suben el promedio. Esto se confirma con la asimetría positiva (0.92): la mayoría de las cervezas tienen pocas calorías, pero hay un grupo con muchas más calorías que estira la distribución hacia la derecha. La curtosis positiva (1.32) muestra que los datos están bastante juntos alrededor de la media. El intervalo con más cervezas es el que va de 139.18 a 162.82 calorías, con cerca del 26.43% del total, casi la cuarta parte de toda la base. Las calorías van de 21 a 541, con una variabilidad más alta que la del precio (CV = 24.11%).
En cuanto a las variables cualitativas, el tipo de cerveza muestra una categoría muy dominante (“cerveza normal y helada”, más de la mitad de la base), mientras que la nacionalidad está mucho más repartida entre los 10 países, sin que ninguno se destaque demasiado sobre los demás. En cuanto a las variables cuantitativas, el precio es una variable pareja y sin inclinarse hacia ningún lado, con una variabilidad moderada, mientras que las calorías se inclinan hacia valores altos y tienen más variabilidad, señal de que existe un grupo de cervezas mucho más calóricas que el resto. En conjunto, el análisis muestra una base de datos con categorías bien definidas en cuanto a tipo, un buen equilibrio entre nacionalidades, y dos variables numéricas con comportamientos distintos: una más estable (precio) y otra con más variación y cervezas que se alejan del promedio (calorías).