1 Resumen ejecutivo

  • La base analizada contiene 1.586.614 reseñas de cerveza, correspondientes a 5.743 marcas y 56.857 productos distintos.
  • El 89% de las reseñas son de cerveza importada y el 83% se concentra en solo dos tipos de producto: cerveza normal y helada y clara artesanal.
  • Las valoraciones de los usuarios (calificación, aroma, apariencia, paladar, sabor) están sesgadas hacia puntajes altos: la moda es 4 (sobre 5) en las cinco variables.
  • Las cervezas de tipo clara artesanal obtienen las mejores calificaciones y el precio simulado más alto; las bajas en calorías / sin alcohol obtienen las calificaciones más bajas.
  • alcohol y calorias muestran asimetría positiva relevante, por lo que se prioriza la mediana y el rango intercuartílico sobre la media y la desviación estándar para resumirlas.

2 Introducción

Una empresa cervecera busca comprender las preferencias de sus consumidores y qué características del producto se asocian con mejores valoraciones, como insumo para decisiones de portafolio y comunicación. Este informe presenta un diagnóstico descriptivo de la base beer2, que reúne reseñas de cerveza con información de identificación, composición nutricional, procedencia y valoración.

3 Datos y metodología

dim(beer2)
sum(is.na(beer2))
length(unique(beer2$marca))
length(unique(beer2$nombre_cerveza))

La base contiene 1.586.614 filas (reseñas) y 15 columnas. Se verificó que no existen valores faltantes en ninguna variable. Cada reseña corresponde a una combinación marca–producto–usuario, por lo que una misma cerveza puede tener múltiples registros.

La tabla siguiente resume el tipo y contenido de cada variable:

diccionario <- 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", "Cuantitativa continua (simulada)",
           "Cuantitativa continua", "Cuantitativa continua", "Cuantitativa discreta",
           "Cualitativa nominal", "Cualitativa ordinal", "Cualitativa ordinal",
           "Cualitativa ordinal", "Cualitativa ordinal", "Cualitativa ordinal",
           "Cualitativa nominal", "Cualitativa nominal", "Cualitativa nominal dicotómica"),
  Descripcion = c(
    "Código del producto reseñado",
    "Cervecería productora",
    "Precio de referencia de una caja de 6 botellas de 355 ml",
    "Gramos de alcohol puro en 355 ml",
    "Gramos de carbohidratos en 355 ml",
    "Calorías totales en 355 ml",
    "País de la cervecería",
    "Valoración general de la experiencia",
    "Valoración del aroma",
    "Valoración de la apariencia",
    "Valoración en el paladar",
    "Valoración del sabor",
    "Nombre comercial del producto",
    "Categoría del producto",
    "Nacional o importada"
  )
)
knitr::kable(diccionario, caption = "Tabla 1. Variables de la base beer2")
Tabla 1. Variables de la base beer2
Variable Tipo Descripcion
id Identificador Código del producto reseñado
marca Cualitativa nominal Cervecería productora
precio Cuantitativa continua (simulada) Precio de referencia de una caja de 6 botellas de 355 ml
alcohol Cuantitativa continua Gramos de alcohol puro en 355 ml
carbohidratos Cuantitativa continua Gramos de carbohidratos en 355 ml
calorias Cuantitativa discreta Calorías totales en 355 ml
nacionalidad Cualitativa nominal País de la cervecería
calificacion Cualitativa ordinal Valoración general de la experiencia
aroma Cualitativa ordinal Valoración del aroma
apariencia Cualitativa ordinal Valoración de la apariencia
paladar Cualitativa ordinal Valoración en el paladar
sabor Cualitativa ordinal Valoración del sabor
nombre_cerveza Cualitativa nominal Nombre comercial del producto
tipo Cualitativa nominal Categoría del producto
origen Cualitativa nominal dicotómica Nacional o importada

Todos los cálculos se realizaron en R base (funciones table, prop.table, aggregate, quantile, sd, hist, boxplot); el código completo se incluye en el anexo al final del documento.

4 Perfil general de la muestra

4.1 Tipo y origen de las cervezas reseñadas

t_tipo   <- sort(table(beer2$tipo), decreasing = TRUE)
t_origen <- sort(table(beer2$origen), decreasing = TRUE)

par(mfrow = c(1, 2), mar = c(8, 4, 3, 1))
barplot(as.vector(t_tipo), names.arg = names(t_tipo), las = 2,
        col = "steelblue", main = "Reseñas por tipo de cerveza",
        ylab = "Número de reseñas", cex.names = 0.8)
barplot(as.vector(t_origen), names.arg = names(t_origen), las = 1,
        col = "steelblue", main = "Reseñas por origen",
        ylab = "Número de reseñas")

