Este informe tiene como objetivo hacer un primer diagnóstico descriptivo sobre una base de datos de reseñas de cerveza, a petición de una empresa del sector cervecero que busca entender mejor las preferencias de los consumidores.
La base de datos beer2.csv contiene 1.586.614
reseñas y 15 variables que cubren desde
información del producto (tipo, marca, origen, composición nutricional)
hasta valoraciones sensoriales dadas por los consumidores (aroma, sabor,
apariencia, paladar y calificación general). Cada fila es una reseña,
así que una misma cerveza puede aparecer muchas veces si tiene varias
reseñas.
Es importante aclarar que la variable precio fue
simulada, por lo que los resultados sobre precios aplican solo dentro de
esta base y no se deben tomar como datos reales del mercado. Además, al
tratarse de un análisis descriptivo, lo que podemos hacer es identificar
patrones y diferencias, pero no podemos afirmar que una variable
cause cambios en otra.
library(tidyverse)
library(knitr)
library(kableExtra)
library(scales)
beer <- read_csv("beer2.csv")
Verificamos que todo se haya cargado correctamente:
dim(beer)
## [1] 1586614 15
sum(is.na(beer))
## [1] 0
Son 1,586,614 filas y 15 columnas, sin datos faltantes. Ahora vemos las primeras filas para familiarizarnos con la estructura:
head(beer, 8) %>%
kable() %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, font_size = 12) %>%
scroll_box(width = "100%")
| id | marca | precio | alcohol | carbohidratos | calorias | nacionalidad | calificacion | aroma | apariencia | paladar | sabor | nombre_cerveza | tipo | origen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 47986 | Vecchio Birraio | 4.99 | 13.75 | 11.5 | 148 | Canadá | 1.5 | 2.0 | 2.5 | 1.5 | 1.5 | Sausa Weizen | clara artesanal | importada |
| 48213 | Vecchio Birraio | 4.45 | 16.90 | 14.2 | 181 | Canadá | 3.0 | 2.5 | 3.0 | 3.0 | 3.0 | Red Moon | cerveza normal y helada | importada |
| 48215 | Vecchio Birraio | 4.95 | 17.67 | 15.0 | 190 | Canadá | 3.0 | 2.5 | 3.0 | 3.0 | 3.0 | Black Horse Black Beer | cerveza normal y helada | importada |
| 47969 | Vecchio Birraio | 5.58 | 13.75 | 10.5 | 144 | Canadá | 3.0 | 3.0 | 3.5 | 2.5 | 3.0 | Sausa Pils | lager importada | importada |
| 64883 | Caldera Brewing Company | 3.90 | 20.69 | 15.2 | 212 | Canadá | 4.0 | 4.5 | 4.0 | 4.0 | 4.5 | Cauldron DIPA | clara artesanal | importada |
| 52159 | Caldera Brewing Company | 5.07 | 12.95 | 12.1 | 145 | Canadá | 3.0 | 3.5 | 3.5 | 3.0 | 3.5 | Caldera Ginger Beer | cerveza normal y helada | importada |
| 52159 | Caldera Brewing Company | 5.07 | 12.95 | 12.1 | 145 | Canadá | 3.5 | 3.5 | 3.5 | 4.0 | 4.0 | Caldera Ginger Beer | cerveza normal y helada | importada |
| 52159 | Caldera Brewing Company | 5.07 | 12.95 | 12.1 | 145 | Canadá | 3.0 | 2.5 | 3.5 | 2.0 | 3.5 | Caldera Ginger Beer | cerveza normal y helada | importada |
glimpse(beer)
## Rows: 1,586,614
## Columns: 15
## $ id <dbl> 47986, 48213, 48215, 47969, 64883, 52159, 52159, 52159,…
## $ marca <chr> "Vecchio Birraio", "Vecchio Birraio", "Vecchio Birraio"…
## $ precio <dbl> 4.99, 4.45, 4.95, 5.58, 3.90, 5.07, 5.07, 5.07, 5.07, 5…
## $ alcohol <dbl> 13.75, 16.90, 17.67, 13.75, 20.69, 12.95, 12.95, 12.95,…
## $ carbohidratos <dbl> 11.5, 14.2, 15.0, 10.5, 15.2, 12.1, 12.1, 12.1, 12.1, 1…
## $ calorias <dbl> 148, 181, 190, 144, 212, 145, 145, 145, 145, 145, 112, …
## $ nacionalidad <chr> "Canadá", "Canadá", "Canadá", "Canadá", "Canadá", "Cana…
## $ calificacion <dbl> 1.5, 3.0, 3.0, 3.0, 4.0, 3.0, 3.5, 3.0, 4.0, 4.5, 3.0, …
## $ aroma <dbl> 2.0, 2.5, 2.5, 3.0, 4.5, 3.5, 3.5, 2.5, 3.0, 3.5, 2.0, …
## $ apariencia <dbl> 2.5, 3.0, 3.0, 3.5, 4.0, 3.5, 3.5, 3.5, 3.5, 5.0, 3.0, …
## $ paladar <dbl> 1.5, 3.0, 3.0, 2.5, 4.0, 3.0, 4.0, 2.0, 3.5, 4.0, 2.5, …
## $ sabor <dbl> 1.5, 3.0, 3.0, 3.0, 4.5, 3.5, 4.0, 3.5, 4.0, 4.0, 2.5, …
## $ nombre_cerveza <chr> "Sausa Weizen", "Red Moon", "Black Horse Black Beer", "…
## $ tipo <chr> "clara artesanal", "cerveza normal y helada", "cerveza …
## $ origen <chr> "importada", "importada", "importada", "importada", "im…
Según el enunciado, las variables se clasifican de la siguiente forma:
data.frame(
Variable = c("id", "marca", "precio", "alcohol", "carbohidratos", "calorias",
"nacionalidad", "calificacion", "aroma", "apariencia", "paladar",
"sabor", "nombre_cerveza", "tipo", "origen"),
Tipo = c("Identificador (Cualitativa nominal)",
"Cualitativa nominal",
"Cuantitativa de razón",
"Cuantitativa de razón",
"Cuantitativa de razón",
"Cuantitativa de razón",
"Cualitativa nominal",
"Cualitativa ordinal",
"Cualitativa ordinal",
"Cualitativa ordinal",
"Cualitativa ordinal",
"Cualitativa ordinal",
"Cualitativa nominal",
"Cualitativa nominal",
"Cualitativa nominal")
) %>%
kable() %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Variable | Tipo |
|---|---|
| id | Identificador (Cualitativa nominal) |
| marca | Cualitativa nominal |
| precio | Cuantitativa de razón |
| alcohol | Cuantitativa de razón |
| carbohidratos | Cuantitativa de razón |
| calorias | Cuantitativa de razón |
| nacionalidad | Cualitativa nominal |
| calificacion | Cualitativa ordinal |
| aroma | Cualitativa ordinal |
| apariencia | Cualitativa ordinal |
| paladar | Cualitativa ordinal |
| sabor | Cualitativa ordinal |
| nombre_cerveza | Cualitativa nominal |
| tipo | Cualitativa nominal |
| origen | Cualitativa nominal |
Para cada variable cualitativa se construyen tablas de frecuencias absolutas y relativas, y se identifica la moda.
tabla_tipo <- beer %>%
count(tipo) %>%
arrange(desc(n)) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_tipo %>%
kable(col.names = c("Tipo", "Frecuencia absoluta", "Frecuencia relativa", "Porcentaje (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Tipo | Frecuencia absoluta | Frecuencia relativa | Porcentaje (%) |
|---|---|---|---|
| cerveza normal y helada | 839088 | 0.5288545 | 52.89 |
| clara artesanal | 483464 | 0.3047143 | 30.47 |
| lager importada | 219194 | 0.1381521 | 13.82 |
| lager artesanal | 22725 | 0.0143230 | 1.43 |
| baja en calorías / sin alcohol | 22143 | 0.0139561 | 1.40 |
La moda es cerveza normal y helada con 839,088 reseñas.
ggplot(tabla_tipo, aes(x = reorder(tipo, n), y = n)) +
geom_col(fill = "steelblue") +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(x = NULL, y = "Cantidad de reseñas", title = "Reseñas por tipo de cerveza") +
theme_minimal()
tabla_origen <- beer %>%
count(origen) %>%
arrange(desc(n)) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_origen %>%
kable(col.names = c("Origen", "Frecuencia absoluta", "Frecuencia relativa", "Porcentaje (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Origen | Frecuencia absoluta | Frecuencia relativa | Porcentaje (%) |
|---|---|---|---|
| importada | 1412449 | 0.8902285 | 89.02 |
| nacional | 174165 | 0.1097715 | 10.98 |
La moda es importada.
ggplot(tabla_origen, aes(x = reorder(origen, n), y = n)) +
geom_col(fill = "darkgreen", width = 0.5) +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(x = NULL, y = "Cantidad de reseñas", title = "Reseñas por origen") +
theme_minimal()
Como hay muchas nacionalidades, mostramos las 15 con más reseñas:
tabla_nac <- beer %>%
count(nacionalidad) %>%
arrange(desc(n)) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_nac %>%
head(15) %>%
kable(col.names = c("Nacionalidad", "Frec. absoluta", "Frec. relativa", "Porcentaje (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Nacionalidad | Frec. absoluta | Frec. relativa | Porcentaje (%) |
|---|---|---|---|
| Austria | 201941 | 0.1272780 | 12.73 |
| Bélgica | 188677 | 0.1189180 | 11.89 |
| Francia | 181574 | 0.1144412 | 11.44 |
| Estados Unidos | 174165 | 0.1097715 | 10.98 |
| Inglaterra | 162644 | 0.1025101 | 10.25 |
| Canadá | 159508 | 0.1005336 | 10.05 |
| Japón | 155273 | 0.0978644 | 9.79 |
| Alemania | 121684 | 0.0766941 | 7.67 |
| Irlanda | 120742 | 0.0761004 | 7.61 |
| República Checa | 120406 | 0.0758887 | 7.59 |
La moda es Austria.
tabla_nac %>%
head(10) %>%
ggplot(aes(x = reorder(nacionalidad, n), y = n)) +
geom_col(fill = "mediumpurple") +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(x = NULL, y = "Cantidad de reseñas", title = "Top 10 nacionalidades") +
theme_minimal()
Las variables de valoración (calificación, aroma, apariencia, paladar y sabor) son ordinales. Construimos la tabla de frecuencias de cada una para ver cómo se distribuyen las puntuaciones.
tabla_calif <- beer %>%
count(calificacion) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_calif %>%
kable(col.names = c("Calificación", "Frec. absoluta", "Frec. relativa", "%")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Calificación | Frec. absoluta | Frec. relativa | % |
|---|---|---|---|
| 0.0 | 7 | 0.0000044 | 0.00 |
| 1.0 | 10954 | 0.0069040 | 0.69 |
| 1.5 | 12975 | 0.0081778 | 0.82 |
| 2.0 | 38225 | 0.0240922 | 2.41 |
| 2.5 | 58523 | 0.0368855 | 3.69 |
| 3.0 | 165644 | 0.1044009 | 10.44 |
| 3.5 | 301817 | 0.1902271 | 19.02 |
| 4.0 | 582764 | 0.3673004 | 36.73 |
| 4.5 | 324385 | 0.2044511 | 20.45 |
| 5.0 | 91320 | 0.0575565 | 5.76 |
La moda de calificación es 4 para las variables ordinales en general.
tabla_aroma <- beer %>%
count(aroma) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_aroma %>%
kable(col.names = c("Aroma", "Frec. absoluta", "Frec. relativa", "%")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Aroma | Frec. absoluta | Frec. relativa | % |
|---|---|---|---|
| 1.0 | 6873 | 0.0043319 | 0.43 |
| 1.5 | 12524 | 0.0078935 | 0.79 |
| 2.0 | 42566 | 0.0268282 | 2.68 |
| 2.5 | 66359 | 0.0418243 | 4.18 |
| 3.0 | 200030 | 0.1260735 | 12.61 |
| 3.5 | 365312 | 0.2302463 | 23.02 |
| 4.0 | 557383 | 0.3513035 | 35.13 |
| 4.5 | 271450 | 0.1710876 | 17.11 |
| 5.0 | 64117 | 0.0404112 | 4.04 |
La moda de aroma es 4.
tabla_apariencia <- beer %>%
count(apariencia) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_apariencia %>%
kable(col.names = c("Apariencia", "Frec. absoluta", "Frec. relativa", "%")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Apariencia | Frec. absoluta | Frec. relativa | % |
|---|---|---|---|
| 0.0 | 7 | 0.0000044 | 0.00 |
| 1.0 | 3323 | 0.0020944 | 0.21 |
| 1.5 | 6147 | 0.0038743 | 0.39 |
| 2.0 | 25414 | 0.0160178 | 1.60 |
| 2.5 | 39493 | 0.0248914 | 2.49 |
| 3.0 | 166009 | 0.1046310 | 10.46 |
| 3.5 | 318529 | 0.2007602 | 20.08 |
| 4.0 | 674186 | 0.4249212 | 42.49 |
| 4.5 | 288108 | 0.1815867 | 18.16 |
| 5.0 | 65398 | 0.0412186 | 4.12 |
La moda de apariencia es 4.
tabla_paladar <- beer %>%
count(paladar) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_paladar %>%
kable(col.names = c("Paladar", "Frec. absoluta", "Frec. relativa", "%")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Paladar | Frec. absoluta | Frec. relativa | % |
|---|---|---|---|
| 1.0 | 6874 | 0.0043325 | 0.43 |
| 1.5 | 11045 | 0.0069614 | 0.70 |
| 2.0 | 38333 | 0.0241603 | 2.42 |
| 2.5 | 62842 | 0.0396076 | 3.96 |
| 3.0 | 206932 | 0.1304237 | 13.04 |
| 3.5 | 338585 | 0.2134010 | 21.34 |
| 4.0 | 606711 | 0.3823936 | 38.24 |
| 4.5 | 253102 | 0.1595234 | 15.95 |
| 5.0 | 62190 | 0.0391967 | 3.92 |
La moda de paladar es 4.
tabla_sabor <- beer %>%
count(sabor) %>%
mutate(frecuencia_relativa = n / sum(n),
porcentaje = round(frecuencia_relativa * 100, 2))
tabla_sabor %>%
kable(col.names = c("Sabor", "Frec. absoluta", "Frec. relativa", "%")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Sabor | Frec. absoluta | Frec. relativa | % |
|---|---|---|---|
| 1.0 | 9991 | 0.0062971 | 0.63 |
| 1.5 | 15128 | 0.0095348 | 0.95 |
| 2.0 | 41992 | 0.0264664 | 2.65 |
| 2.5 | 66534 | 0.0419346 | 4.19 |
| 3.0 | 166860 | 0.1051674 | 10.52 |
| 3.5 | 324541 | 0.2045494 | 20.45 |
| 4.0 | 541429 | 0.3412481 | 34.12 |
| 4.5 | 336162 | 0.2118738 | 21.19 |
| 5.0 | 83977 | 0.0529284 | 5.29 |
La moda de sabor es 4.
Para tener un panorama general de las cinco variables ordinales juntas:
beer %>%
select(calificacion, aroma, apariencia, paladar, sabor) %>%
pivot_longer(everything(), names_to = "variable", values_to = "valor") %>%
count(variable, valor) %>%
ggplot(aes(x = factor(valor), y = n)) +
geom_col(fill = "coral") +
facet_wrap(~ variable, scales = "free_y", ncol = 2) +
scale_y_continuous(labels = comma) +
labs(x = "Puntuación", y = "Frecuencia",
title = "Distribución de las valoraciones sensoriales") +
theme_minimal()
Para las variables cuantitativas (precio, alcohol, carbohidratos y calorías) calculamos indicadores de tendencia central, posición y dispersión.
# Armamos la tabla manualmente para cada variable
resumen <- data.frame(
Variable = c("precio", "alcohol", "carbohidratos", "calorias"),
Media = c(round(mean(beer$precio), 2),
round(mean(beer$alcohol), 2),
round(mean(beer$carbohidratos), 2),
round(mean(beer$calorias), 2)),
Mediana = c(round(median(beer$precio), 2),
round(median(beer$alcohol), 2),
round(median(beer$carbohidratos), 2),
round(median(beer$calorias), 2)),
Desv_Est = c(round(sd(beer$precio), 2),
round(sd(beer$alcohol), 2),
round(sd(beer$carbohidratos), 2),
round(sd(beer$calorias), 2)),
Min = c(round(min(beer$precio), 2),
round(min(beer$alcohol), 2),
round(min(beer$carbohidratos), 2),
round(min(beer$calorias), 2)),
Q1 = c(round(quantile(beer$precio, 0.25), 2),
round(quantile(beer$alcohol, 0.25), 2),
round(quantile(beer$carbohidratos, 0.25), 2),
round(quantile(beer$calorias, 0.25), 2)),
Q3 = c(round(quantile(beer$precio, 0.75), 2),
round(quantile(beer$alcohol, 0.75), 2),
round(quantile(beer$carbohidratos, 0.75), 2),
round(quantile(beer$calorias, 0.75), 2)),
Max = c(round(max(beer$precio), 2),
round(max(beer$alcohol), 2),
round(max(beer$carbohidratos), 2),
round(max(beer$calorias), 2)),
RIQ = c(round(IQR(beer$precio), 2),
round(IQR(beer$alcohol), 2),
round(IQR(beer$carbohidratos), 2),
round(IQR(beer$calorias), 2)),
CV = c(round(sd(beer$precio)/mean(beer$precio)*100, 2),
round(sd(beer$alcohol)/mean(beer$alcohol)*100, 2),
round(sd(beer$carbohidratos)/mean(beer$carbohidratos)*100, 2),
round(sd(beer$calorias)/mean(beer$calorias)*100, 2))
)
resumen %>%
kable(col.names = c("Variable", "Media", "Mediana", "Desv. Est.", "Mín.",
"Q1", "Q3", "Máx.", "RIQ", "CV (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Variable | Media | Mediana | Desv. Est. | Mín. | Q1 | Q3 | Máx. | RIQ | CV (%) |
|---|---|---|---|---|---|---|---|---|---|
| precio | 5.00 | 5.00 | 0.89 | 2.37 | 4.36 | 5.64 | 7.72 | 1.28 | 17.71 |
| alcohol | 18.71 | 17.67 | 5.46 | 0.03 | 14.28 | 22.63 | 59.45 | 8.35 | 29.16 |
| carbohidratos | 14.05 | 13.80 | 2.38 | 3.50 | 12.40 | 15.60 | 30.20 | 3.20 | 16.91 |
| calorias | 193.17 | 182.00 | 46.57 | 21.00 | 157.00 | 224.00 | 541.00 | 67.00 | 24.11 |
El Coeficiente de Variación (CV) nos ayuda a saber qué tan dispersos están los datos respecto a la media. Si el CV es bajo (menor a 15%), los datos son bastante homogéneos; si es alto (mayor a 30%), hay mucha variabilidad y probablemente la mediana represente mejor a los datos que la media.
También es importante comparar la media con la mediana: si son muy parecidas, la distribución es simétrica; si la media es mayor que la mediana, hay asimetría hacia la derecha (valores altos que jalan la media) y si la media es menor que la mediana, hay asimetria hacia la izquierda (valores bajos que jalan la media).
beer %>%
select(precio, alcohol, carbohidratos, calorias) %>%
pivot_longer(everything(), names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = valor)) +
geom_histogram(fill = "steelblue", color = "white", bins = 100) +
facet_wrap(~ variable, scales = "free", ncol = 2) +
scale_y_continuous(labels = comma) +
labs(x = "Valor", y = "Frecuencia", title = "Histogramas de variables cuantitativas") +
theme_minimal()
beer %>%
select(precio, alcohol, carbohidratos, calorias) %>%
pivot_longer(everything(), names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = variable, y = valor)) +
geom_boxplot(fill = "steelblue", color = "black", outlier.size = 0.3, outlier.alpha = 0.1) +
facet_wrap(~ variable, scales = "free", ncol = 2) +
labs(x = NULL, y = "Valor", title = "Boxplots de variables cuantitativas") +
theme_minimal()
beer %>%
group_by(tipo) %>%
summarise(
n = n(),
media_precio = round(mean(precio), 2),
mediana_precio = round(median(precio), 2),
de_precio = round(sd(precio), 2),
media_alcohol = round(mean(alcohol), 2),
mediana_alcohol = round(median(alcohol), 2),
de_alcohol = round(sd(alcohol), 2),
media_calorias = round(mean(calorias), 2),
mediana_calorias = round(median(calorias), 2),
de_calorias = round(sd(calorias), 2)
) %>%
kable(caption = "Indicadores por tipo de cerveza") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE, font_size = 11) %>%
scroll_box(width = "100%")
| tipo | n | media_precio | mediana_precio | de_precio | media_alcohol | mediana_alcohol | de_alcohol | media_calorias | mediana_calorias | de_calorias |
|---|---|---|---|---|---|---|---|---|---|---|
| baja en calorías / sin alcohol | 22143 | 4.99 | 4.98 | 0.80 | 9.84 | 11.07 | 2.66 | 109.52 | 116 | 23.04 |
| cerveza normal y helada | 839088 | 4.99 | 4.99 | 0.89 | 20.10 | 18.94 | 5.77 | 203.82 | 198 | 49.05 |
| clara artesanal | 483464 | 5.00 | 4.99 | 0.89 | 18.15 | 17.41 | 4.58 | 191.10 | 184 | 39.24 |
| lager artesanal | 22725 | 5.07 | 5.03 | 0.80 | 15.67 | 13.75 | 3.78 | 169.88 | 158 | 32.87 |
| lager importada | 219194 | 5.03 | 5.05 | 0.89 | 15.86 | 14.28 | 3.84 | 167.84 | 156 | 32.83 |
beer %>%
select(tipo, precio, alcohol, carbohidratos, calorias) %>%
pivot_longer(-tipo, names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = tipo, y = valor, fill = tipo)) +
geom_boxplot(outlier.size = 0.2, outlier.alpha = 0.1, show.legend = FALSE) +
facet_wrap(~ variable, scales = "free_y", ncol = 2) +
labs(x = NULL, y = "Valor", title = "Variables cuantitativas según tipo de cerveza") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 30, hjust = 1, size = 7))
beer %>%
group_by(origen) %>%
summarise(
n = n(),
media_precio = round(mean(precio), 2),
mediana_precio = round(median(precio), 2),
de_precio = round(sd(precio), 2),
media_alcohol = round(mean(alcohol), 2),
mediana_alcohol = round(median(alcohol), 2),
de_alcohol = round(sd(alcohol), 2),
media_calorias = round(mean(calorias), 2),
mediana_calorias = round(median(calorias), 2),
de_calorias = round(sd(calorias), 2)
) %>%
kable(caption = "Indicadores por origen") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| origen | n | media_precio | mediana_precio | de_precio | media_alcohol | mediana_alcohol | de_alcohol | media_calorias | mediana_calorias | de_calorias |
|---|---|---|---|---|---|---|---|---|---|---|
| importada | 1412449 | 5.00 | 5.00 | 0.88 | 18.71 | 17.41 | 5.47 | 193.06 | 182 | 46.72 |
| nacional | 174165 | 5.02 | 5.03 | 0.90 | 18.73 | 17.93 | 5.35 | 194.06 | 188 | 45.31 |
beer %>%
select(origen, precio, alcohol, carbohidratos, calorias) %>%
pivot_longer(-origen, names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = origen, y = valor, fill = origen)) +
geom_boxplot(outlier.size = 0.2, outlier.alpha = 0.1, show.legend = FALSE) +
facet_wrap(~ variable, scales = "free_y", ncol = 2) +
labs(x = NULL, y = "Valor", title = "Variables cuantitativas según origen") +
theme_minimal()
beer %>%
group_by(tipo) %>%
summarise(
mediana_calificacion = median(calificacion),
media_calificacion = round(mean(calificacion), 2),
mediana_aroma = median(aroma),
media_aroma = round(mean(aroma), 2),
mediana_sabor = median(sabor),
media_sabor = round(mean(sabor), 2),
mediana_paladar = median(paladar),
media_paladar = round(mean(paladar), 2),
mediana_apariencia = median(apariencia),
media_apariencia = round(mean(apariencia), 2)
) %>%
kable(caption = "Valoraciones por tipo de cerveza") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE, font_size = 11) %>%
scroll_box(width = "100%")
| tipo | mediana_calificacion | media_calificacion | mediana_aroma | media_aroma | mediana_sabor | media_sabor | mediana_paladar | media_paladar | mediana_apariencia | media_apariencia |
|---|---|---|---|---|---|---|---|---|---|---|
| baja en calorías / sin alcohol | 3 | 2.95 | 2.5 | 2.58 | 2.5 | 2.64 | 2.5 | 2.68 | 3.0 | 2.82 |
| cerveza normal y helada | 4 | 3.86 | 4.0 | 3.85 | 4.0 | 3.90 | 4.0 | 3.83 | 4.0 | 3.94 |
| clara artesanal | 4 | 3.88 | 4.0 | 3.78 | 4.0 | 3.82 | 4.0 | 3.79 | 4.0 | 3.87 |
| lager artesanal | 4 | 3.64 | 3.5 | 3.37 | 3.5 | 3.49 | 3.5 | 3.49 | 3.5 | 3.59 |
| lager importada | 4 | 3.61 | 3.5 | 3.34 | 3.5 | 3.48 | 3.5 | 3.47 | 3.5 | 3.55 |
beer %>%
select(tipo, calificacion, aroma, apariencia, paladar, sabor) %>%
pivot_longer(-tipo, names_to = "atributo", values_to = "puntuacion") %>%
ggplot(aes(x = tipo, y = puntuacion, fill = tipo)) +
geom_boxplot(outlier.size = 0.2, outlier.alpha = 0.1, show.legend = FALSE) +
facet_wrap(~ atributo, scales = "free_y", ncol = 2) +
labs(x = NULL, y = "Puntuación", title = "Valoraciones sensoriales por tipo de cerveza") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 30, hjust = 1, size = 7))
beer %>%
group_by(origen) %>%
summarise(
mediana_calificacion = median(calificacion),
media_calificacion = round(mean(calificacion), 2),
mediana_aroma = median(aroma),
media_aroma = round(mean(aroma), 2),
mediana_sabor = median(sabor),
media_sabor = round(mean(sabor), 2),
mediana_paladar = median(paladar),
media_paladar = round(mean(paladar), 2),
mediana_apariencia = median(apariencia),
media_apariencia = round(mean(apariencia), 2)
) %>%
kable(caption = "Valoraciones por origen") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| origen | mediana_calificacion | media_calificacion | mediana_aroma | media_aroma | mediana_sabor | media_sabor | mediana_paladar | media_paladar | mediana_apariencia | media_apariencia |
|---|---|---|---|---|---|---|---|---|---|---|
| importada | 4 | 3.81 | 4 | 3.73 | 4 | 3.79 | 4 | 3.74 | 4 | 3.84 |
| nacional | 4 | 3.85 | 4 | 3.77 | 4 | 3.82 | 4 | 3.77 | 4 | 3.88 |
beer %>%
select(origen, calificacion, aroma, apariencia, paladar, sabor) %>%
pivot_longer(-origen, names_to = "atributo", values_to = "puntuacion") %>%
ggplot(aes(x = origen, y = puntuacion, fill = origen)) +
geom_boxplot(outlier.size = 0.2, outlier.alpha = 0.1, show.legend = FALSE) +
facet_wrap(~ atributo, scales = "free_y", ncol = 2) +
labs(x = NULL, y = "Puntuación", title = "Valoraciones sensoriales por origen") +
theme_minimal()
A partir del análisis descriptivo realizado se pueden señalar los siguientes patrones generales:
La base de datos está compuesta en su gran mayoría por reseñas de un tipo de cerveza en particular, lo que significa que los promedios generales están fuertemente influenciados por esa categoría. Sería importante tener esto en cuenta si en el futuro se quieren hacer comparaciones más equilibradas.
Al observar las variables cuantitativas, se puede notar que alcohol, carbohidratos y calorías tienden a moverse juntas: las cervezas con más alcohol suelen tener también más carbohidratos y calorías, lo cual tiene sentido desde un punto de vista nutricional. Sin embargo, este informe no puede confirmar una relación causal entre ellas.
En las comparaciones por tipo de cerveza se observan diferencias en los indicadores. Por ejemplo, las cervezas artesanales tienden a presentar valores distintos de alcohol y calorías en comparación con las cervezas bajas en calorías o sin alcohol, lo cual es esperable dada la naturaleza de cada categoría.
Las valoraciones sensoriales (aroma, sabor, paladar, apariencia) muestran patrones similares entre sí: cuando una cerveza recibe buenas puntuaciones en un atributo, suele recibirlas también en los demás. Esto sugiere que la experiencia del consumidor tiende a ser consistente.
Sobre las diferencias por origen (nacional vs. importada), los datos permiten observar si hay alguna tendencia en las valoraciones y la composición, aunque las diferencias podrían deberse a la composición desigual de la base.
Consideraciones finales:
precio es simulada, por lo que las
observaciones sobre precios describen únicamente esta base académica y
no el mercado real.Informe elaborado por Sergio Amaya — 2026-08-11