library(readr) # importación de archivos csv
library(dplyr) # manipulación de datos
library(flextable) # presentación de tablasAsignatura: Teoría de Probabilidades
Docente: Daniel Enrique González Gómez
Institución: Pontificia Universidad Javeriana
Cali
Base de datos: beer2.csv
Este informe presenta el diagnóstico descriptivo inicial solicitado por la dirección de investigación de una empresa del sector cervecero. Se analizaron 1.586.614 reseñas de consumidores sobre 15 variables relativas a la identificación del producto, su composición nutricional, su procedencia, su precio de referencia y las valoraciones sensoriales otorgadas.
Para las variables cualitativas y ordinales se construyeron tablas de frecuencias absolutas, relativas y acumuladas, identificando la moda en cada caso. Para las variables cuantitativas se calcularon indicadores de tendencia central, posición, dispersión y forma, seleccionando en cada caso el indicador apropiado según la simetría observada en la distribución. Finalmente se compararon los indicadores entre tipos y orígenes de cerveza.
Los resultados muestran una base fuertemente concentrada en cerveza normal y helada de origen importado, con valoraciones sensoriales que se agrupan en los niveles altos de las escalas. Entre los atributos evaluados, el sabor y el paladar son los que presentan mayor asociación con la calificación general, mientras que el precio y la composición nutricional muestran asociaciones débiles. Todos los hallazgos son de naturaleza descriptiva y no permiten establecer relaciones causales.
La presente investigación surge del interés de una empresa del sector cervecero por comprender las preferencias expresadas por los consumidores y reconocer qué características de las cervezas se relacionan con mejores valoraciones. Conocer las diferencias según el tipo, el origen, la composición nutricional, el precio y los atributos sensoriales puede aportar evidencia para orientar la selección del portafolio, la comunicación de los productos y futuras decisiones comerciales.
En esta primera aproximación se realiza un análisis descriptivo. Por tanto, los resultados permiten identificar patrones y formular nuevas hipótesis, pero no establecer relaciones causales.
Elaborar un informe descriptivo que sirva como diagnóstico inicial de
las preferencias expresadas por los consumidores de cerveza, a partir
del procesamiento estadístico de la base de datos
beer2.csv.
ficha <- data.frame(
Aspecto = c("Nombre del archivo", "Unidad de observación",
"Número de registros", "Número de variables",
"Datos faltantes", "Marcas o cervecerías distintas",
"Cervezas distintas reseñadas", "Países de procedencia",
"Variables simuladas"),
Detalle = c("beer2.csv",
"Una reseña de un consumidor sobre una cerveza",
format(nrow(cerveza), big.mark = ".", decimal.mark = ","),
as.character(ncol(cerveza)),
format(sum(is.na(cerveza)), big.mark = ".", decimal.mark = ","),
format(n_distinct(cerveza$marca), big.mark = ".", decimal.mark = ","),
format(n_distinct(cerveza$nombre_cerveza), big.mark = ".", decimal.mark = ","),
as.character(n_distinct(cerveza$nacionalidad)),
"precio"),
stringsAsFactors = FALSE
)
flextable(ficha) |>
set_header_labels(Aspecto = "Aspecto", Detalle = "Detalle") |>
theme_booktabs() |>
align(j = 2, align = "left", part = "all") |>
set_caption("Tabla 1. Ficha técnica de la base de datos") |>
autofit()Aspecto | Detalle |
|---|---|
Nombre del archivo | beer2.csv |
Unidad de observación | Una reseña de un consumidor sobre una cerveza |
Número de registros | 1.586.614 |
Número de variables | 15 |
Datos faltantes | 0 |
Marcas o cervecerías distintas | 5.743 |
Cervezas distintas reseñadas | 56.857 |
Países de procedencia | 10 |
Variables simuladas | precio |
Cada fila corresponde a una reseña individual; por esta razón una misma cerveza puede aparecer en varios registros. Los indicadores calculados describen, en consecuencia, el comportamiento del conjunto de reseñas y no el de un catálogo de productos únicos.
La selección de las tablas e indicadores apropiados depende directamente del tipo de variable y de su escala de medición.
clasif <- data.frame(
Variable = c("id", "marca", "nombre_cerveza", "nacionalidad", "tipo", "origen",
"precio", "alcohol", "carbohidratos", "calorias",
"calificacion", "aroma", "apariencia", "paladar", "sabor"),
Naturaleza = c("Identificador", rep("Cualitativa", 5),
rep("Cuantitativa", 4), rep("Cualitativa", 5)),
Escala = c("No aplica", rep("Nominal", 4), "Nominal dicotómica",
"Continua (de razón)", "Continua (de razón)",
"Continua (de razón)", "Discreta (de razón)",
rep("Ordinal", 5)),
Resumen_apropiado = c("No se resume",
rep("Tabla de frecuencias y moda", 5),
rep("Indicadores de tendencia, posición, dispersión y forma", 4),
rep("Tabla de frecuencias, moda y mediana", 5)),
stringsAsFactors = FALSE
)
flextable(clasif) |>
set_header_labels(Variable = "Variable", Naturaleza = "Naturaleza",
Escala = "Escala de medición",
Resumen_apropiado = "Forma de resumen apropiada") |>
theme_booktabs() |>
align(align = "left", part = "all") |>
set_caption("Tabla 2. Clasificación de las variables según naturaleza y escala") |>
autofit()Variable | Naturaleza | Escala de medición | Forma de resumen apropiada |
|---|---|---|---|
id | Identificador | No aplica | No se resume |
marca | Cualitativa | Nominal | Tabla de frecuencias y moda |
nombre_cerveza | Cualitativa | Nominal | Tabla de frecuencias y moda |
nacionalidad | Cualitativa | Nominal | Tabla de frecuencias y moda |
tipo | Cualitativa | Nominal | Tabla de frecuencias y moda |
origen | Cualitativa | Nominal dicotómica | Tabla de frecuencias y moda |
precio | Cuantitativa | Continua (de razón) | Indicadores de tendencia, posición, dispersión y forma |
alcohol | Cuantitativa | Continua (de razón) | Indicadores de tendencia, posición, dispersión y forma |
carbohidratos | Cuantitativa | Continua (de razón) | Indicadores de tendencia, posición, dispersión y forma |
calorias | Cuantitativa | Discreta (de razón) | Indicadores de tendencia, posición, dispersión y forma |
calificacion | Cualitativa | Ordinal | Tabla de frecuencias, moda y mediana |
aroma | Cualitativa | Ordinal | Tabla de frecuencias, moda y mediana |
apariencia | Cualitativa | Ordinal | Tabla de frecuencias, moda y mediana |
paladar | Cualitativa | Ordinal | Tabla de frecuencias, moda y mediana |
sabor | Cualitativa | Ordinal | Tabla de frecuencias, moda y mediana |
La variable id identifica el producto reseñado pero no
constituye una variable estadística de interés, por lo que se excluye
del análisis. Las cinco escalas sensoriales están codificadas con
números, pero representan niveles de valoración y no cantidades
medibles; por ello se tratan como ordinales.
Para las variables cuantitativas, la elección entre media y mediana se fundamenta en el coeficiente de asimetría:
\[g_1 = \frac{\frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x})^3}{s^3}\]
El criterio aplicado en este informe es el siguiente:
asimetria <- function(x) {
n <- length(x)
(sum((x - mean(x))^3) / n) / (sd(x)^3)
}
curtosis <- function(x) {
n <- length(x)
(sum((x - mean(x))^4) / n) / (sd(x)^4) - 3
}
# Tabla de frecuencias: absoluta, relativa, porcentual y acumuladas
tabla_frecuencia <- function(x, ordenar = "frecuencia") {
fa <- table(x)
df <- data.frame(Categoria = names(fa),
fa = as.numeric(fa),
stringsAsFactors = FALSE)
if (ordenar == "frecuencia") {
df <- df[order(-df$fa), ]
} else {
df <- df[order(as.numeric(df$Categoria)), ]
}
df$fr <- df$fa / sum(df$fa)
df$pct <- df$fr * 100
df$fa_acum <- cumsum(df$fa)
df$pct_acum <- cumsum(df$pct)
rownames(df) <- NULL
df
}
moda <- function(x) {
fa <- table(x)
names(fa)[which.max(fa)]
}
# Presentación de la tabla de frecuencias
ft_frecuencia <- function(df, titulo) {
flextable(df) |>
set_header_labels(Categoria = "Categoría", fa = "Frec. absoluta",
fr = "Frec. relativa", pct = "Porcentaje (%)",
fa_acum = "Frec. acumulada", pct_acum = "% acumulado") |>
colformat_double(j = "fr", digits = 4) |>
colformat_double(j = c("pct", "pct_acum"), digits = 2) |>
colformat_double(j = c("fa", "fa_acum"), digits = 0, big.mark = ".", decimal.mark = ",") |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption(titulo) |>
autofit()
}
# Resumen completo de una variable cuantitativa
resumen_cuantitativa <- function(x) {
data.frame(
Indicador = c("Media", "Mediana", "Desviación estándar",
"Coeficiente de variación", "Mínimo", "Percentil 10",
"Cuartil 1 (Q1)", "Cuartil 3 (Q3)", "Percentil 90", "Máximo",
"Rango", "Rango intercuartílico (IQR)",
"Asimetría", "Curtosis"),
Valor = c(mean(x), median(x), sd(x), sd(x) / mean(x), min(x),
unname(quantile(x, 0.10)), unname(quantile(x, 0.25)),
unname(quantile(x, 0.75)), unname(quantile(x, 0.90)), max(x),
max(x) - min(x), IQR(x), asimetria(x), curtosis(x)),
stringsAsFactors = FALSE
)
}
ft_cuantitativa <- function(x, titulo) {
flextable(resumen_cuantitativa(x)) |>
set_header_labels(Indicador = "Indicador", Valor = "Valor") |>
colformat_double(j = "Valor", digits = 3, big.mark = ".", decimal.mark = ",") |>
theme_booktabs() |>
align(j = 1, align = "left", part = "all") |>
align(j = 2, align = "right", part = "all") |>
set_caption(titulo) |>
autofit()
}
# Comparación de una variable cuantitativa entre grupos
comparar_grupos <- function(variable, grupo) {
data.frame(
Grupo = names(tapply(variable, grupo, mean)),
n = as.numeric(tapply(variable, grupo, length)),
Media = as.numeric(tapply(variable, grupo, mean)),
Mediana = as.numeric(tapply(variable, grupo, median)),
Desv = as.numeric(tapply(variable, grupo, sd)),
CV = as.numeric(tapply(variable, grupo, function(z) sd(z) / mean(z))),
Q1 = as.numeric(tapply(variable, grupo, function(z) quantile(z, 0.25))),
Q3 = as.numeric(tapply(variable, grupo, function(z) quantile(z, 0.75))),
Asimetria = as.numeric(tapply(variable, grupo, asimetria)),
stringsAsFactors = FALSE
)
}
ft_comparacion <- function(df, titulo) {
flextable(df) |>
set_header_labels(Grupo = "Grupo", n = "n", Media = "Media",
Mediana = "Mediana", Desv = "Desv. estándar",
CV = "CV", Q1 = "Q1", Q3 = "Q3",
Asimetria = "Asimetría") |>
colformat_double(j = "n", digits = 0, big.mark = ".", decimal.mark = ",") |>
colformat_double(j = c("Media", "Mediana", "Desv", "Q1", "Q3"), digits = 2) |>
colformat_double(j = c("CV", "Asimetria"), digits = 3) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption(titulo) |>
autofit()
}ft_frecuencia(tabla_frecuencia(cerveza$tipo),
"Tabla 3. Distribución de las reseñas según el tipo de cerveza")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
cerveza normal y helada | 839.088 | 0.5289 | 52.89 | 839.088 | 52.89 |
clara artesanal | 483.464 | 0.3047 | 30.47 | 1.322.552 | 83.36 |
lager importada | 219.194 | 0.1382 | 13.82 | 1.541.746 | 97.17 |
lager artesanal | 22.725 | 0.0143 | 1.43 | 1.564.471 | 98.60 |
baja en calorías / sin alcohol | 22.143 | 0.0140 | 1.40 | 1.586.614 | 100.00 |
par(mar = c(5, 12, 4, 2))
barplot(sort(table(cerveza$tipo)), horiz = TRUE, las = 1,
col = "#1F4E79", border = NA, cex.names = 0.85,
main = "Figura 1. Reseñas por tipo de cerveza",
xlab = "Número de reseñas")La moda corresponde a cerveza normal y helada, con 839.088 reseñas (52.9 % del total). Los dos tipos más frecuentes concentran más del 80 % de los registros, mientras que las categorías lager artesanal y baja en calorías / sin alcohol apenas superan el 1 % cada una. Esta concentración es relevante para la lectura del resto del informe: los indicadores globales están dominados por el comportamiento de los tipos mayoritarios.
ft_frecuencia(tabla_frecuencia(cerveza$origen),
"Tabla 4. Distribución de las reseñas según el origen")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
importada | 1.412.449 | 0.8902 | 89.02 | 1.412.449 | 89.02 |
nacional | 174.165 | 0.1098 | 10.98 | 1.586.614 | 100.00 |
La moda es importada (89 % de las reseñas). La base está claramente desbalanceada hacia el producto importado.
cruce <- as.data.frame.matrix(table(cerveza$tipo, cerveza$origen))
cruce <- data.frame(Tipo = rownames(cruce), cruce, row.names = NULL,
check.names = FALSE)
flextable(cruce) |>
set_header_labels(Tipo = "Tipo de cerveza") |>
colformat_double(j = c("importada", "nacional"), digits = 0, big.mark = ".", decimal.mark = ",") |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 5. Tabla de doble entrada: tipo de cerveza según origen") |>
autofit()Tipo de cerveza | importada | nacional |
|---|---|---|
baja en calorías / sin alcohol | 20,432 | 1,711 |
cerveza normal y helada | 754,796 | 84,292 |
clara artesanal | 418,027 | 65,437 |
lager artesanal | 0 | 22,725 |
lager importada | 219,194 | 0 |
Esta tabla revela una dependencia estructural entre ambas variables: las categorías lager importada y lager artesanal aparecen exclusivamente en un solo origen. En consecuencia, cualquier diferencia observada entre orígenes está parcialmente condicionada por la composición de tipos que cada uno contiene, y no debe atribuirse únicamente a la procedencia del producto.
ft_frecuencia(tabla_frecuencia(cerveza$nacionalidad),
"Tabla 6. Distribución de las reseñas según la nacionalidad")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
Austria | 201.941 | 0.1273 | 12.73 | 201.941 | 12.73 |
Bélgica | 188.677 | 0.1189 | 11.89 | 390.618 | 24.62 |
Francia | 181.574 | 0.1144 | 11.44 | 572.192 | 36.06 |
Estados Unidos | 174.165 | 0.1098 | 10.98 | 746.357 | 47.04 |
Inglaterra | 162.644 | 0.1025 | 10.25 | 909.001 | 57.29 |
Canadá | 159.508 | 0.1005 | 10.05 | 1.068.509 | 67.35 |
Japón | 155.273 | 0.0979 | 9.79 | 1.223.782 | 77.13 |
Alemania | 121.684 | 0.0767 | 7.67 | 1.345.466 | 84.80 |
Irlanda | 120.742 | 0.0761 | 7.61 | 1.466.208 | 92.41 |
República Checa | 120.406 | 0.0759 | 7.59 | 1.586.614 | 100.00 |
La moda es Austria. A diferencia de las variables anteriores, la nacionalidad se distribuye de forma relativamente homogénea entre los diez países registrados, con porcentajes que oscilan aproximadamente entre el 7 % y el 13 %.
Estas dos variables presentan un número muy elevado de categorías (5.743 marcas y 56.857 nombres comerciales), por lo que una tabla completa no resulta interpretable. Se presentan las diez categorías de mayor frecuencia.
top_marca <- cerveza |>
count(marca, sort = TRUE, name = "resenas") |>
slice_head(n = 10) |>
mutate(porcentaje = resenas / nrow(cerveza) * 100)
flextable(top_marca) |>
set_header_labels(marca = "Marca o cervecería", resenas = "Reseñas",
porcentaje = "Porcentaje (%)") |>
colformat_double(j = "resenas", digits = 0, big.mark = ".", decimal.mark = ",") |>
colformat_double(j = "porcentaje", digits = 2) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 7. Diez marcas con mayor número de reseñas") |>
autofit()Marca o cervecería | Reseñas | Porcentaje (%) |
|---|---|---|
Boston Beer Company (Samuel Adams) | 39,444 | 2.49 |
Dogfish Head Brewery | 33,839 | 2.13 |
Stone Brewing Co. | 33,066 | 2.08 |
Sierra Nevada Brewing Co. | 28,751 | 1.81 |
Bell's Brewery, Inc. | 25,191 | 1.59 |
Rogue Ales | 24,083 | 1.52 |
Founders Brewing Company | 20,004 | 1.26 |
Victory Brewing Company | 19,479 | 1.23 |
Lagunitas Brewing Company | 16,837 | 1.06 |
Avery Brewing Company | 16,107 | 1.02 |
top_nombre <- cerveza |>
count(nombre_cerveza, sort = TRUE, name = "resenas") |>
slice_head(n = 10) |>
mutate(porcentaje = resenas / nrow(cerveza) * 100)
flextable(top_nombre) |>
set_header_labels(nombre_cerveza = "Cerveza", resenas = "Reseñas",
porcentaje = "Porcentaje (%)") |>
colformat_double(j = "resenas", digits = 0, big.mark = ".", decimal.mark = ",") |>
colformat_double(j = "porcentaje", digits = 2) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 8. Diez cervezas con mayor número de reseñas") |>
autofit()Cerveza | Reseñas | Porcentaje (%) |
|---|---|---|
90 Minute IPA | 3,290 | 0.21 |
India Pale Ale | 3,130 | 0.20 |
Old Rasputin Russian Imperial Stout | 3,111 | 0.20 |
Sierra Nevada Celebration Ale | 3,000 | 0.19 |
Two Hearted Ale | 2,728 | 0.17 |
Arrogant Bastard Ale | 2,704 | 0.17 |
Stone Ruination IPA | 2,704 | 0.17 |
Sierra Nevada Pale Ale | 2,587 | 0.16 |
Stone IPA (India Pale Ale) | 2,575 | 0.16 |
Pliny The Elder | 2,527 | 0.16 |
Las cinco escalas sensoriales (calificacion,
aroma, apariencia, paladar y
sabor) se miden en niveles que van de 0 a 5 con incrementos
de 0,5. Al tratarse de escalas ordinales, se resumen mediante tablas de
frecuencia, moda y mediana; no se calculan medias aritméticas como
indicador principal, ya que la distancia entre niveles consecutivos no
es necesariamente constante.
ft_frecuencia(tabla_frecuencia(cerveza$calificacion, ordenar = "categoria"),
"Tabla 9. Distribución de la calificación general")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
0 | 7 | 0.0000 | 0.00 | 7 | 0.00 |
1 | 10.954 | 0.0069 | 0.69 | 10.961 | 0.69 |
1.5 | 12.975 | 0.0082 | 0.82 | 23.936 | 1.51 |
2 | 38.225 | 0.0241 | 2.41 | 62.161 | 3.92 |
2.5 | 58.523 | 0.0369 | 3.69 | 120.684 | 7.61 |
3 | 165.644 | 0.1044 | 10.44 | 286.328 | 18.05 |
3.5 | 301.817 | 0.1902 | 19.02 | 588.145 | 37.07 |
4 | 582.764 | 0.3673 | 36.73 | 1.170.909 | 73.80 |
4.5 | 324.385 | 0.2045 | 20.45 | 1.495.294 | 94.24 |
5 | 91.320 | 0.0576 | 5.76 | 1.586.614 | 100.00 |
ft_frecuencia(tabla_frecuencia(cerveza$aroma, ordenar = "categoria"),
"Tabla 10. Distribución de la valoración del aroma")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
1 | 6.873 | 0.0043 | 0.43 | 6.873 | 0.43 |
1.5 | 12.524 | 0.0079 | 0.79 | 19.397 | 1.22 |
2 | 42.566 | 0.0268 | 2.68 | 61.963 | 3.91 |
2.5 | 66.359 | 0.0418 | 4.18 | 128.322 | 8.09 |
3 | 200.030 | 0.1261 | 12.61 | 328.352 | 20.70 |
3.5 | 365.312 | 0.2302 | 23.02 | 693.664 | 43.72 |
4 | 557.383 | 0.3513 | 35.13 | 1.251.047 | 78.85 |
4.5 | 271.450 | 0.1711 | 17.11 | 1.522.497 | 95.96 |
5 | 64.117 | 0.0404 | 4.04 | 1.586.614 | 100.00 |
ft_frecuencia(tabla_frecuencia(cerveza$apariencia, ordenar = "categoria"),
"Tabla 11. Distribución de la valoración de la apariencia")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
0 | 7 | 0.0000 | 0.00 | 7 | 0.00 |
1 | 3.323 | 0.0021 | 0.21 | 3.330 | 0.21 |
1.5 | 6.147 | 0.0039 | 0.39 | 9.477 | 0.60 |
2 | 25.414 | 0.0160 | 1.60 | 34.891 | 2.20 |
2.5 | 39.493 | 0.0249 | 2.49 | 74.384 | 4.69 |
3 | 166.009 | 0.1046 | 10.46 | 240.393 | 15.15 |
3.5 | 318.529 | 0.2008 | 20.08 | 558.922 | 35.23 |
4 | 674.186 | 0.4249 | 42.49 | 1.233.108 | 77.72 |
4.5 | 288.108 | 0.1816 | 18.16 | 1.521.216 | 95.88 |
5 | 65.398 | 0.0412 | 4.12 | 1.586.614 | 100.00 |
ft_frecuencia(tabla_frecuencia(cerveza$paladar, ordenar = "categoria"),
"Tabla 12. Distribución de la valoración del paladar")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
1 | 6.874 | 0.0043 | 0.43 | 6.874 | 0.43 |
1.5 | 11.045 | 0.0070 | 0.70 | 17.919 | 1.13 |
2 | 38.333 | 0.0242 | 2.42 | 56.252 | 3.55 |
2.5 | 62.842 | 0.0396 | 3.96 | 119.094 | 7.51 |
3 | 206.932 | 0.1304 | 13.04 | 326.026 | 20.55 |
3.5 | 338.585 | 0.2134 | 21.34 | 664.611 | 41.89 |
4 | 606.711 | 0.3824 | 38.24 | 1.271.322 | 80.13 |
4.5 | 253.102 | 0.1595 | 15.95 | 1.524.424 | 96.08 |
5 | 62.190 | 0.0392 | 3.92 | 1.586.614 | 100.00 |
ft_frecuencia(tabla_frecuencia(cerveza$sabor, ordenar = "categoria"),
"Tabla 13. Distribución de la valoración del sabor")Categoría | Frec. absoluta | Frec. relativa | Porcentaje (%) | Frec. acumulada | % acumulado |
|---|---|---|---|---|---|
1 | 9.991 | 0.0063 | 0.63 | 9.991 | 0.63 |
1.5 | 15.128 | 0.0095 | 0.95 | 25.119 | 1.58 |
2 | 41.992 | 0.0265 | 2.65 | 67.111 | 4.23 |
2.5 | 66.534 | 0.0419 | 4.19 | 133.645 | 8.42 |
3 | 166.860 | 0.1052 | 10.52 | 300.505 | 18.94 |
3.5 | 324.541 | 0.2045 | 20.45 | 625.046 | 39.39 |
4 | 541.429 | 0.3412 | 34.12 | 1.166.475 | 73.52 |
4.5 | 336.162 | 0.2119 | 21.19 | 1.502.637 | 94.71 |
5 | 83.977 | 0.0529 | 5.29 | 1.586.614 | 100.00 |
ordinales <- c("calificacion", "aroma", "apariencia", "paladar", "sabor")
sintesis <- data.frame(
Escala = c("Calificación general", "Aroma", "Apariencia", "Paladar", "Sabor"),
Moda = sapply(ordinales, function(v) moda(cerveza[[v]])),
Mediana = sapply(ordinales, function(v) median(cerveza[[v]])),
Q1 = sapply(ordinales, function(v) unname(quantile(cerveza[[v]], 0.25))),
Q3 = sapply(ordinales, function(v) unname(quantile(cerveza[[v]], 0.75))),
Pct_4_o_mas = sapply(ordinales,
function(v) mean(cerveza[[v]] >= 4) * 100),
stringsAsFactors = FALSE, row.names = NULL
)
flextable(sintesis) |>
set_header_labels(Escala = "Escala", Moda = "Moda", Mediana = "Mediana",
Q1 = "Q1", Q3 = "Q3",
Pct_4_o_mas = "% con valoración ≥ 4") |>
colformat_double(j = c("Mediana", "Q1", "Q3"), digits = 1) |>
colformat_double(j = "Pct_4_o_mas", digits = 1) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 14. Síntesis de las cinco escalas sensoriales") |>
autofit()Escala | Moda | Mediana | Q1 | Q3 | % con valoración ≥ 4 |
|---|---|---|---|---|---|
Calificación general | 4 | 4.0 | 3.5 | 4.5 | 62.9 |
Aroma | 4 | 4.0 | 3.5 | 4.0 | 56.3 |
Apariencia | 4 | 4.0 | 3.5 | 4.0 | 64.8 |
Paladar | 4 | 4.0 | 3.5 | 4.0 | 58.1 |
Sabor | 4 | 4.0 | 3.5 | 4.5 | 60.6 |
par(mfrow = c(2, 3), mar = c(4, 4, 3, 1))
titulos <- c("Calificación general", "Aroma", "Apariencia", "Paladar", "Sabor")
for (i in seq_along(ordinales)) {
barplot(table(cerveza[[ordinales[i]]]),
col = "#2E75B6", border = NA,
main = titulos[i], xlab = "Nivel", ylab = "Frecuencia",
cex.main = 1)
}
par(mfrow = c(1, 1))Figura 2. Distribución de las cinco escalas sensoriales
En las cinco escalas la moda y la mediana coinciden en el nivel 4, y las distribuciones presentan un marcado sesgo hacia los valores altos: los niveles más bajos (0, 1 y 1,5) representan en conjunto menos del 2 % de los registros en todos los casos. Este patrón sugiere que los consumidores que dejan una reseña tienden a evaluar favorablemente el producto, lo que constituye una característica de la base que debe tenerse en cuenta al interpretar cualquier comparación entre grupos.
ft_cuantitativa(cerveza$precio,
"Tabla 15. Indicadores descriptivos del precio (COP, caja de 6 × 355 ml)")Indicador | Valor |
|---|---|
Media | 5,363 |
Mediana | 5,410 |
Desviación estándar | 0,649 |
Coeficiente de variación | 0,121 |
Mínimo | 2,200 |
Percentil 10 | 4,500 |
Cuartil 1 (Q1) | 4,980 |
Cuartil 3 (Q3) | 5,820 |
Percentil 90 | 6,140 |
Máximo | 8,030 |
Rango | 5,830 |
Rango intercuartílico (IQR) | 0,840 |
Asimetría | -0,468 |
Curtosis | 0,365 |
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
hist(cerveza$precio, breaks = 40, col = "#9DC3E6", border = "white",
main = "Histograma", xlab = "Precio")
abline(v = mean(cerveza$precio), col = "#C00000", lwd = 2)
abline(v = median(cerveza$precio), col = "#1F4E79", lwd = 2, lty = 2)
legend("topleft", legend = c("Media", "Mediana"),
col = c("#C00000", "#1F4E79"), lwd = 2, lty = c(1, 2),
bty = "n", cex = 0.85)
boxplot(cerveza$precio, horizontal = TRUE, col = "#9DC3E6",
main = "Diagrama de caja", xlab = "Precio")Figura 3. Distribución del precio
Indicador seleccionado: con una asimetría de -0.468, en valor absoluto inferior a 0,5, la distribución se considera aproximadamente simétrica. La media (5.36) y la mediana (5.41) prácticamente coinciden, por lo que ambas son representativas y se reporta la media acompañada de la desviación estándar. El coeficiente de variación (0.121) indica una dispersión relativa baja: los precios se concentran en un rango estrecho alrededor del centro.
ft_cuantitativa(cerveza$alcohol,
"Tabla 16. Indicadores descriptivos del contenido de alcohol (g / 355 ml)")Indicador | Valor |
|---|---|
Media | 18,712 |
Mediana | 17,670 |
Desviación estándar | 5,456 |
Coeficiente de variación | 0,292 |
Mínimo | 0,030 |
Percentil 10 | 13,220 |
Cuartil 1 (Q1) | 14,280 |
Cuartil 3 (Q3) | 22,630 |
Percentil 90 | 26,140 |
Máximo | 59,450 |
Rango | 59,420 |
Rango intercuartílico (IQR) | 8,350 |
Asimetría | 0,959 |
Curtosis | 1,310 |
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
hist(cerveza$alcohol, breaks = 40, col = "#F4B183", border = "white",
main = "Histograma", xlab = "Alcohol (g)")
abline(v = mean(cerveza$alcohol), col = "#C00000", lwd = 2)
abline(v = median(cerveza$alcohol), col = "#1F4E79", lwd = 2, lty = 2)
legend("topright", legend = c("Media", "Mediana"),
col = c("#C00000", "#1F4E79"), lwd = 2, lty = c(1, 2),
bty = "n", cex = 0.85)
boxplot(cerveza$alcohol, horizontal = TRUE, col = "#F4B183",
main = "Diagrama de caja", xlab = "Alcohol (g)")Figura 4. Distribución del contenido de alcohol
Indicador seleccionado: la asimetría es 0.959, superior a 0,5, lo que confirma un sesgo positivo visible en el histograma. La media (18.71) supera a la mediana (17.67) porque un grupo reducido de cervezas de alta graduación desplaza el promedio hacia arriba. Por ello se reporta como indicadores principales la mediana y el rango intercuartílico (8.35).
ft_cuantitativa(cerveza$carbohidratos,
"Tabla 17. Indicadores descriptivos de los carbohidratos (g / 355 ml)")Indicador | Valor |
|---|---|
Media | 14,048 |
Mediana | 13,800 |
Desviación estándar | 2,376 |
Coeficiente de variación | 0,169 |
Mínimo | 3,500 |
Percentil 10 | 11,200 |
Cuartil 1 (Q1) | 12,400 |
Cuartil 3 (Q3) | 15,600 |
Percentil 90 | 17,200 |
Máximo | 30,200 |
Rango | 26,700 |
Rango intercuartílico (IQR) | 3,200 |
Asimetría | 0,461 |
Curtosis | 0,869 |
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
hist(cerveza$carbohidratos, breaks = 40, col = "#FFE699", border = "white",
main = "Histograma", xlab = "Carbohidratos (g)")
abline(v = mean(cerveza$carbohidratos), col = "#C00000", lwd = 2)
abline(v = median(cerveza$carbohidratos), col = "#1F4E79", lwd = 2, lty = 2)
legend("topright", legend = c("Media", "Mediana"),
col = c("#C00000", "#1F4E79"), lwd = 2, lty = c(1, 2),
bty = "n", cex = 0.85)
boxplot(cerveza$carbohidratos, horizontal = TRUE, col = "#FFE699",
main = "Diagrama de caja", xlab = "Carbohidratos (g)")Figura 5. Distribución de los carbohidratos
Indicador seleccionado: la asimetría es 0.461, por debajo del umbral de 0,5, por lo que la distribución se considera aproximadamente simétrica y se reportan la media (14.05) y la desviación estándar (2.38).
ft_cuantitativa(cerveza$calorias,
"Tabla 18. Indicadores descriptivos de las calorías (kcal / 355 ml)")Indicador | Valor |
|---|---|
Media | 193,173 |
Mediana | 182,000 |
Desviación estándar | 46,569 |
Coeficiente de variación | 0,241 |
Mínimo | 21,000 |
Percentil 10 | 145,000 |
Cuartil 1 (Q1) | 157,000 |
Cuartil 3 (Q3) | 224,000 |
Percentil 90 | 258,000 |
Máximo | 541,000 |
Rango | 520,000 |
Rango intercuartílico (IQR) | 67,000 |
Asimetría | 0,915 |
Curtosis | 1,318 |
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
hist(cerveza$calorias, breaks = 40, col = "#C5A5CF", border = "white",
main = "Histograma", xlab = "Calorías")
abline(v = mean(cerveza$calorias), col = "#C00000", lwd = 2)
abline(v = median(cerveza$calorias), col = "#1F4E79", lwd = 2, lty = 2)
legend("topright", legend = c("Media", "Mediana"),
col = c("#C00000", "#1F4E79"), lwd = 2, lty = c(1, 2),
bty = "n", cex = 0.85)
boxplot(cerveza$calorias, horizontal = TRUE, col = "#C5A5CF",
main = "Diagrama de caja", xlab = "Calorías")Figura 6. Distribución de las calorías
Indicador seleccionado: con una asimetría de 0.915, la distribución presenta sesgo positivo. Se reportan como indicadores principales la mediana (182) y el rango intercuartílico (67).
cuantitativas <- c("precio", "alcohol", "carbohidratos", "calorias")
global <- data.frame(
Variable = c("Precio", "Alcohol (g)", "Carbohidratos (g)", "Calorías"),
Media = sapply(cuantitativas, function(v) mean(cerveza[[v]])),
Mediana = sapply(cuantitativas, function(v) median(cerveza[[v]])),
Desv = sapply(cuantitativas, function(v) sd(cerveza[[v]])),
CV = sapply(cuantitativas, function(v) sd(cerveza[[v]]) / mean(cerveza[[v]])),
IQR = sapply(cuantitativas, function(v) IQR(cerveza[[v]])),
Asimetria = sapply(cuantitativas, function(v) asimetria(cerveza[[v]])),
Indicador = c("Media y desviación estándar", "Mediana e IQR",
"Media y desviación estándar", "Mediana e IQR"),
stringsAsFactors = FALSE, row.names = NULL
)
flextable(global) |>
set_header_labels(Variable = "Variable", Media = "Media", Mediana = "Mediana",
Desv = "Desv. estándar", CV = "CV", IQR = "IQR",
Asimetria = "Asimetría",
Indicador = "Indicador seleccionado") |>
colformat_double(j = c("Media", "Mediana", "Desv", "IQR"), digits = 2) |>
colformat_double(j = c("CV", "Asimetria"), digits = 3) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = c(1, 8), align = "left", part = "body") |>
set_caption("Tabla 19. Resumen de indicadores y criterio de selección aplicado") |>
autofit()Variable | Media | Mediana | Desv. estándar | CV | IQR | Asimetría | Indicador seleccionado |
|---|---|---|---|---|---|---|---|
Precio | 5.36 | 5.41 | 0.65 | 0.121 | 0.84 | -0.468 | Media y desviación estándar |
Alcohol (g) | 18.71 | 17.67 | 5.46 | 0.292 | 8.35 | 0.959 | Mediana e IQR |
Carbohidratos (g) | 14.05 | 13.80 | 2.38 | 0.169 | 3.20 | 0.461 | Media y desviación estándar |
Calorías | 193.17 | 182.00 | 46.57 | 0.241 | 67.00 | 0.915 | Mediana e IQR |
ft_comparacion(comparar_grupos(cerveza$precio, cerveza$tipo),
"Tabla 20. Precio según el tipo de cerveza")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
baja en calorías / sin alcohol | 22.143 | 4.28 | 4.25 | 0.71 | 0.165 | 3.73 | 4.67 | 0.328 |
cerveza normal y helada | 839.088 | 5.27 | 5.34 | 0.60 | 0.114 | 4.93 | 5.68 | -0.604 |
clara artesanal | 483.464 | 5.70 | 5.78 | 0.59 | 0.103 | 5.33 | 6.13 | -0.508 |
lager artesanal | 22.725 | 4.55 | 4.54 | 0.54 | 0.119 | 4.21 | 4.93 | -0.210 |
lager importada | 219.194 | 5.17 | 5.24 | 0.56 | 0.107 | 4.83 | 5.56 | -0.415 |
ft_comparacion(comparar_grupos(cerveza$alcohol, cerveza$tipo),
"Tabla 21. Contenido de alcohol según el tipo de cerveza")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
baja en calorías / sin alcohol | 22.143 | 9.84 | 11.07 | 2.66 | 0.270 | 9.17 | 11.61 | -1.876 |
cerveza normal y helada | 839.088 | 20.10 | 18.94 | 5.77 | 0.287 | 15.34 | 24.06 | 0.770 |
clara artesanal | 483.464 | 18.15 | 17.41 | 4.58 | 0.252 | 14.55 | 20.93 | 1.146 |
lager artesanal | 22.725 | 15.67 | 13.75 | 3.78 | 0.241 | 13.22 | 17.41 | 1.416 |
lager importada | 219.194 | 15.86 | 14.28 | 3.84 | 0.242 | 13.49 | 17.03 | 1.950 |
ft_comparacion(comparar_grupos(cerveza$carbohidratos, cerveza$tipo),
"Tabla 22. Carbohidratos según el tipo de cerveza")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
baja en calorías / sin alcohol | 22.143 | 8.66 | 8.70 | 1.52 | 0.176 | 7.60 | 10.10 | -0.614 |
cerveza normal y helada | 839.088 | 14.29 | 14.10 | 2.40 | 0.168 | 12.50 | 15.80 | 0.527 |
clara artesanal | 483.464 | 14.51 | 14.30 | 2.07 | 0.143 | 13.00 | 15.80 | 0.805 |
lager artesanal | 22.725 | 13.54 | 13.10 | 1.86 | 0.137 | 12.20 | 14.40 | 0.844 |
lager importada | 219.194 | 12.71 | 12.60 | 1.79 | 0.141 | 11.30 | 13.50 | 1.160 |
ft_comparacion(comparar_grupos(cerveza$calorias, cerveza$tipo),
"Tabla 23. Calorías según el tipo de cerveza")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
baja en calorías / sin alcohol | 22.143 | 109.52 | 116.00 | 23.04 | 0.210 | 100.00 | 125.00 | -1.755 |
cerveza normal y helada | 839.088 | 203.82 | 198.00 | 49.05 | 0.241 | 163.00 | 240.00 | 0.763 |
clara artesanal | 483.464 | 191.10 | 184.00 | 39.24 | 0.205 | 160.00 | 215.00 | 1.156 |
lager artesanal | 22.725 | 169.88 | 158.00 | 32.87 | 0.193 | 148.00 | 185.00 | 1.404 |
lager importada | 219.194 | 167.84 | 156.00 | 32.83 | 0.196 | 147.00 | 179.00 | 1.957 |
par(mfrow = c(2, 2), mar = c(9, 4, 3, 1))
for (v in cuantitativas) {
boxplot(cerveza[[v]] ~ cerveza$tipo, las = 2, col = "#9DC3E6",
main = v, xlab = "", ylab = v, cex.axis = 0.7)
}Figura 7. Variables cuantitativas según el tipo de cerveza
calif_tipo <- data.frame(
Tipo = names(tapply(cerveza$calificacion, cerveza$tipo, median)),
n = as.numeric(tapply(cerveza$calificacion, cerveza$tipo, length)),
Mediana = as.numeric(tapply(cerveza$calificacion, cerveza$tipo, median)),
Moda = sapply(split(cerveza$calificacion, cerveza$tipo), moda),
Pct_4_o_mas = as.numeric(tapply(cerveza$calificacion, cerveza$tipo,
function(z) mean(z >= 4) * 100)),
stringsAsFactors = FALSE, row.names = NULL
)
flextable(calif_tipo) |>
set_header_labels(Tipo = "Tipo de cerveza", n = "n", Mediana = "Mediana",
Moda = "Moda", Pct_4_o_mas = "% con calificación ≥ 4") |>
colformat_double(j = "n", digits = 0, big.mark = ".", decimal.mark = ",") |>
colformat_double(j = "Mediana", digits = 1) |>
colformat_double(j = "Pct_4_o_mas", digits = 1) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 24. Calificación general según el tipo de cerveza") |>
autofit()Tipo de cerveza | n | Mediana | Moda | % con calificación ≥ 4 |
|---|---|---|---|---|
baja en calorías / sin alcohol | 22.143 | 3.0 | 3 | 27.2 |
cerveza normal y helada | 839.088 | 4.0 | 4 | 65.7 |
clara artesanal | 483.464 | 4.0 | 4 | 65.7 |
lager artesanal | 22.725 | 4.0 | 4 | 51.1 |
lager importada | 219.194 | 4.0 | 4 | 51.0 |
Lectura de los resultados. El tipo baja en calorías / sin alcohol se separa nítidamente del resto en todas las variables nutricionales: presenta el menor contenido de alcohol, de carbohidratos y de calorías, junto con el precio promedio más bajo. Este comportamiento es consistente con la naturaleza del producto. Es además el tipo con la menor proporción de calificaciones altas, lo que sugiere que en esta base los productos de perfil reducido reciben valoraciones menos favorables que los tipos convencionales y artesanales.
Los tipos cerveza normal y helada y clara artesanal, que concentran la mayor parte de las reseñas, muestran los contenidos nutricionales más altos y también la mayor proporción de calificaciones favorables. Las dos categorías lager ocupan posiciones intermedias.
Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
importada | 1.412.449 | 5.46 | 5.50 | 0.58 | 0.106 | 5.11 | 5.86 | -0.370 |
nacional | 174.165 | 4.54 | 4.54 | 0.59 | 0.131 | 4.12 | 4.94 | 0.024 |
ft_comparacion(comparar_grupos(cerveza$alcohol, cerveza$origen),
"Tabla 26. Contenido de alcohol según el origen")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
importada | 1.412.449 | 18.71 | 17.41 | 5.47 | 0.292 | 14.28 | 22.63 | 0.961 |
nacional | 174.165 | 18.73 | 17.93 | 5.35 | 0.286 | 14.55 | 22.15 | 0.944 |
ft_comparacion(comparar_grupos(cerveza$carbohidratos, cerveza$origen),
"Tabla 27. Carbohidratos según el origen")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
importada | 1.412.449 | 14.02 | 13.80 | 2.39 | 0.170 | 12.30 | 15.50 | 0.488 |
nacional | 174.165 | 14.24 | 14.10 | 2.29 | 0.160 | 12.70 | 15.90 | 0.237 |
ft_comparacion(comparar_grupos(cerveza$calorias, cerveza$origen),
"Tabla 28. Calorías según el origen")Grupo | n | Media | Mediana | Desv. estándar | CV | Q1 | Q3 | Asimetría |
|---|---|---|---|---|---|---|---|---|
importada | 1.412.449 | 193.06 | 182.00 | 46.72 | 0.242 | 157.00 | 224.00 | 0.923 |
nacional | 174.165 | 194.06 | 188.00 | 45.31 | 0.233 | 158.00 | 223.00 | 0.847 |
par(mfrow = c(2, 2), mar = c(4, 4, 3, 1))
for (v in cuantitativas) {
boxplot(cerveza[[v]] ~ cerveza$origen, col = c("#9DC3E6", "#F4B183"),
main = v, xlab = "", ylab = v)
}Figura 8. Variables cuantitativas según el origen
calif_origen <- data.frame(
Origen = names(tapply(cerveza$calificacion, cerveza$origen, median)),
n = as.numeric(tapply(cerveza$calificacion, cerveza$origen, length)),
Mediana = as.numeric(tapply(cerveza$calificacion, cerveza$origen, median)),
Moda = sapply(split(cerveza$calificacion, cerveza$origen), moda),
Pct_4_o_mas = as.numeric(tapply(cerveza$calificacion, cerveza$origen,
function(z) mean(z >= 4) * 100)),
stringsAsFactors = FALSE, row.names = NULL
)
flextable(calif_origen) |>
set_header_labels(Origen = "Origen", n = "n", Mediana = "Mediana",
Moda = "Moda", Pct_4_o_mas = "% con calificación ≥ 4") |>
colformat_double(j = "n", digits = 0, big.mark = ".", decimal.mark = ",") |>
colformat_double(j = "Mediana", digits = 1) |>
colformat_double(j = "Pct_4_o_mas", digits = 1) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
set_caption("Tabla 29. Calificación general según el origen") |>
autofit()Origen | n | Mediana | Moda | % con calificación ≥ 4 |
|---|---|---|---|---|
importada | 1.412.449 | 4.0 | 4 | 62.7 |
nacional | 174.165 | 4.0 | 4 | 64.8 |
Lectura de los resultados. La diferencia más notoria entre orígenes se presenta en el precio: la cerveza importada registra una media de 5.46 frente a 4.54 de la nacional. En contraste, los perfiles nutricionales son muy similares entre ambos grupos: las medianas de alcohol, carbohidratos y calorías difieren de forma marginal. Las calificaciones también son prácticamente equivalentes.
Esto sugiere que, dentro de esta base, la brecha de precio entre producto importado y nacional no se explica por diferencias en la composición nutricional ni por una mejor valoración del consumidor. Debe recordarse, sin embargo, que el precio es una variable simulada y que ambas variables presentan la dependencia estructural señalada en la Tabla 5.
El propósito declarado de la investigación incluye reconocer qué características se relacionan con mejores valoraciones. Para explorar esta pregunta de forma descriptiva se calcula la matriz de correlaciones de Spearman, apropiada cuando intervienen variables ordinales, ya que se basa en rangos y no exige distribuciones simétricas.
vars_cor <- c("precio", "alcohol", "carbohidratos", "calorias",
"calificacion", "aroma", "apariencia", "paladar", "sabor")
mat <- cor(cerveza[, vars_cor], method = "spearman")
cor_df <- data.frame(Variable = rownames(mat), round(mat, 2),
row.names = NULL, check.names = FALSE)
flextable(cor_df) |>
theme_booktabs() |>
align(align = "center", part = "all") |>
align(j = 1, align = "left", part = "body") |>
fontsize(size = 8, part = "all") |>
set_caption("Tabla 30. Matriz de correlaciones de Spearman") |>
autofit()Variable | precio | alcohol | carbohidratos | calorias | calificacion | aroma | apariencia | paladar | sabor |
|---|---|---|---|---|---|---|---|---|---|
precio | 1.00 | 0.14 | 0.17 | 0.15 | 0.24 | 0.25 | 0.21 | 0.24 | 0.25 |
alcohol | 0.14 | 1.00 | 0.82 | 0.99 | 0.18 | 0.38 | 0.31 | 0.33 | 0.35 |
carbohidratos | 0.17 | 0.82 | 1.00 | 0.89 | 0.15 | 0.33 | 0.25 | 0.28 | 0.29 |
calorias | 0.15 | 0.99 | 0.89 | 1.00 | 0.18 | 0.38 | 0.31 | 0.33 | 0.35 |
calificacion | 0.24 | 0.18 | 0.15 | 0.18 | 1.00 | 0.56 | 0.46 | 0.65 | 0.73 |
aroma | 0.25 | 0.38 | 0.33 | 0.38 | 0.56 | 1.00 | 0.50 | 0.56 | 0.67 |
apariencia | 0.21 | 0.31 | 0.25 | 0.31 | 0.46 | 0.50 | 1.00 | 0.51 | 0.49 |
paladar | 0.24 | 0.33 | 0.28 | 0.33 | 0.65 | 0.56 | 0.51 | 1.00 | 0.69 |
sabor | 0.25 | 0.35 | 0.29 | 0.35 | 0.73 | 0.67 | 0.49 | 0.69 | 1.00 |
cor_calif <- data.frame(
Atributo = c("Sabor", "Paladar", "Aroma", "Apariencia", "Precio",
"Alcohol", "Calorías", "Carbohidratos"),
Correlacion = c(mat["calificacion", "sabor"], mat["calificacion", "paladar"],
mat["calificacion", "aroma"], mat["calificacion", "apariencia"],
mat["calificacion", "precio"], mat["calificacion", "alcohol"],
mat["calificacion", "calorias"],
mat["calificacion", "carbohidratos"]),
stringsAsFactors = FALSE
)
cor_calif <- cor_calif[order(-cor_calif$Correlacion), ]
par(mar = c(4, 8, 3, 2))
barplot(rev(cor_calif$Correlacion), horiz = TRUE, las = 1,
names.arg = rev(cor_calif$Atributo), col = "#1F4E79", border = NA,
xlim = c(0, 0.8), xlab = "Correlación de Spearman con la calificación",
main = "Figura 9. Asociación de cada atributo con la calificación general")Los atributos sensoriales presentan las asociaciones más fuertes con la calificación general, encabezados por el sabor (0.73) y el paladar (0.65). La apariencia muestra la asociación más débil dentro del bloque sensorial (0.46).
Las variables de composición y precio presentan asociaciones claramente menores: el precio alcanza 0.24 y el contenido de alcohol 0.18.
Se observa además una correlación casi perfecta entre alcohol y calorías (0.99), lo que indica que ambas variables aportan prácticamente la misma información y resultan redundantes entre sí.
Los resultados permiten formular varias observaciones de interés para el propósito de la investigación:
La base no es un catálogo balanceado del mercado. Más de la mitad de las reseñas corresponde a un solo tipo de cerveza y cerca del 89 % a producto importado. Cualquier indicador global refleja principalmente el comportamiento de esos segmentos mayoritarios.
Las valoraciones están concentradas en la parte alta de la escala. La moda y la mediana coinciden en el nivel 4 en las cinco escalas sensoriales. Esto limita la capacidad de las escalas para discriminar entre productos y es coherente con el hecho de que quienes reseñan voluntariamente tienden a hacerlo sobre productos que ya conocen o prefieren.
La experiencia gustativa concentra la asociación con la valoración general. El sabor y el paladar son, con diferencia, los atributos más asociados a la calificación, mientras que la apariencia lo está en menor medida. Esto sugiere una hipótesis para etapas posteriores: la comunicación y el desarrollo de producto podrían priorizar los atributos gustativos.
El precio no acompaña a la valoración. Su asociación con la calificación es débil, y la diferencia de precio entre importado y nacional no se corresponde con diferencias nutricionales ni de valoración. Dado que se trata de una variable simulada, esta observación describe únicamente la base académica.
Existe redundancia entre variables nutricionales. Alcohol y calorías están correlacionadas casi perfectamente, por lo que en análisis posteriores bastaría con incluir una de las dos.
La base analizada reúne 1.586.614 reseñas sin datos faltantes. La moda del tipo de cerveza es cerveza normal y helada y la del origen es importada.
Las cinco escalas sensoriales presentan moda y mediana en el nivel 4, con distribuciones sesgadas hacia las valoraciones altas.
En las variables cuantitativas, el criterio de asimetría condujo a reportar media y desviación estándar para el precio y los carbohidratos, y mediana y rango intercuartílico para el alcohol y las calorías, dado su sesgo positivo.
La comparación por tipo muestra que la categoría baja en calorías / sin alcohol se diferencia del resto en todas las variables nutricionales y registra la menor proporción de calificaciones altas.
La comparación por origen muestra una diferencia apreciable en el precio, pero perfiles nutricionales y valoraciones muy similares entre producto importado y nacional.
Entre los atributos evaluados, el sabor y el paladar son los que presentan mayor asociación con la calificación general.
Advertencias sobre el alcance de este informe.
precio es simulada. Sus
valores describen únicamente esta base académica y no deben
interpretarse como precios reales de mercado ni extrapolarse a
decisiones comerciales.
Informe elaborado por Manuel Alejandro Vargas Imuez — Actividad 121,
Caso 1
Teoría de Probabilidades, Pontificia Universidad Javeriana
Cali