par(mfrow = c(1, 1))
tabla_tipo <- data.frame(
  Tipo = names(t_tipo),
  Frecuencia = as.vector(t_tipo),
  Porcentaje = round(prop.table(t_tipo) * 100, 2)
)
knitr::kable(tabla_tipo, row.names = FALSE,
             caption = "Tabla 2. Frecuencia de reseñas por tipo de cerveza")
Tabla 2. Frecuencia de reseñas por tipo de cerveza
Tipo Frecuencia Porcentaje.Var1 Porcentaje.Freq
cerveza normal y helada 839088 cerveza normal y helada 52.89
clara artesanal 483464 clara artesanal 30.47
lager importada 219194 lager importada 13.82
lager artesanal 22725 lager artesanal 1.43
baja en calorías / sin alcohol 22143 baja en calorías / sin alcohol 1.40

Más de la mitad de las reseñas corresponde a cerveza normal y helada (≈53%), seguida de clara artesanal (≈30%); entre ambas concentran más del 80% de los registros (moda: cerveza normal y helada). Las categorías lager artesanal y baja en calorías / sin alcohol son minoritarias (≈1,4% cada una). En cuanto al origen, el 89% de las reseñas son de cerveza importada frente a solo 11% de nacional (moda: importada): la base está claramente desbalanceada en esta variable.

4.2 Procedencia geográfica y concentración de marcas

t_nac <- sort(table(beer2$nacionalidad), decreasing = TRUE)
tabla_nac <- data.frame(
  Pais = names(t_nac),
  Frecuencia = as.vector(t_nac),
  Porcentaje = round(prop.table(t_nac) * 100, 2)
)
knitr::kable(tabla_nac, row.names = FALSE,
             caption = "Tabla 3. Reseñas por nacionalidad de la cervecería (10 países)")
Tabla 3. Reseñas por nacionalidad de la cervecería (10 países)
Pais Frecuencia Porcentaje.Var1 Porcentaje.Freq
Austria 201941 Austria 12.73
Bélgica 188677 Bélgica 11.89
Francia 181574 Francia 11.44
Estados Unidos 174165 Estados Unidos 10.98
Inglaterra 162644 Inglaterra 10.25
Canadá 159508 Canadá 10.05
Japón 155273 Japón 9.79
Alemania 121684 Alemania 7.67
Irlanda 120742 Irlanda 7.61
República Checa 120406 República Checa 7.59
t_marca <- sort(table(beer2$marca), decreasing = TRUE)
tabla_marca <- data.frame(
  Marca = names(head(t_marca, 10)),
  Frecuencia = as.vector(head(t_marca, 10)),
  Porcentaje = round(prop.table(t_marca)[1:10] * 100, 2)
)
knitr::kable(tabla_marca, row.names = FALSE,
             caption = "Tabla 4. Top 10 marcas con más reseñas (de 5.743 en total)")
Tabla 4. Top 10 marcas con más reseñas (de 5.743 en total)
Marca Frecuencia Porcentaje.Var1 Porcentaje.Freq
Boston Beer Company (Samuel Adams) 39444 Boston Beer Company (Samuel Adams) 2.49
Dogfish Head Brewery 33839 Dogfish Head Brewery 2.13
Stone Brewing Co. 33066 Stone Brewing Co. 2.08
Sierra Nevada Brewing Co. 28751 Sierra Nevada Brewing Co. 1.81
Bell’s Brewery, Inc. 25191 Bell’s Brewery, Inc. 1.59
Rogue Ales 24083 Rogue Ales 1.52
Founders Brewing Company 20004 Founders Brewing Company 1.26
Victory Brewing Company 19479 Victory Brewing Company 1.23
Lagunitas Brewing Company 16837 Lagunitas Brewing Company 1.06
Avery Brewing Company 16107 Avery Brewing Company 1.02

La variable nacionalidad reúne solo 10 países con una distribución relativamente equilibrada (entre ≈7,6% y ≈12,7% cada uno; moda: Austria), sin un país claramente dominante. El mercado de marcas, en cambio, está muy fragmentado: aun la más reseñada (Boston Beer Company / Samuel Adams) no alcanza el 2,5% del total, y existen 5.743 cervecerías distintas. La variable nombre_cerveza (56.857 productos distintos) funciona como identificador del producto —igual que id— más que como variable de interés estadístico, por lo que no se calculan frecuencias completas para ella.

5 Percepción de los consumidores

Las cinco variables de valoración (calificacion, aroma, apariencia, paladar, sabor) se miden en una escala de 1 a 5, con incrementos de 0,5.

niveles <- sort(unique(unlist(lapply(beer2[ordinales], unique))))
tabla_ord <- sapply(ordinales, function(v) {
  t <- table(factor(beer2[[v]], levels = niveles))
  round(as.vector(prop.table(t)) * 100, 2)
})
rownames(tabla_ord) <- niveles
knitr::kable(tabla_ord,
             caption = "Tabla 5. Distribución porcentual (%) de las variables de valoración")
