El propósito de este informe es realizar un diagnóstico descriptivo de las preferencias expresadas por consumidores de cerveza e identificar patrones en el precio, la composición nutricional, el tipo, el origen y las valoraciones sensoriales. El análisis es descriptivo: permite comparar comportamientos dentro de la base académica, pero no demostrar relaciones de causa y efecto.
La base beer2.csv contiene 1.586.614
reseñas y 15 variables. Cada fila representa
una reseña; por ello, una cerveza puede aparecer más de una vez.
id se utiliza únicamente como identificador y no se
interpreta como variable estadística.
calidad <- data.table(
Indicador = c("Número de reseñas", "Número de variables", "Datos faltantes"),
Resultado = c(format(nrow(beer2), big.mark = "."), ncol(beer2), sum(is.na(beer2)))
)
kable(calidad, align = c("l", "r"))
| Indicador | Resultado |
|---|---|
| Número de reseñas | 1.586.614 |
| Número de variables | 15 |
| Datos faltantes | 0 |
No se encontraron datos faltantes. La variable precio es
simulada, por lo que sus resultados describen exclusivamente esta base
académica y no deben interpretarse como precios reales del mercado.
datatable(head(beer2, 8), options = list(pageLength = 8, scrollX = TRUE),
rownames = FALSE)
ft_tipo <- tabla_frecuencia(beer2$tipo)
kable(ft_tipo, align = c("l", "r", "r"))
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| cerveza normal y helada | 839088 | 52.89 |
| clara artesanal | 483464 | 30.47 |
| lager importada | 219194 | 13.82 |
| lager artesanal | 22725 | 1.43 |
| baja en calorías / sin alcohol | 22143 | 1.40 |
moda(beer2$tipo)
## [1] "cerveza normal y helada"
ggplot(ft_tipo, aes(x = reorder(Categoría, Frecuencia), y = Frecuencia)) +
geom_col(fill = "#2E86AB") +
coord_flip() +
scale_y_continuous(labels = label_number(big.mark = ".")) +
labs(title = "Reseñas según tipo de cerveza", x = NULL, y = "Frecuencia") +
theme_minimal()
La categoría modal es cerveza normal y helada, con aproximadamente 52,89 % de las reseñas. Le sigue la cerveza clara artesanal con 30,47 %. Las categorías lager artesanal y baja en calorías o sin alcohol tienen una representación cercana al 1,4 % cada una. Por tanto, las comparaciones deben interpretarse teniendo en cuenta el fuerte desbalance entre tipos.
ft_origen <- tabla_frecuencia(beer2$origen)
kable(ft_origen, align = c("l", "r", "r"))
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| importada | 1412449 | 89.02 |
| nacional | 174165 | 10.98 |
moda(beer2$origen)
## [1] "importada"
ggplot(ft_origen, aes(x = Categoría, y = Frecuencia, fill = Categoría)) +
geom_col(show.legend = FALSE) +
scale_y_continuous(labels = label_number(big.mark = ".")) +
labs(title = "Reseñas según origen", x = NULL, y = "Frecuencia") +
theme_minimal()
El origen modal es importada. Las cervezas importadas reúnen 89,02 % de las reseñas, mientras las nacionales representan 10,98 %. Esta diferencia describe la composición de la base y no necesariamente la participación real del mercado.
ft_nacionalidad <- tabla_frecuencia(beer2$nacionalidad)
kable(ft_nacionalidad, align = c("l", "r", "r"))
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| Austria | 201941 | 12.73 |
| Bélgica | 188677 | 11.89 |
| Francia | 181574 | 11.44 |
| Estados Unidos | 174165 | 10.98 |
| Inglaterra | 162644 | 10.25 |
| Canadá | 159508 | 10.05 |
| Japón | 155273 | 9.79 |
| Alemania | 121684 | 7.67 |
| Irlanda | 120742 | 7.61 |
| República Checa | 120406 | 7.59 |
moda(beer2$nacionalidad)
## [1] "Austria"
Austria es la nacionalidad modal, con 12,73 % de los registros,
seguida por Bélgica y Francia. Las diez nacionalidades presentan
participaciones entre 7,59 % y 12,73 %, de modo que esta variable está
menos concentrada que tipo y origen.
Debido a que marca y nombre_cerveza tienen
muchas categorías, una tabla completa sería poco legible. Se muestran
las diez categorías más frecuentes y se identifica la moda.
top_marcas <- tabla_frecuencia(beer2$marca)[1:10]
top_nombres <- tabla_frecuencia(beer2$nombre_cerveza)[1:10]
kable(top_marcas, caption = "Diez marcas más frecuentes")
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| Boston Beer Company (Samuel Adams) | 39444 | 2.49 |
| Dogfish Head Brewery | 33839 | 2.13 |
| Stone Brewing Co. | 33066 | 2.08 |
| Sierra Nevada Brewing Co. | 28751 | 1.81 |
| Bell’s Brewery, Inc. | 25191 | 1.59 |
| Rogue Ales | 24083 | 1.52 |
| Founders Brewing Company | 20004 | 1.26 |
| Victory Brewing Company | 19479 | 1.23 |
| Lagunitas Brewing Company | 16837 | 1.06 |
| Avery Brewing Company | 16107 | 1.02 |
kable(top_nombres, caption = "Diez nombres de cerveza más frecuentes")
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 90 Minute IPA | 3290 | 0.21 |
| India Pale Ale | 3130 | 0.20 |
| Old Rasputin Russian Imperial Stout | 3111 | 0.20 |
| Sierra Nevada Celebration Ale | 3000 | 0.19 |
| Two Hearted Ale | 2728 | 0.17 |
| Arrogant Bastard Ale | 2704 | 0.17 |
| Stone Ruination IPA | 2704 | 0.17 |
| Sierra Nevada Pale Ale | 2587 | 0.16 |
| Stone IPA (India Pale Ale) | 2575 | 0.16 |
| Pliny The Elder | 2527 | 0.16 |
cat("Moda de marca:", paste(moda(beer2$marca), collapse = ", "), "\n\n")
## Moda de marca: Boston Beer Company (Samuel Adams)
cat("Moda de nombre de cerveza:", paste(moda(beer2$nombre_cerveza), collapse = ", "))
## Moda de nombre de cerveza: 90 Minute IPA
Aunque las valoraciones utilizan números, representan categorías ordenadas de evaluación. Por ello se resumen con frecuencias, porcentajes, mediana y moda.
for (v in variables_ordinales) {
cat("\n\n##", tools::toTitleCase(v), "\n\n")
tf <- tabla_frecuencia(beer2[[v]])
print(kable(tf, align = c("r", "r", "r")))
cat("\nMediana:", median(beer2[[v]]),
"— Moda:", paste(moda(beer2[[v]]), collapse = ", "), "\n")
}
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 4 | 582764 | 36.73 |
| 4.5 | 324385 | 20.45 |
| 3.5 | 301817 | 19.02 |
| 3 | 165644 | 10.44 |
| 5 | 91320 | 5.76 |
| 2.5 | 58523 | 3.69 |
| 2 | 38225 | 2.41 |
| 1.5 | 12975 | 0.82 |
| 1 | 10954 | 0.69 |
| 0 | 7 | 0.00 |
Mediana: 4 — Moda: 4
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 4 | 557383 | 35.13 |
| 3.5 | 365312 | 23.02 |
| 4.5 | 271450 | 17.11 |
| 3 | 200030 | 12.61 |
| 2.5 | 66359 | 4.18 |
| 5 | 64117 | 4.04 |
| 2 | 42566 | 2.68 |
| 1.5 | 12524 | 0.79 |
| 1 | 6873 | 0.43 |
Mediana: 4 — Moda: 4
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 4 | 674186 | 42.49 |
| 3.5 | 318529 | 20.08 |
| 4.5 | 288108 | 18.16 |
| 3 | 166009 | 10.46 |
| 5 | 65398 | 4.12 |
| 2.5 | 39493 | 2.49 |
| 2 | 25414 | 1.60 |
| 1.5 | 6147 | 0.39 |
| 1 | 3323 | 0.21 |
| 0 | 7 | 0.00 |
Mediana: 4 — Moda: 4
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 4 | 606711 | 38.24 |
| 3.5 | 338585 | 21.34 |
| 4.5 | 253102 | 15.95 |
| 3 | 206932 | 13.04 |
| 2.5 | 62842 | 3.96 |
| 5 | 62190 | 3.92 |
| 2 | 38333 | 2.42 |
| 1.5 | 11045 | 0.70 |
| 1 | 6874 | 0.43 |
Mediana: 4 — Moda: 4
| Categoría | Frecuencia | Porcentaje |
|---|---|---|
| 4 | 541429 | 34.12 |
| 4.5 | 336162 | 21.19 |
| 3.5 | 324541 | 20.45 |
| 3 | 166860 | 10.52 |
| 5 | 83977 | 5.29 |
| 2.5 | 66534 | 4.19 |
| 2 | 41992 | 2.65 |
| 1.5 | 15128 | 0.95 |
| 1 | 9991 | 0.63 |
Mediana: 4 — Moda: 4
En las cinco valoraciones la moda es 4,0. La calificación general de 4,0 concentra 36,73 % de los registros; aroma 35,13 %; apariencia 42,49 %; paladar 38,24 % y sabor 34,12 %. En general, las reseñas se concentran entre 3,5 y 4,5, lo cual refleja valoraciones predominantemente favorables dentro de esta base.
ord_long <- melt(beer2[, ..variables_ordinales],
measure.vars = variables_ordinales,
variable.name = "Atributo", value.name = "Valor")
ggplot(ord_long, aes(x = factor(Valor), fill = Atributo)) +
geom_bar(position = "dodge") +
scale_y_continuous(labels = label_number(big.mark = ".")) +
labs(title = "Distribución de las valoraciones", x = "Valoración", y = "Frecuencia") +
theme_minimal() +
theme(legend.position = "bottom")
rm(ord_long)
resumen_num <- resumen_cuantitativo(beer2, variables_cuantitativas)
columnas_numericas <- setdiff(names(resumen_num), c("Variable", "Moda"))
resumen_num[, (columnas_numericas) := lapply(.SD, round, 2), .SDcols = columnas_numericas]
kable(resumen_num, align = c("l", rep("r", ncol(resumen_num) - 1)))
| Variable | Media | Mediana | Moda | Minimo | Q1 | Q3 | Maximo | Rango | RIC | Varianza | Desviacion | CV_porcentaje |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| precio | 5.36 | 5.41 | 5.69 | 2.20 | 4.98 | 5.82 | 8.03 | 5.83 | 0.84 | 0.42 | 0.65 | 12.11 |
| alcohol | 18.71 | 17.67 | 13.75 | 0.03 | 14.28 | 22.63 | 59.45 | 59.42 | 8.35 | 29.77 | 5.46 | 29.16 |
| carbohidratos | 14.05 | 13.80 | 13.5 | 3.50 | 12.40 | 15.60 | 30.20 | 26.70 | 3.20 | 5.64 | 2.38 | 16.91 |
| calorias | 193.17 | 182.00 | 156 | 21.00 | 157.00 | 224.00 | 541.00 | 520.00 | 67.00 | 2168.65 | 46.57 | 24.11 |
El precio presenta media de 5,36 y mediana de 5,41; su cercanía sugiere una distribución relativamente equilibrada. El alcohol tiene media de 18,71 gramos y mediana de 17,67, mientras las calorías tienen media de 193,17 y mediana de 182. En estas dos variables la media supera la mediana, lo que indica influencia de valores altos. En consecuencia, para alcohol y calorías conviene acompañar la media y desviación estándar con la mediana y el rango intercuartílico, que son menos sensibles a extremos.
for (v in variables_cuantitativas) {
print(
ggplot(beer2, aes(x = .data[[v]])) +
geom_histogram(bins = 40, fill = "#2E86AB", color = "white") +
scale_y_continuous(labels = label_number(big.mark = ".")) +
labs(title = paste("Distribución de", v), x = v, y = "Frecuencia") +
theme_minimal()
)
}
comparacion_tipo <- beer2[, lapply(.SD, mean), by = tipo,
.SDcols = c(variables_cuantitativas, variables_ordinales)]
comparacion_tipo[, (names(comparacion_tipo)[-1]) :=
lapply(.SD, round, 2), .SDcols = -1]
kable(comparacion_tipo)
| tipo | precio | alcohol | carbohidratos | calorias | calificacion | aroma | apariencia | paladar | sabor |
|---|---|---|---|---|---|---|---|---|---|
| clara artesanal | 5.70 | 18.15 | 14.51 | 191.10 | 3.88 | 3.78 | 3.87 | 3.79 | 3.82 |
| cerveza normal y helada | 5.27 | 20.10 | 14.29 | 203.82 | 3.86 | 3.85 | 3.94 | 3.83 | 3.90 |
| lager importada | 5.17 | 15.86 | 12.71 | 167.84 | 3.61 | 3.34 | 3.55 | 3.47 | 3.48 |
| baja en calorías / sin alcohol | 4.28 | 9.84 | 8.66 | 109.52 | 2.95 | 2.58 | 2.82 | 2.68 | 2.64 |
| lager artesanal | 4.55 | 15.67 | 13.54 | 169.88 | 3.64 | 3.37 | 3.59 | 3.49 | 3.49 |
La cerveza clara artesanal presenta el mayor precio promedio (5,71). La cerveza normal y helada tiene los mayores promedios de alcohol (20,10 gramos) y calorías (203,82), mientras que la categoría baja en calorías o sin alcohol registra los menores promedios de alcohol, carbohidratos y calorías. Esta última categoría también presenta las valoraciones promedio más bajas. Las calificaciones generales promedio de cerveza normal y helada y clara artesanal son muy cercanas (3,86 y 3,88), por lo que no sería apropiado afirmar una diferencia sustancial únicamente con este resumen.
set.seed(121)
muestra_grafica <- beer2[sample(.N, min(.N, 100000))]
ggplot(muestra_grafica, aes(x = tipo, y = precio, fill = tipo)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.15) +
coord_flip() +
labs(title = "Precio según tipo de cerveza",
subtitle = "Visualización basada en una muestra aleatoria de 100.000 reseñas",
x = NULL, y = "Precio") +
theme_minimal()
comparacion_origen <- beer2[, lapply(.SD, mean), by = origen,
.SDcols = c(variables_cuantitativas, variables_ordinales)]
comparacion_origen[, (names(comparacion_origen)[-1]) :=
lapply(.SD, round, 2), .SDcols = -1]
kable(comparacion_origen)
| origen | precio | alcohol | carbohidratos | calorias | calificacion | aroma | apariencia | paladar | sabor |
|---|---|---|---|---|---|---|---|---|---|
| importada | 5.46 | 18.71 | 14.02 | 193.06 | 3.81 | 3.73 | 3.84 | 3.74 | 3.79 |
| nacional | 4.54 | 18.73 | 14.24 | 194.06 | 3.85 | 3.77 | 3.88 | 3.77 | 3.82 |
Las cervezas importadas tienen mayor precio promedio (5,47) que las nacionales (4,54). En alcohol, carbohidratos y calorías los promedios son cercanos. Las cervezas nacionales presentan valoraciones promedio ligeramente superiores en los cinco atributos; sin embargo, las diferencias son pequeñas y la mediana es 4,0 para ambos orígenes. Estos resultados describen la muestra y no demuestran que el origen produzca mejores valoraciones.
ggplot(muestra_grafica, aes(x = origen, y = precio, fill = origen)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.15) +
labs(title = "Precio según origen",
subtitle = "Visualización basada en una muestra aleatoria de 100.000 reseñas",
x = NULL, y = "Precio") +
theme_minimal()