Com influeix el dia de la setmana i l’hora del dia en el tipus i quantitat de begudes comprades, així com en els ingressos generats?
Aquesta pregunta és rellevant perquè permet:
Les variables disponibles al dataset permeten respondre aquesta pregunta de manera exhaustiva, ja que tenim informació sobre:
Les dades provenen de Kaggle i representen transaccions reals d’una cafeteria durant l’any 2024.
# Exemple d'importació (modifiqueu segons calgui)
dades <- read_csv("coffe.csv")
## Rows: 3547 Columns: 11
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (6): cash_type, coffee_name, Time_of_Day, Weekday, Month_name, Date
## dbl (4): hour_of_day, money, Weekdaysort, Monthsort
## time (1): Time
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
dim(dades)
## [1] 3547 11
glimpse(dades)
## Rows: 3,547
## Columns: 11
## $ hour_of_day <dbl> 10, 12, 12, 13, 13, 15, 16, 18, 19, 19, 19, 10, 10, 11, 14…
## $ cash_type <chr> "card", "card", "card", "card", "card", "card", "card", "c…
## $ money <dbl> 38.7, 38.7, 38.7, 28.9, 38.7, 33.8, 38.7, 33.8, 38.7, 33.8…
## $ coffee_name <chr> "Latte", "Hot Chocolate", "Hot Chocolate", "Americano", "L…
## $ Time_of_Day <chr> "Morning", "Afternoon", "Afternoon", "Afternoon", "Afterno…
## $ Weekday <chr> "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "F…
## $ Month_name <chr> "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "M…
## $ Weekdaysort <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7…
## $ Monthsort <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3…
## $ Date <chr> "01/03/2024", "01/03/2024", "01/03/2024", "01/03/2024", "0…
## $ Time <time> 15:50:00, 19:22:00, 20:18:00, 46:33:00, 48:14:00, 39:47:0…
| Variable | Tipus | Descripció | Valors possibles / rang |
|---|---|---|---|
| hour_of_day | numèrica | Hora del dia en què es fa la compra | 0–23 |
| money | numèrica | Import pagat per la compra (preu total del tiquet) | ≥ 0 (p. ex. 0–50) |
| coffee_name | categòrica | Tipus de beguda adquirida | Latte, Americano, Hot Chocolate, etc. |
| Weekday | categòrica | Dia de la setmana | Mon–Sun (segons dataset: Fri, Sat, etc.) |
| Month_name | categòrica | Mes de l’any | Jan–Dec (p. ex. Mar) |
| Weekdaysort | numèrica | Codificació numèrica de l’ordre dels dies | 1–7 |
| Monthsort | numèrica | Codificació numèrica dels mesos | 1–12 |
| Date | text | Data completa de la transacció | Format dd/mm/aaaa |
| Time | text | Hora exacta de la transacció | Format hh:mm.ss |
No utilitzarem les columnes cash_type, Weekdaysort Monthsort (perque son redundant, ja tenim les categories del nom del mes i dies de la setmana) i , perque les considerem extres per respondre a la nostra pregunta.
# Modificacio de les dades perque siguin de tipus temps´
dades$Date <- as.Date(dades$Date, "%d/%m/%Y")
glimpse(dades)
## Rows: 3,547
## Columns: 11
## $ hour_of_day <dbl> 10, 12, 12, 13, 13, 15, 16, 18, 19, 19, 19, 10, 10, 11, 14…
## $ cash_type <chr> "card", "card", "card", "card", "card", "card", "card", "c…
## $ money <dbl> 38.7, 38.7, 38.7, 28.9, 38.7, 33.8, 38.7, 33.8, 38.7, 33.8…
## $ coffee_name <chr> "Latte", "Hot Chocolate", "Hot Chocolate", "Americano", "L…
## $ Time_of_Day <chr> "Morning", "Afternoon", "Afternoon", "Afternoon", "Afterno…
## $ Weekday <chr> "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "F…
## $ Month_name <chr> "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "M…
## $ Weekdaysort <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7…
## $ Monthsort <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3…
## $ Date <date> 2024-03-01, 2024-03-01, 2024-03-01, 2024-03-01, 2024-03-0…
## $ Time <time> 15:50:00, 19:22:00, 20:18:00, 46:33:00, 48:14:00, 39:47:0…
dades$datetime <- dades$Date + dades$Time
glimpse(dades)
## Rows: 3,547
## Columns: 12
## $ hour_of_day <dbl> 10, 12, 12, 13, 13, 15, 16, 18, 19, 19, 19, 10, 10, 11, 14…
## $ cash_type <chr> "card", "card", "card", "card", "card", "card", "card", "c…
## $ money <dbl> 38.7, 38.7, 38.7, 28.9, 38.7, 33.8, 38.7, 33.8, 38.7, 33.8…
## $ coffee_name <chr> "Latte", "Hot Chocolate", "Hot Chocolate", "Americano", "L…
## $ Time_of_Day <chr> "Morning", "Afternoon", "Afternoon", "Afternoon", "Afterno…
## $ Weekday <chr> "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "Fri", "F…
## $ Month_name <chr> "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "Mar", "M…
## $ Weekdaysort <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7…
## $ Monthsort <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3…
## $ Date <date> 2024-03-01, 2024-03-01, 2024-03-01, 2024-03-01, 2024-03-0…
## $ Time <time> 15:50:00, 19:22:00, 20:18:00, 46:33:00, 48:14:00, 39:47:0…
## $ datetime <date> 2024-03-02, 2024-03-02, 2024-03-02, 2024-03-03, 2024-03-0…
##El fragment de temps (dates) de quan a quan s'han pres les mesures:
floor_date(dades$Date, 'month')[1]
## [1] "2024-03-01"
last(floor_date(dades$Date, 'month'))
## [1] "2025-03-01"
Nombre d’observacions: 3,547 transaccions Període temporal: Març 2024 - Març 2025 (aproximadament 1 any) Unitat d’anàlisi: Cada fila representa una transacció individual
El conjunt de dades conté 3547 registres de compres fetes a la cafeteria. Segons les dates que hi apareixen, les vendes van des del 2024-03-01 fins al 2025-03-23. Aquest perríode ens permet observar com varien les compres al llarg dels dies i de les hores, i veure si hi ha moments en què la cafeteria ven més.
Durant la preparació de dades hem creat:
En aquest apartat descriurem el plantejament de les preguntes d’anàlisi, la formulació de les hipòtesis estadístiques i la selecció dels mètodes de inferencia que aplicarem més endavant.
Per reduir la pregunta general de l’estudi, es consideren les següents preguntes específiques:
L’import mitjà varia entre les diferents hores de dia? (variable hour_of_day)
Hi ha diferències en l’import mitjà de les transaccions segons el dia de la setmana? (variable Weekdaysort)
Quina seria la variancia del import mitja per el tipus de beguda? (variable coffee_name)
A partir de les preguntes anteriors, hem formulat les seguents hipotesis:
Hipòtesi nul·la (H₀): La despesa mitjana per transacció (money) és la mateixa per a totes les hores del dia.
Hipòtesi alternativa (H₁): Existeixen diferències en la despesa mitjana per transacció entre almenys dues hores del dia.
Hipòtesi nul·la (H₀): La despesa mitjana per transacció (money) és la mateixa per a tots els dies de la setmana.
Hipòtesi alternativa (H₁): Almenys un dia de la setmana presenta una despesa mitjana per transacció diferent.
Hipòtesi nul·la (H₀): La despesa mitjana per transacció (money) és la mateixa per a tots els tipus de beguda.
Hipòtesi alternativa (H₁): Existeixen diferències en la despesa mitjana per transacció entre almenys dos tipus de beguda.
Com que compararem la mitjana de money entre tres o més grups (hores del dia, dies de la setmana o tipus de beguda) s’utilitzara una anàlisi de la variància ANOVA.
Per aplicar els contrastos de hipotesis del test ANOVA, hem de tenir en compte les assumpcions del model (tot i que aquestes condicions no sempre es compleixen estrictament en dades reals).
Independència de les observacions: Cada fila del conjunt de dades correspon a una transacció individual. No es disposa d’informació sobre clients, per tant considerem que son independents.
Normalitat de la variable resposta: ANOVA assumeix una distribució aproximadament normal de la variable resposta (money) dins de cada grup.
Homogeneïtat de les variàncies: Assumim que la variància de la variable resposta és similar entre els grups comparats.
anova_hour <- aov(money ~ hour_of_day, data = dades)
summary(anova_hour)
## Df Sum Sq Mean Sq F value Pr(>F)
## hour_of_day 1 3468 3468 152 <2e-16 ***
## Residuals 3545 80900 23
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
p < 0.05 => Tenim prou evidencies per rebutjar la hipotesi nul·la. ### 2.2 Segons el dia de la setmana Weekday
anova_weekday <- aov(money ~ Weekday, data = dades)
summary(anova_weekday)
## Df Sum Sq Mean Sq F value Pr(>F)
## Weekday 6 121 20.11 0.845 0.535
## Residuals 3540 84247 23.80
p = 0.535 > 0.05 => NO tenim prou evidencia per rebutjar la hipotesi nul·la.
anova_coffee <- aov(money ~ coffee_name, data = dades)
summary(anova_coffee)
## Df Sum Sq Mean Sq F value Pr(>F)
## coffee_name 7 73122 10446 3287 <2e-16 ***
## Residuals 3539 11246 3
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
p < 0.05 => Tenim prou evidencies per rebutjar la hipotesi nul·la.
A continuació es mostren les primeres taula i diversos gràfics per explorar els patrons principals del conjunt de dades en relació amb la pregunta d’estudi.
# Estadístiques bàsiques
summary(dades$money)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 18.12 27.92 32.82 31.65 35.76 38.70
summary(dades$hour_of_day)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 6.00 10.00 14.00 14.19 18.00 22.00
table(dades$coffee_name)
##
## Americano Americano with Milk Cappuccino Cocoa
## 564 809 486 239
## Cortado Espresso Hot Chocolate Latte
## 287 129 276 757
# Mitjana d’ingressos per hora
aggregate(money ~ hour_of_day, data = dades, mean)
## hour_of_day money
## 1 6 29.88000
## 2 7 32.34114
## 3 8 29.86332
## 4 9 30.01769
## 5 10 31.09305
## 6 11 29.86961
## 7 12 30.78680
## 8 13 31.23893
## 9 14 31.88356
## 10 15 31.67805
## 11 16 32.48863
## 12 17 32.31966
## 13 18 32.85596
## 14 19 33.85135
## 15 20 33.01136
## 16 21 32.80995
## 17 22 32.16956
# Mitjana d’ingressos per dia de la setmana
aggregate(money ~ Weekday, data = dades, mean)
## Weekday money
## 1 Fri 31.58395
## 2 Mon 31.91746
## 3 Sat 31.34791
## 4 Sun 31.82831
## 5 Thu 31.55176
## 6 Tue 31.76290
## 7 Wed 31.50092
Observacions inicials:
-Preus: Oscil·len entre 18.12€ i 38.70€, amb una mitjana al voltant dels 32€ -Hores operatives: La cafeteria opera majoritàriament entre les 7h i les 22h -Begudes més populars: Cal analitzar la distribució
Es mostra com es reparteixen les compres al llarg del dia i com varia la despesa segons el dia de la setmana. Podem veure que hi ha hores i dies amb més ventes que altres.
library(ggplot2)
ggplot(dades, aes(x = coffee_name, y = money, fill = coffee_name)) +
geom_bar(stat = "summary", fun = "sum") +
labs(title = "Ingressos totals per tipus de beguda",
x = "Tipus de beguda",
y = "Total ingressos") +
theme_minimal()
Aquest gràfic ajuda a veure quines begudes generen més ingressos. Podem veure que hi ha una variació clara en la venta de les diferents begudes.
# Boxplot per detectar valors extrems
boxplot(dades$money, main = "Detecció de valors inusuals en 'money'")
# Observacions potencialment extremes (Top 1%)
subset(dades, money > quantile(money, 0.99))
## # A tibble: 0 × 12
## # ℹ 12 variables: hour_of_day <dbl>, cash_type <chr>, money <dbl>,
## # coffee_name <chr>, Time_of_Day <chr>, Weekday <chr>, Month_name <chr>,
## # Weekdaysort <dbl>, Monthsort <dbl>, Date <date>, Time <time>,
## # datetime <date>
Observem si hi ha tiquets amb imports molt més alts del normal.
ggplot(dades, aes(x = money)) +
geom_histogram(bins = 30, fill = "#8B4513", color = "white") +
theme_minimal() +
labs(
title = "Distribució dels Imports per Transacció",
x = "Import (€)",
y = "Freqüència"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
Interpretació:
-Es detecten 4-5 pics principals corresponents als diferents preus de begudes -Els preus semblen estar agrupats al voltant de valors específics (probablement els diferents tipus de begudes) -No s’observen valors aberrants significatius
vendes_hora <- dades %>%
group_by(hour_of_day) %>%
summarise(
num_vendes = n(),
ingressos_totals = sum(money, na.rm = TRUE)
)
ggplot(vendes_hora, aes(x = hour_of_day, y = num_vendes)) +
geom_col(fill = "#D2691E") +
geom_line(color = "red", size = 1) +
theme_minimal() +
scale_x_continuous(breaks = 6:22) +
labs(
title = "Nombre de Vendes per Hora del Dia",
x = "Hora",
y = "Nombre de Transaccions"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Patrons identificats:
Connexió amb la pregunta d’estudi: Aquest patró temporal és clau per entendre quan concentrar recursos i personal.
En aquesta secció presentem estadístiques i visualitzacions que ajuden a respondre la pregunta d’estudi:
Quina és la relació entre el dia de la setmana, l’hora i el tipus de beguda amb la quantitat gastada?
# Estadístiques bàsiques d’import i hora
summary(dades[, c("hour_of_day", "money")])
## hour_of_day money
## Min. : 6.00 Min. :18.12
## 1st Qu.:10.00 1st Qu.:27.92
## Median :14.00 Median :32.82
## Mean :14.19 Mean :31.65
## 3rd Qu.:18.00 3rd Qu.:35.76
## Max. :22.00 Max. :38.70
# Desviació estàndard
sd_hour <- sd(dades$hour_of_day, na.rm = TRUE)
sd_money <- sd(dades$money, na.rm = TRUE)
sd_hour
## [1] 4.23401
sd_money
## [1] 4.877754
Aquest, ens dona una idea general de com es distribueixen les hores de compra i quins preus són més habituals. La mitjan i la mediana ens indiquen quines són les tendències generals, la desviació estàndard ens diu a quin punt les dades estan concentrades o disperses.
aggregate(money ~ Weekday, data = dades, FUN = function(x) c(mean = mean(x), median = median(x), sd = sd(x)))
## Weekday money.mean money.median money.sd
## 1 Fri 31.583947 32.820000 4.913948
## 2 Mon 31.917463 32.820000 4.511083
## 3 Sat 31.347915 32.820000 5.003080
## 4 Sun 31.828305 32.820000 4.878133
## 5 Thu 31.551765 32.820000 5.187470
## 6 Tue 31.762902 32.820000 4.738134
## 7 Wed 31.500920 32.820000 4.939150
library(ggplot2)
ggplot(dades, aes(x = Weekday, y = money)) +
geom_boxplot(fill = "lightblue") +
labs(title = "Distribució de diners gastats per dia de la setmana",
x = "Dia",
y = "Import (money)") +
theme_minimal()
Aquesta comparació entre dies, ens ajuda a veure si hi ha diferència en la despesa segons el dia de la setmana.
boxplot(dades$money, main = "Valors inusuals de diners gastats")
subset(dades, money > quantile(money, 0.99)) # top 1% de valors
## # A tibble: 0 × 12
## # ℹ 12 variables: hour_of_day <dbl>, cash_type <chr>, money <dbl>,
## # coffee_name <chr>, Time_of_Day <chr>, Weekday <chr>, Month_name <chr>,
## # Weekdaysort <dbl>, Monthsort <dbl>, Date <date>, Time <time>,
## # datetime <date>
# Resum per dia de la setmana
resum_setmana <- dades %>%
group_by(Weekday) %>%
summarise(
Transaccions = n(),
Ingressos_Total = sum(money, na.rm = TRUE),
Import_Mitjà = mean(money, na.rm = TRUE),
Import_Mediana = median(money, na.rm = TRUE),
Desviacio_Std = sd(money, na.rm = TRUE)
) %>%
arrange(match(Weekday, c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")))
knitr::kable(resum_setmana,
caption = "Estadístiques per Dia de la Setmana",
digits = 2)
| Weekday | Transaccions | Ingressos_Total | Import_Mitjà | Import_Mediana | Desviacio_Std |
|---|---|---|---|---|---|
| Mon | 544 | 17363.10 | 31.92 | 32.82 | 4.51 |
| Tue | 572 | 18168.38 | 31.76 | 32.82 | 4.74 |
| Wed | 500 | 15750.46 | 31.50 | 32.82 | 4.94 |
| Thu | 510 | 16091.40 | 31.55 | 32.82 | 5.19 |
| Fri | 532 | 16802.66 | 31.58 | 32.82 | 4.91 |
| Sat | 470 | 14733.52 | 31.35 | 32.82 | 5.00 |
| Sun | 419 | 13336.06 | 31.83 | 32.82 | 4.88 |
Hipòtesis emergents:
1.Hi ha una clara diferència en el volum de vendes segons l’hora del dia 2.El tipus de beguda està correlacionat amb el moment del dia 3.Els caps de setmana poden tenir un patró de consum diferent dels dies laborables
p1 <- ggplot(dades, aes(x = factor(hour_of_day), y = money)) +
geom_boxplot(fill = "#D2691E", alpha = 0.7) +
labs(title = "Distribució de l'import per hora del dia",
x = "Hora del dia",
y = "Import (€)") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
El gràfic permet observar diferències clares en la distribució dels imports segons l’hora del dia. Algunes hores presenten una mediana més elevada i una major dispersió, fet que suggereix que l’hora del dia podria tenir un efecte significatiu sobre l’import de les vendes. Aquest resultat justifica l’aplicació d’un ANOVA per contrastar formalment les diferències entre hores.
mitjanes_hora <- dades %>%
group_by(hour_of_day) %>%
summarise(
mitjana = mean(money, na.rm = TRUE),
sd = sd(money, na.rm = TRUE),
n = n(),
se = sd / sqrt(n),
ic_inf = mitjana - 1.96 * se,
ic_sup = mitjana + 1.96 * se
)
p2 <- ggplot(mitjanes_hora, aes(x = hour_of_day, y = mitjana)) +
geom_line(color = "#8B4513", size = 1) +
geom_point(size = 3, color = "#D2691E") +
geom_errorbar(aes(ymin = ic_inf, ymax = ic_sup),
width = 0.3, color = "#8B4513", alpha = 0.6) +
labs(title = "Import mitjà per hora amb intervals de confiança (95%)",
x = "Hora del dia",
y = "Import mitjà (€)") +
theme_minimal()
S’observa una variació clara de l’import mitjà al llarg del dia, amb franges horàries on la mitjana és notablement superior. Els intervals de confiança permeten visualitzar la incertesa associada a cada estimació i suggereixen que algunes diferències entre hores no es deuen únicament a la variabilitat aleatòria, reforçant la plausibilitat d’un efecte significatiu de l’hora del dia sobre l’import.
m_hour <- aov(money ~ factor(hour_of_day), data = dades)
dades_residus_hora <- tibble(
ajustats = fitted(m_hour),
residus = residuals(m_hour)
)
p3 <- ggplot(dades_residus_hora, aes(x = ajustats, y = residus)) +
geom_point(alpha = 0.5, color = "#8B4513") +
geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
geom_smooth(method = "loess", se = FALSE, color = "blue") +
labs(title = "Residus vs Valors ajustats (hora del dia)",
x = "Valors ajustats",
y = "Residus") +
theme_minimal()
El núvol de punts no mostra patrons sistemàtics evidents ni una forma de ventall pronunciada, la qual cosa indica que l’assumpció d’homocedasticitat es compleix de manera raonable. Això suggereix que el model ANOVA és adequat des del punt de vista de la variància dels errors.
p4 <- ggplot(dades_residus_hora, aes(sample = residus)) +
stat_qq(color = "#8B4513") +
stat_qq_line(color = "red") +
labs(title = "Q-Q Plot - Normalitat dels residus (hora del dia)",
x = "Quantils teòrics",
y = "Quantils observats") +
theme_minimal()
Els punts segueixen aproximadament la línia diagonal, amb petites desviacions als extrems. Aquest comportament indica que l’assumpció de normalitat dels residus és raonablement satisfactòria, especialment tenint en compte la mida de la mostra.
dades_ordenat <- dades %>%
mutate(Weekday = factor(Weekday,
levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")))
p5 <- ggplot(dades_ordenat, aes(x = Weekday, y = money)) +
geom_boxplot(fill = "#A0522D", alpha = 0.7) +
labs(title = "Distribució de l'import per dia de la setmana",
x = "Dia de la setmana",
y = "Import (€)") +
theme_minimal()
El boxplot mostra una distribució força similar dels imports entre els diferents dies de la setmana, amb lleugeres diferències en la mediana i la dispersió. Aquest gràfic suggereix que l’efecte del dia de la setmana podria ser més moderat que l’efecte de l’hora del dia, fet que serà contrastat amb l’ANOVA corresponent.
mitjanes_dia <- dades_ordenat %>%
group_by(Weekday) %>%
summarise(
mitjana = mean(money, na.rm = TRUE),
sd = sd(money, na.rm = TRUE),
n = n(),
se = sd / sqrt(n),
ic_inf = mitjana - 1.96 * se,
ic_sup = mitjana + 1.96 * se
)
p6 <- ggplot(mitjanes_dia, aes(x = Weekday, y = mitjana)) +
geom_col(fill = "#A0522D", alpha = 0.7) +
geom_errorbar(aes(ymin = ic_inf, ymax = ic_sup),
width = 0.3, color = "black") +
geom_text(aes(label = round(mitjana, 2)), vjust = -0.5, size = 3) +
labs(title = "Import mitjà per dia amb intervals de confiança (95%)",
x = "Dia de la setmana",
y = "Import mitjà (€)") +
theme_minimal()
Les mitjanes diàries presenten diferències relativament petites, amb intervals de confiança que se solapen en diversos casos. Això indica que, visualment, les diferències entre dies són menys marcades, tot i que l’ANOVA permetrà determinar si aquestes diferències són estadísticament significatives.
p7 <- ggplot(dades, aes(x = reorder(coffee_name, money, median), y = money)) +
geom_boxplot(aes(fill = coffee_name), alpha = 0.7, show.legend = FALSE) +
coord_flip() +
labs(title = "Distribució de l'import per tipus de beguda",
x = "Tipus de beguda",
y = "Import (€)") +
theme_minimal()
Aquest gràfic evidencia diferències clares en la distribució dels imports segons el tipus de beguda. Algunes begudes presenten medians més elevades i una major dispersió, fet coherent amb una estructura de preus diferenciada entre productes.
mitjanes_beguda <- dades %>%
group_by(coffee_name) %>%
summarise(
mitjana = mean(money, na.rm = TRUE),
sd = sd(money, na.rm = TRUE),
n = n(),
se = sd / sqrt(n),
ic_inf = mitjana - 1.96 * se,
ic_sup = mitjana + 1.96 * se
) %>%
arrange(mitjana)
p8 <- ggplot(mitjanes_beguda, aes(x = reorder(coffee_name, mitjana), y = mitjana)) +
geom_col(fill = "#CD853F", alpha = 0.7) +
geom_errorbar(aes(ymin = ic_inf, ymax = ic_sup),
width = 0.3, color = "black") +
coord_flip() +
labs(title = "Import mitjà per tipus de beguda amb IC (95%)",
x = "Tipus de beguda",
y = "Import mitjà (€)") +
theme_minimal()
Les mitjanes dels imports per tipus de beguda mostren diferències substancials, amb intervals de confiança que en molts casos no se solapen. Això suggereix un efecte fort del tipus de beguda sobre l’import de la transacció, fet esperable donada la naturalesa del producte.
m_coffee <- aov(money ~ coffee_name, data = dades)
dades_residus_coffee <- tibble(
ajustats = fitted(m_coffee),
residus = residuals(m_coffee),
beguda = dades$coffee_name
)
p9 <- ggplot(dades_residus_coffee, aes(x = ajustats, y = residus)) +
geom_point(aes(color = beguda), alpha = 0.5, show.legend = FALSE) +
geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
geom_smooth(method = "loess", se = FALSE, color = "blue") +
labs(title = "Residus vs Valors ajustats (tipus de beguda)",
x = "Valors ajustats",
y = "Residus") +
theme_minimal()
Tot i una major dispersió associada a certs tipus de beguda, no s’observen patrons sistemàtics clars en els residus. Això indica que el model ANOVA és raonablement adequat també per analitzar l’efecte del tipus de beguda.
# 10. Comparació de la variabilitat explicada
models_r2 <- tibble(
Model = c("Hora del dia", "Dia setmana", "Tipus beguda"),
R2 = c(
summary(aov(money ~ factor(hour_of_day), data = dades))[[1]][1,2] /
sum(summary(aov(money ~ factor(hour_of_day), data = dades))[[1]][,2]),
summary(aov(money ~ Weekday, data = dades))[[1]][1,2] /
sum(summary(aov(money ~ Weekday, data = dades))[[1]][,2]),
summary(aov(money ~ coffee_name, data = dades))[[1]][1,2] /
sum(summary(aov(money ~ coffee_name, data = dades))[[1]][,2])
)
)
p10 <- ggplot(models_r2, aes(x = reorder(Model, R2), y = R2)) +
geom_col(fill = c("#8B4513", "#A0522D", "#CD853F"), alpha = 0.8) +
geom_text(aes(label = paste0(round(R2 * 100, 1), "%")),
hjust = -0.2, size = 4) +
coord_flip() +
ylim(0, 1) +
labs(title = "Comparació de variància explicada (R²) dels models ANOVA",
x = "Model",
y = "Proporció de variància explicada (R²)") +
theme_minimal()
El model basat en el tipus de beguda explica una proporció de variància clarament superior, seguit pel model de l’hora del dia. El dia de la setmana presenta el menor poder explicatiu. Aquest resultat indica que el preu del producte és el principal factor determinant de l’import de la transacció, mentre que els factors temporals tenen un efecte secundari.
# ==============================================================================
# MOSTRAR TOTS ELS GRÀFICS
# ==============================================================================
# Combinació de gràfics amb patchwork
print("Gràfics ANOVA - Hora del dia:")
## [1] "Gràfics ANOVA - Hora del dia:"
(p1 | p2) / (p3 | p4)
## `geom_smooth()` using formula = 'y ~ x'
print("\nGràfics ANOVA - Dia de la setmana:")
## [1] "\nGràfics ANOVA - Dia de la setmana:"
(p5 | p6)
print("\nGràfics ANOVA - Tipus de beguda:")
## [1] "\nGràfics ANOVA - Tipus de beguda:"
(p7 | p8) / p9
## `geom_smooth()` using formula = 'y ~ x'
print("\nComparació de models:")
## [1] "\nComparació de models:"
p10
# També pots guardar els gràfics
# ggsave("anova_hora.png", (p1 | p2) / (p3 | p4), width = 12, height = 10)
# ggsave("anova_weekday.png", (p5 | p6), width = 10, height = 5)
# ggsave("anova_beguda.png", (p7 | p8) / p9, width = 12, height = 10)
# ggsave("comparacio_models.png", p10, width = 8, height = 5)
Patrons Temporals Clars:
Tres pics principals de vendes: matí (8-11h), tarda (14-17h) i nit primerenca (19-21h)
Els matins són el moment de màxima activitat
Preferències de Begudes:
Americano domina en nombre de vendes
Les preferències varien segons el moment del dia (cafès senzills al matí, més elaborats a la tarda)
Ingressos:
Els ingressos són relativament constants entre dies laborables
Hi ha variabilitat mensual que cal explorar més
Preus Estratificats:
El dataset mostra 4-5 nivells de preu clars, corresponents als diferents tipus de begudes
Cal verificar si tenim dades completes per cada mes Alguns mesos poden tenir més dades que altres
No tenim informació sobre:
Condicions meteorològiques Esdeveniments especials o festius Nombre de clients (vs. transaccions) Cost de producció per calcular benefici net
Tots els pagaments són amb targeta (cash_type = “card”). No hi ha valors perduts evidents, però cal verificar inconsistències.
Tot i tenir 3,547 observacions, alguns segments (hores específiques, dies concrets) poden tenir poca representació.
Valor Aplicat: Els resultats d’aquesta anàlisi poden ajudar a:
Optimitzar la dotació de personal segons hores punta Gestionar millor l’inventari segons preferències temporals Dissenyar promocions específiques per hores/dies de menys activitat Millorar l’oferta de productes segons moment del dia