Tabla 5. Distribución porcentual (%) de las variables de valoración
calificacion aroma apariencia paladar sabor
0 0.00 0.00 0.00 0.00 0.00
1 0.69 0.43 0.21 0.43 0.63
1.5 0.82 0.79 0.39 0.70 0.95
2 2.41 2.68 1.60 2.42 2.65
2.5 3.69 4.18 2.49 3.96 4.19
3 10.44 12.61 10.46 13.04 10.52
3.5 19.02 23.02 20.08 21.34 20.45
4 36.73 35.13 42.49 38.24 34.12
4.5 20.45 17.11 18.16 15.95 21.19
5 5.76 4.04 4.12 3.92 5.29
boxplot(beer2[ordinales], col = "lightgreen",
        main = "Distribución de las variables de valoración")

Las cinco variables muestran un patrón muy similar: la moda es 4 en todas ellas y la mayor concentración de respuestas está entre 3,5 y 4,5. Las calificaciones bajas (1 a 2) son poco frecuentes, lo que sugiere un sesgo hacia valoraciones positivas, típico de plataformas de reseñas donde los usuarios tienden a comentar productos que les gustaron. También se observan unos pocos registros extremos (7 en calificacion y 7 en apariencia) con valor 0; su frecuencia es tan baja (< 0,001%) que no afecta materialmente los resultados, pero conviene señalarlos.

6 Características cuantitativas de las cervezas

resumen <- data.frame(
  Variable  = cuant,
  Media     = sapply(cuant, function(v) mean(beer2[[v]])),
  Mediana   = sapply(cuant, function(v) median(beer2[[v]])),
  Q1        = sapply(cuant, function(v) quantile(beer2[[v]], .25)),
  Q3        = sapply(cuant, function(v) quantile(beer2[[v]], .75)),
  IQR       = sapply(cuant, function(v) IQR(beer2[[v]])),
  DesvEst   = sapply(cuant, function(v) sd(beer2[[v]])),
  CoefVar_pct = sapply(cuant, function(v) sd(beer2[[v]]) / mean(beer2[[v]]) * 100),
  Asimetria = sapply(cuant, function(v) asimetria(beer2[[v]]))
)
rownames(resumen) <- NULL
knitr::kable(resumen, digits = 2,
             caption = "Tabla 6. Estadísticos descriptivos de las variables cuantitativas")
Tabla 6. Estadísticos descriptivos de las variables cuantitativas
Variable Media Mediana Q1 Q3 IQR DesvEst CoefVar_pct Asimetria
precio 5.36 5.41 4.98 5.82 0.84 0.65 12.11 -0.47
alcohol 18.71 17.67 14.28 22.63 8.35 5.46 29.16 0.96
carbohidratos 14.05 13.80 12.40 15.60 3.20 2.38 16.91 0.46
calorias 193.17 182.00 157.00 224.00 67.00 46.57 24.11 0.92
par(mfrow = c(2, 2))
for (v in cuant) {
  hist(beer2[[v]], main = paste("Histograma de", v), xlab = v,
       col = "steelblue", border = "white")
}

par(mfrow = c(1, 1))

El precio (simulado) y los carbohidratos presentan distribuciones casi simétricas (asimetría entre -0,47 y 0,46), con media y mediana muy cercanas; para ambas, la media y la desviación estándar son medidas resumen adecuadas. El alcohol y las calorías, en cambio, muestran asimetría positiva moderada (≈0,96 y ≈0,92, cola hacia la derecha) y mayor coeficiente de variación (≈29% y ≈24%): unas pocas cervezas artesanales con alto contenido alcohólico o calórico alargan la cola superior y elevan la media por encima de la mediana. Por ello, para estas dos variables se recomienda priorizar la mediana y el rango intercuartílico (IQR) frente a la media y la desviación estándar.

7 Comparación entre tipos y orígenes

media_tipo   <- aggregate(beer2[vars_comp], by = list(Tipo = beer2$tipo), FUN = mean)
mediana_tipo <- aggregate(beer2[vars_comp], by = list(Tipo = beer2$tipo), FUN = median)
names(mediana_tipo)[-1] <- paste0(names(mediana_tipo)[-1], "_mediana")
names(media_tipo)[-1]   <- paste0(names(media_tipo)[-1], "_media")
tabla_tipo_comp <- merge(media_tipo, mediana_tipo, by = "Tipo")

knitr::kable(tabla_tipo_comp, digits = 2,
             caption = "Tabla 7. Media y mediana de los indicadores según tipo de cerveza")
Tabla 7. Media y mediana de los indicadores según tipo de cerveza
Tipo precio_media alcohol_media carbohidratos_media calorias_media calificacion_media precio_mediana alcohol_mediana carbohidratos_mediana calorias_mediana calificacion_mediana
baja en calorías / sin alcohol 4.28 9.84 8.66 109.5 2.95 4.25 11.07 8.7 116 3
cerveza normal y helada 5.27 20.10 14.29 203.8 3.86 5.34 18.94 14.1 198 4
clara artesanal 5.70 18.15 14.51 191.1 3.88 5.78 17.41 14.3 184 4
lager artesanal 4.55 15.67 13.54 169.9 3.64 4.54 13.75 13.1 158 4
lager importada 5.17 15.86 12.71 167.8 3.61 5.24 14.28 12.6 156 4
media_origen   <- aggregate(beer2[vars_comp], by = list(Origen = beer2$origen), FUN = mean)
mediana_origen <- aggregate(beer2[vars_comp], by = list(Origen = beer2$origen), FUN = median)
names(mediana_origen)[-1] <- paste0(names(mediana_origen)[-1], "_mediana")
names(media_origen)[-1]   <- paste0(names(media_origen)[-1], "_media")
tabla_origen_comp <- merge(media_origen, mediana_origen, by = "Origen")

knitr::kable(tabla_origen_comp, digits = 2,
             caption = "Tabla 8. Media y mediana de los indicadores según origen")
Tabla 8. Media y mediana de los indicadores según origen
Origen precio_media alcohol_media carbohidratos_media calorias_media calificacion_media precio_mediana alcohol_mediana carbohidratos_mediana calorias_mediana calificacion_mediana
importada 5.46 18.71 14.02 193.1 3.81 5.50 17.41 13.8 182 4
nacional 4.54 18.73 14.24 194.1 3.85 4.54 17.93 14.1 188 4
par(mfrow = c(1, 2), mar = c(8, 4, 3, 1))
boxplot(calificacion ~ tipo, data = beer2, las = 2, cex.axis = 0.7,
        main = "Calificación según tipo", col = "lightgreen", xlab = "")
boxplot(alcohol ~ origen, data = beer2,
        main = "Alcohol según origen", col = "lightgoldenrod")

par(mfrow = c(1, 1))
knitr::kable(table(beer2$tipo, beer2$origen),
             caption = "Tabla 9. Número de reseñas por tipo y origen")
Tabla 9. Número de reseñas por tipo y origen
importada nacional
baja en calorías / sin alcohol 20432 1711
cerveza normal y helada 754796 84292
clara artesanal 418027 65437
lager artesanal 0 22725
lager importada 219194 0

El tipo baja en calorías / sin alcohol tiene en promedio el menor contenido de alcohol, carbohidratos y calorías, y también la calificación promedio más baja (≈2,95 sobre 5); en esta base, las cervezas más ligeras tienden a ser peor valoradas. El tipo clara artesanal tiene el precio simulado promedio más alto (≈5,71) y, junto con cerveza normal y helada, las mejores calificaciones promedio (≈3,88 y ≈3,86). Al cruzar tipo con origen aparece una relación estructural relevante (Tabla 9): toda la categoría lager artesanal es de origen nacional y toda la categoría lager importada es de origen importado; para estos dos tipos, tipo determina por definición el origen, por lo que las comparaciones entre ambas variables no son totalmente independientes para esas categorías. Comparando directamente por origen, las cervezas nacionales obtienen una calificación levemente superior (≈3,85 frente a ≈3,81) y un precio simulado menor (≈4,54 frente a ≈5,47) que las importadas, aunque el alcohol y las calorías son muy similares entre ambos grupos.

8 Conclusiones

  • La base está dominada por cerveza importada (89%) y por dos tipos de producto (cerveza normal y helada y clara artesanal, >80% combinado), mientras que la nacionalidad está relativamente equilibrada entre 10 países y el mercado de marcas está muy fragmentado (ninguna supera el 2,5% de las reseñas).
  • Las variables de valoración muestran un sesgo hacia calificaciones altas (moda = 4 en las cinco), un patrón común en plataformas de reseñas.
  • Las cervezas artesanales tienden a obtener mejores calificaciones y mayor precio promedio; las bajas en calorías/sin alcohol presentan las calificaciones más bajas.
  • Para alcohol y calorias, cuya distribución es asimétrica hacia la derecha, se recomienda reportar mediana e IQR en lugar de media y desviación estándar.
  • Este es un análisis descriptivo, no experimental: las asociaciones encontradas (por ejemplo, entre tipo de cerveza y calificación) no implican causalidad y pueden estar influenciadas por factores no observados (perfil de quien reseña, popularidad previa de la marca, autoselección de los productos comentados, etc.).