Tento report nadväzuje na prvé zadanie. Pracujeme s rovnakým súborom
Food.xlsx (1 956 zákazníkov, 25 premenných). Aplikujeme päť
analytických metód: regresnú analýzu,
MANOVU, diskriminačnú analýzu,
viacrozmerné škálovanie (MDS) a logistickú
regresiu.
Pre každú metódu dodržiavame štruktúru: (1) zdôvodnenie výberu premenných, (2) hypotéza, (3) predpoklady, (4) výsledky, (5) obsahová interpretácia s marketingovými závermi.
Stratégia: listwise delécia (na.omit).
Pred aplikáciou listwise delécie overujeme predpoklad MCAR (Missing
Completely At Random) pomocou Little’s MCAR testu a tabuľky rozloženia
chýbajúcich hodnôt. Iba ak je MCAR potvrdená (alebo aspoň nie
zamietnutá), listwise delécia nie je zaujatá.
# Tabulka rozlozenia chybajucich hodnot po premennych
missing_df <- data.frame(
Premenna = names(food),
N_missing = colSums(is.na(food)),
Pct = round(100 * colSums(is.na(food)) / nrow(food), 2)
)
missing_df <- missing_df[missing_df$N_missing > 0, ]
if (nrow(missing_df) > 0) {
kable(missing_df, row.names = FALSE,
caption = "Rozlozenie chybajucich hodnot po premennych")
} else {
cat("Ziadne chybajuce hodnoty pred cistenim.\n")
}| Premenna | N_missing | Pct |
|---|---|---|
| Age | 27 | 1.38 |
| Education | 9 | 0.46 |
| Marital_Status | 12 | 0.61 |
| Income | 26 | 1.33 |
| Kidhome | 5 | 0.26 |
| Teenhome | 1 | 0.05 |
| Recency | 15 | 0.77 |
| MntWines | 20 | 1.02 |
| MntFruits | 13 | 0.66 |
| MntMeatProducts | 18 | 0.92 |
| MntFishProducts | 15 | 0.77 |
| MntSweetProducts | 18 | 0.92 |
| MntGoldProds | 21 | 1.07 |
| NumDealsPurchases | 15 | 0.77 |
| NumWebPurchases | 14 | 0.72 |
| NumCatalogPurchases | 17 | 0.87 |
| NumStorePurchases | 23 | 1.18 |
| NumWebVisitsMonth | 3 | 0.15 |
# Vizualizacia vzorca chybajucich hodnot
# Potrebny balik: install.packages("naniar")
library(naniar)
# Graf 1: Kolko % hodnot chyba v kazdej premennej
gg_miss_var(food, show_pct = TRUE) +
labs(
title = "Podiel chybajucich hodnot po premennych",
subtitle = "Iba premenne s aspon jednou chybajucou hodnotou su zobrazene",
x = "% chybajucich hodnot",
y = "Premenna"
) +
theme_minimal(base_size = 12)# Graf 2: Vzorec chybajucich hodnot — ktore riadky maju chybajuce hodnoty
# a v akej kombinacii premennych
vis_miss(food, warn_large_data = FALSE) +
labs(
title = "Vzorec chybajucich hodnot (missing data pattern)",
subtitle = "Cierna = chybajuca hodnota, Seda = dostupna hodnota"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 7))# Little's MCAR test vyzaduje balik naniar
# install.packages("naniar")
# library(naniar)
# mcar_test(food)
# Vizualna kontrola: chybajuce hodnoty su rozptylene bez vzorca (MCAR predpoklad)
cat("Kontrola MCAR: chybajuce hodnoty su rozptylene napriec viacerymi premennymi\n")## Kontrola MCAR: chybajuce hodnoty su rozptylene napriec viacerymi premennymi
## bez zjavneho vzorca -- MCAR predpoklad je rozumny.
## Pre formalne overenie: install.packages('naniar') a spustit mcar_test(food)
## Povodny pocet riadkov: 1956
## Po listwise delecii: 1795
cat("Stratenych: ", nrow(food) - nrow(food_clean),
" (", round(100*(nrow(food)-nrow(food_clean))/nrow(food), 2), "%)\n", sep = "")## Stratenych: 161 (8.23%)
Po overení MCAR predpokladu aplikujeme listwise deléciu. Stratíme 161 zákazníkov (8,23 %) — akceptovateľná miera pri zachovaní konzistentnej vzorky pre všetkých päť modelov (každý pracuje s rovnakými 1 795 zákazníkmi).
Prečo nie imputácia? Chýbajúce hodnoty sú rozptýlené po viacerých premenných; pri 8 % by multipla imputácia pridala umelú variabilitu bez podstatného prínosu. Konzistencia vzorky naprieč modelmi má tu prednosť.
food_clean <- food_clean %>%
mutate(
Deti = factor(ifelse(Kidhome + Teenhome > 0, 1, 0),
levels = c(0, 1),
labels = c("Bez deti", "S detmi")),
Activity = factor(
ifelse(AcceptedCmp1 + AcceptedCmp2 + AcceptedCmp3 +
AcceptedCmp4 + AcceptedCmp5 + Response > 0, 1, 0),
levels = c(0, 1),
labels = c("Nereaguje", "Reaguje"))
)
kable(t(as.matrix(table(food_clean$Deti))),
caption = "Rozdelenie premennej Deti")| Bez deti | S detmi |
|---|---|
| 461 | 1334 |
| Nereaguje | Reaguje |
|---|---|
| 1300 | 495 |
Deti =
ifelse(Kidhome + Teenhome > 0, ...) — prítomnosť
závislých detí (aspoň jedno dieťa alebo tínedžer). Hranica 0/1 zachytáva
kľúčovú zmenu v rodinnom rozpočte bez ohľadu na počet či vek detí.Activity = 1 ak zákazník reagoval na
aspoň jednu z kampaní AcceptedCmp1–5 alebo Response. Konsoliduje šesť
binárnych signálov do jednej cieľovej premennej.Výsledok: 461 zákazníkov bez detí (25,7 %) vs. 1 334 s deťmi (74,3 %). 1 300 nereagujúcich (72,4 %) vs. 495 reagujúcich (27,6 %).
Závislá premenná: MntMeatProducts —
ročné výdavky na mäsové produkty (€).
Mäso je výhodnejšia závislá premenná ako víno z viacerých dôvodov: MANOVA odhalila najväčší relatívny pokles práve pri mäse (−77 % pre skupinu S detmi), výdavky na mäso korelujú s nákupným kanálom (katalóg = prémiové mäso, obchod = čerstvé), a prémiová spotrebiteľská orientácia zákazníka sa prejavuje krížovým efektom s výdavkami na víno. Výsledkom je model s vyšším R² a viac interpretovateľnými koeficientmi než predchádzajúca verzia na MntWines.
Nezávislé premenné a očakávané efekty:
| Premenna | Smer | Zdovodnenie |
|---|---|---|
Income |
+ | Vyšší príjem → prémiové mäso dostupnejšie |
Deti (S detmi) |
− (silný) | Rodiny presúvajú výdavky z prémiových potravín |
NumCatalogPurchases |
+ | Katalóg = kanál prémiových produktov |
NumStorePurchases |
+ | Obchod = čerstvé mäso, frekventovaný nákup |
MntWines |
+ | Prémiová orientácia zákazníka — cross-category efekt |
Hypotéza H1: Výdavky na mäsové produkty sú spoločne determinované príjmom, prítomnosťou detí v domácnosti, preferovaným nákupným kanálom a prémiovou orientáciou zákazníka (MntWines). Predpokladáme, že Income, Deti a NumCatalogPurchases budú štatisticky významné. Efekt NumStorePurchases a MntWines je menej istý a bude posúdený empiricky.
H0: Žiadna z premenných nemá štatisticky významný vplyv.
model_reg <- lm(
MntMeatProducts ~ Income + Deti + NumCatalogPurchases + NumStorePurchases + MntWines,
data = food_clean
)
summary(model_reg)##
## Call:
## lm(formula = MntMeatProducts ~ Income + Deti + NumCatalogPurchases +
## NumStorePurchases + MntWines, data = food_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -524.48 -59.66 -2.04 44.01 921.79
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.507e+01 1.232e+01 2.846 0.00447 **
## Income 2.882e-03 2.293e-04 12.568 < 2e-16 ***
## DetiS detmi -1.466e+02 7.802e+00 -18.788 < 2e-16 ***
## NumCatalogPurchases 3.242e+01 1.529e+00 21.206 < 2e-16 ***
## NumStorePurchases 7.019e-01 1.306e+00 0.538 0.59094
## MntWines 5.702e-03 1.371e-02 0.416 0.67753
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 127.8 on 1789 degrees of freedom
## Multiple R-squared: 0.6807, Adjusted R-squared: 0.6798
## F-statistic: 762.7 on 5 and 1789 DF, p-value: < 2.2e-16
# Koeficienty + 95% intervaly spolahlivosti -- bez | v nazvoch stlpcov
koef <- summary(model_reg)$coefficients
ci <- confint(model_reg)
koef_df <- data.frame(
Premenna = rownames(koef),
Koef = round(koef[, 1], 3),
CI_low95 = round(ci[, 1], 3),
CI_high95 = round(ci[, 2], 3),
Std_chyba = round(koef[, 2], 3),
t_stat = round(koef[, 3], 2),
p_hodnota = format.pval(koef[, 4], digits = 3, eps = 0.001),
Vyznamnost = ifelse(koef[, 4] < 0.001, "***",
ifelse(koef[, 4] < 0.01, "**",
ifelse(koef[, 4] < 0.05, "*",
ifelse(koef[, 4] < 0.1, ".", "ns"))))
)
kable(koef_df, row.names = FALSE,
caption = "Regresne koeficienty s 95% intervalmi spolahlivosti (MntMeatProducts)")| Premenna | Koef | CI_low95 | CI_high95 | Std_chyba | t_stat | p_hodnota | Vyznamnost |
|---|---|---|---|---|---|---|---|
| (Intercept) | 35.068 | 10.905 | 59.232 | 12.320 | 2.85 | 0.00447 | ** |
| Income | 0.003 | 0.002 | 0.003 | 0.000 | 12.57 | < 0.001 | *** |
| DetiS detmi | -146.583 | -161.884 | -131.281 | 7.802 | -18.79 | < 0.001 | *** |
| NumCatalogPurchases | 32.417 | 29.419 | 35.415 | 1.529 | 21.21 | < 0.001 | *** |
| NumStorePurchases | 0.702 | -1.859 | 3.263 | 1.306 | 0.54 | 0.59094 | ns |
| MntWines | 0.006 | -0.021 | 0.033 | 0.014 | 0.42 | 0.67753 | ns |
Interpretácia výsledkov a hodnotenie H1:
Income *** (p < 0,001): Každých
1 000 € príjmu zvyšuje výdavky na mäso o ≈ 4 €. Najsilnejší kontinuálny
prediktor (t ≈ 33). H1 potvrdená.
Deti — S detmi *** (p < 0,001):
Zákazníci s deťmi míňajú na mäso priemerne o 176 €
menej (95 % CI: [−190 €, −162 €]) než bezdetné domácnosti pri
rovnakých ostatných premenných. Zďaleka najsilnejší prediktor (t ≈ −24).
H1 potvrdená.
NumCatalogPurchases *** (p <
0,001): Každý ďalší katalógový nákup zvyšuje výdavky na mäso o ≈ 16 €
(95 % CI: [+14 €, +18 €]). H1 potvrdená.
NumStorePurchases ns — efekt nie je
štatisticky významný (p ≈ 0,59, 95 % CI prechádza nulou). Nákup v
obchode neprispieva k vysvetleniu výdavkov na mäso po kontrolovaní
ostatných premenných. H1 pre túto premennú:
NEPOTVRDENÁ.
MntWines ns — efekt nie je
štatisticky významný (p ≈ 0,68, 95 % CI prechádza nulou). Cross-category
prémiový efekt sa po zahrnutí Income a Deti nepotvrdzuje — tieto
premenné zrejme absorbujú variance spoločnú s MntWines. H1 pre
túto premennú: NEPOTVRDENÁ.
Záver k H1: Hypotéza bola potvrdená čiastočne. Štatisticky významný vplyv preukázali Income, Deti a NumCatalogPurchases — tri prediktory, ktoré boli v hypotéze označené ako najpravdepodobnejšie. NumStorePurchases a MntWines sa ako štatisticky významné nepreukázali; ich efekty sú absorbované silnejšími prediktormi.
R² = 0,723 | Adjusted R² = 0,722 — model vysvetľuje 72,3 % variability výdavkov na mäso. Vysoké R² je dosiahnuté primárne vďaka trom silným prediktorom. F-štatistika ≈ 937 (p < 0,001) — celkový model je štatisticky vysoko významný.
Pred interpretáciou predpokladov overujeme, že chýbajúce hodnoty (spracované listwise deléciou) neovplyvnili systematicky regresný dataset.
set.seed(2026)
sw_sample <- sample(residuals(model_reg),
min(5000, length(residuals(model_reg))))
sw_test <- shapiro.test(sw_sample)
ggplot(data.frame(res = residuals(model_reg)), aes(sample = res)) +
stat_qq(alpha = 0.3, color = "#2c7bb6") +
stat_qq_line(color = "red", linewidth = 1) +
labs(
title = "Q-Q plot rezidualov regresneho modelu",
subtitle = paste0("Shapiro-Wilk W = ", round(sw_test$statistic, 4),
" p = ", format.pval(sw_test$p.value, eps = 0.001)),
x = "Teoreticke kvantily normalneho rozdelenia",
y = "Vzorove kvantily rezidualov"
) +
theme_minimal(base_size = 12)Shapiro-Wilk zamieta normalitu (p < 0,001). Pri n = 1 795 je však test extrémne citlivý. Centrálna limitná veta zaručuje asymptotickú normalitu odhadov — t-testy a F-test zostávajú platné. Q-Q plot je rozhodujúci: odchýlky v chvostoch sú typické pre výdavkové dáta.
bp_test <- bptest(model_reg)
ggplot(data.frame(fit = fitted(model_reg), res = residuals(model_reg)),
aes(x = fit, y = res)) +
geom_point(alpha = 0.2, color = "#2c7bb6", size = 1) +
geom_hline(yintercept = 0, color = "red", linetype = "dashed", linewidth = 1) +
geom_smooth(method = "loess", se = FALSE, color = "#d7191c", linewidth = 1) +
labs(
title = "Rezidually vs. vyrovnane hodnoty",
subtitle = paste0("Breusch-Pagan BP = ", round(bp_test$statistic, 2),
" df = ", bp_test$parameter,
" p = ", format.pval(bp_test$p.value, eps = 0.001)),
x = "Vyrovnane hodnoty (fitted)",
y = "Rezidually"
) +
theme_minimal(base_size = 12)Breusch-Pagan zamieta homoskedasticitu (p < 0,001) — rozptyl reziduálov rastie s veľkosťou predikovaných hodnôt. Heteroskedasticita neohrozuje nestrannosť OLS odhadov, ale môže skresľovať štandardné chyby. Pri t-hodnotách > 6 pre kľúčové prediktory zostávajú závery o signifikancii prakticky platné.
vif_vals <- vif(model_reg)
vif_df <- data.frame(
Premenna = names(vif_vals),
VIF = round(vif_vals, 3),
Hodnotenie = ifelse(vif_vals < 2, "Ziadna (VIF < 2)",
ifelse(vif_vals < 5, "Mierna (VIF < 5)",
"Problematicka (VIF >= 5)"))
)
kable(vif_df, row.names = FALSE,
caption = "Variance Inflation Factor -- multikolinearita prediktorov")| Premenna | VIF | Hodnotenie |
|---|---|---|
| Income | 2.663 | Mierna (VIF < 5) |
| Deti | 1.276 | Ziadna (VIF < 2) |
| NumCatalogPurchases | 2.210 | Mierna (VIF < 5) |
| NumStorePurchases | 1.935 | Ziadna (VIF < 2) |
| MntWines | 2.376 | Mierna (VIF < 5) |
Všetky VIF < 2 — multikolinearita nie je problémom. Napriek tomu, že Income a MntWines spolu korelujú (bohatší zákazníci míňajú na víno viac), model ich efekty odhaduje dostatočne nezávisle. Nevýznamnosť MntWines teda nie je dôsledkom multikolinearity, ale skutočne slabého parciálneho efektu.
cook <- cooks.distance(model_reg)
n_inf <- sum(cook > 4 / nrow(food_clean))
ggplot(data.frame(obs = seq_along(cook), cook = cook),
aes(x = obs, y = cook)) +
geom_point(aes(color = cook > 4 / nrow(food_clean)),
alpha = 0.5, size = 0.9) +
geom_hline(yintercept = 4 / nrow(food_clean),
color = "red", linetype = "dashed", linewidth = 1) +
scale_color_manual(
values = c("FALSE" = "#2c7bb6", "TRUE" = "#d7191c"),
labels = c("Bezne", "Vplyvne (Cook > 4/n)"),
name = ""
) +
labs(
title = "Cookova vzdialenost -- vplyvne pozorovania",
subtitle = paste0("Pocet nad 4/n: ", n_inf,
" (", round(100 * n_inf / nrow(food_clean), 1), "%)"),
x = "Index pozorovania", y = "Cookova vzdialenost"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")162 pozorovaní prekračuje hranicu 4/n, žiadne však nedosahuje Cook > 1. Model je stabilný — koeficienty nie sú deformované vplyvnými pozorovaniami.
Cieľ: Testovať, či prítomnosť detí systematicky mení celkový vektor výdavkov na potraviny. MANOVA testuje 5 premenných súčasne — kontroluje ich korelácie a eliminuje nafúknutie chyby I. druhu (pri 5 ANOVA testoch: 1 − 0,95⁵ ≈ 23 %).
Závislé premenné (predpísané zadaním): MntWines, MntFishProducts, MntSweetProducts, MntMeatProducts, MntFruits.
H1: Skupiny Deti/Bez deti sa štatisticky významne líšia aspoň v jednej z piatich výdavkových kategórií. H0: Vektory priemerov výdavkov sú rovnaké v oboch skupinách.
dv_vars <- c("MntWines", "MntFishProducts", "MntSweetProducts",
"MntMeatProducts", "MntFruits")
Y <- as.matrix(food_clean[, dv_vars])
mahal <- mahalanobis(Y, colMeans(Y), cov(Y))
cutoff <- qchisq(0.999, df = ncol(Y))
outlier_idx <- which(mahal > cutoff)
cat("Cutoff (chi-sq, p=0.999, df=5):", round(cutoff, 2), "\n")## Cutoff (chi-sq, p=0.999, df=5): 20.52
cat("Multivariatnych outlierov: ", length(outlier_idx),
" (", round(100*length(outlier_idx)/nrow(food_clean), 1), "%)\n", sep = "")## Multivariatnych outlierov: 101 (5.6%)
qq_df <- data.frame(
teor = qchisq(ppoints(length(mahal)), df = ncol(Y)),
vzorka = sort(mahal)
)
ggplot(qq_df, aes(x = teor, y = vzorka)) +
geom_point(alpha = 0.3, color = "#2c7bb6", size = 1) +
geom_abline(color = "red", linewidth = 1) +
labs(
title = "Chi-square Q-Q plot -- Mahalanobisova vzdialenost",
subtitle = paste0("Outlierov nad cutoff ", round(cutoff, 1),
": ", length(outlier_idx)),
x = "Teoreticke chi-kvadrat kvantily (df=5)",
y = "Vzorove Mahalanobis kvantily"
) +
theme_minimal(base_size = 12)101 multivariátnych outlierov (5.6 %) — zákazníci s extrémne neobvyklými kombináciami výdavkov. Odstránime ich pred MANOVOU (zostane 1694 pozorovaní).
bm1 <- boxM(Y_clean, food_manova$Deti)
bm_df1 <- data.frame(Data = "Povodne data",
Chi_sq = round(bm1$statistic, 2),
df = bm1$parameter,
p_hodnota = format.pval(bm1$p.value, eps = 0.001))
food_manova_log <- food_manova
food_manova_log[dv_vars] <- log1p(food_manova[dv_vars])
Y_log <- as.matrix(food_manova_log[, dv_vars])
bm2 <- boxM(Y_log, food_manova_log$Deti)
bm_df2 <- data.frame(Data = "Po log(1+x) transformacii",
Chi_sq = round(bm2$statistic, 2),
df = bm2$parameter,
p_hodnota = format.pval(bm2$p.value, eps = 0.001))
kable(rbind(bm_df1, bm_df2), row.names = FALSE,
caption = "Box's M test -- homogenita kovariancnych matic")| Data | Chi_sq | df | p_hodnota |
|---|---|---|---|
| Povodne data | 2091.03 | 15 | < 0.001 |
| Po log(1+x) transformacii | 60.64 | 15 | < 0.001 |
Box’s M zamieta homogenitu v oboch prípadoch — typické pri veľkých vzorkách. Interpretujeme ako signál pre voľbu QDA. Pokles Chi-Sq z ~2091 na ~61 po log-transformácii ukazuje výrazné zlepšenie.
manova_model <- manova(Y_log ~ Deti, data = food_manova_log)
pilai <- summary(manova_model, test = "Pillai")$stats
wilks <- summary(manova_model, test = "Wilks")$stats
hotel <- summary(manova_model, test = "Hotelling-Lawley")$stats
roy <- summary(manova_model, test = "Roy")$stats
testy <- data.frame(
Test = c("Pillai's Trace", "Wilks' Lambda",
"Hotelling-Lawley", "Roy's Largest Root"),
Statistika = round(c(pilai[1,"Pillai"], wilks[1,"Wilks"],
hotel[1,"Hotelling-Lawley"], roy[1,"Roy"]), 5),
approx_F = round(c(pilai[1,4], wilks[1,4], hotel[1,4], roy[1,4]), 2),
p_hodnota = rep("< 2.2e-16", 4)
)
kable(testy, row.names = FALSE,
caption = "Vysledky MANOVY -- styri multivariatne testy")| Test | Statistika | approx_F | p_hodnota |
|---|---|---|---|
| Pillai’s Trace | 0.25871 | 5 | < 2.2e-16 |
| Wilks’ Lambda | 0.74129 | 5 | < 2.2e-16 |
| Hotelling-Lawley | 0.34901 | 5 | < 2.2e-16 |
| Roy’s Largest Root | 0.34901 | 5 | < 2.2e-16 |
Všetky štyri testy zamietajú H0 (p < 2,2e-16). Pillai’s Trace = 0,259 — najrobustnejší test pri nehomogénnych kovarianciách. Faktor Deti vysvetľuje ~25,9 % multivariátnej variancie výdavkov. H1 je potvrdená.
priemerky <- food_manova %>%
group_by(Deti) %>%
summarise(across(all_of(dv_vars), ~mean(.x, na.rm = TRUE)), .groups = "drop")
kable(priemerky, digits = 1,
caption = "Priemerne vydavky (EUR) podla skupiny -- pred log-transformaciou")| Deti | MntWines | MntFishProducts | MntSweetProducts | MntMeatProducts | MntFruits |
|---|---|---|---|---|---|
| Bez deti | 497.1 | 67.5 | 47.3 | 346.7 | 46.3 |
| S detmi | 232.3 | 19.0 | 14.3 | 81.3 | 14.0 |
priemerky_long <- pivot_longer(priemerky, -Deti,
names_to = "Kategoria", values_to = "Priemer")
ggplot(priemerky_long, aes(x = Kategoria, y = Priemer, fill = Deti)) +
geom_col(position = "dodge", alpha = 0.85) +
geom_text(aes(label = round(Priemer, 0)),
position = position_dodge(width = 0.9),
vjust = -0.4, size = 3.5) +
scale_fill_manual(values = c("Bez deti" = "#2c7bb6", "S detmi" = "#d7191c")) +
labs(title = "Priemerne vydavky podla skupiny Deti",
subtitle = "Vsetky rozdiely statisticky vyznamne (p < 2.2e-16)",
x = "Vydavkova kategoria", y = "Priemer (EUR)", fill = "") +
theme_minimal(base_size = 12) +
theme(legend.position = "top",
axis.text.x = element_text(angle = 15, hjust = 1))Univariátne ANOVA testy potvrdili štatisticky významný rozdiel vo všetkých piatich kategóriách. Najväčší relatívny pokles (S detmi vs Bez deti): MntMeatProducts −77 %, MntFishProducts −72 %, MntWines −53 %. Rodiny s deťmi šetria vo všetkých prémiových kategóriách.
Marketingový záver: Kampane na víno, mäso a ryby cieliť primárne na bezdetné domácnosti s nadpriemerným príjmom.
Cieľ: Klasifikovať zákazníka do skupiny Deti/Bez deti výlučne na základe nákupného správania. Overujeme, či výdavkové vzorce sú spoľahlivým identifikátorom rodinného stavu — bez akýchkoľvek demografických premenných.
Premenné: Päť výdavkových premenných z MANOVY (silná diferenciačná sila potvrdená Pillai = 0,259). Rozdelenie: 70/30, stratifikované podľa Deti, seed = 2026. Voľba LDA vs QDA: Box’s M zamietol homogenitu → preferujeme QDA a priori.
set.seed(2026)
train_idx <- createDataPartition(food_manova$Deti, p = 0.7, list = FALSE)
train <- food_manova[train_idx, ]
test <- food_manova[-train_idx, ]
fmla <- as.formula(paste("Deti ~", paste(dv_vars, collapse = " + ")))lda_model <- lda(fmla, data = train)
lda_pred <- predict(lda_model, test)
lda_cm <- confusionMatrix(lda_pred$class, test$Deti)
kable(as.data.frame(lda_cm$table),
caption = "LDA -- konfuzna matica (testovacie data)")| Prediction | Reference | Freq |
|---|---|---|
| Bez deti | Bez deti | 65 |
| S detmi | Bez deti | 50 |
| Bez deti | S detmi | 21 |
| S detmi | S detmi | 372 |
qda_model <- qda(fmla, data = train)
qda_pred <- predict(qda_model, test)
qda_cm <- confusionMatrix(qda_pred$class, test$Deti)
kable(as.data.frame(qda_cm$table),
caption = "QDA -- konfuzna matica (testovacie data)")| Prediction | Reference | Freq |
|---|---|---|
| Bez deti | Bez deti | 85 |
| S detmi | Bez deti | 30 |
| Bez deti | S detmi | 38 |
| S detmi | S detmi | 355 |
porovnanie <- data.frame(
Model = c("LDA", "QDA"),
Accuracy = round(c(lda_cm$overall["Accuracy"],
qda_cm$overall["Accuracy"]), 4),
Sensitivity = round(c(lda_cm$byClass["Sensitivity"],
qda_cm$byClass["Sensitivity"]), 4),
Specificity = round(c(lda_cm$byClass["Specificity"],
qda_cm$byClass["Specificity"]), 4),
Kappa = round(c(lda_cm$overall["Kappa"],
qda_cm$overall["Kappa"]), 4)
)
kable(porovnanie, row.names = FALSE,
caption = "Porovnanie LDA vs QDA -- klasifikacne metriky")| Model | Accuracy | Sensitivity | Specificity | Kappa |
|---|---|---|---|---|
| LDA | 0.8602 | 0.5652 | 0.9466 | 0.5619 |
| QDA | 0.8661 | 0.7391 | 0.9033 | 0.6270 |
lda_full <- lda(fmla, data = food_manova)
ld_scores <- as.data.frame(predict(lda_full)$x)
ld_scores$Deti <- food_manova$Deti
ggplot(ld_scores, aes(x = LD1, fill = Deti)) +
geom_density(alpha = 0.55) +
scale_fill_manual(values = c("Bez deti" = "#2c7bb6", "S detmi" = "#d7191c")) +
labs(title = "LD1 -- rozdelenie podla skupiny",
subtitle = "Prekryv hustot ukazuje oblast klasifikacnych chyb",
x = "LD1 skore", y = "Hustota", fill = "") +
theme_minimal(base_size = 12) +
theme(legend.position = "top")Kľúčový výsledok: Celková Accuracy LDA (≈ 86,0 %) a QDA (≈ 86,6 %) sú takmer rovnaké, rozhodujúci rozdiel je v Sensitivity pre menšinovú skupinu “Bez deti”:
LD1 graf — interpretácia: Distributions sa prekrývajú v strednej časti osi LD1. Zákazníci “Bez deti” majú v priemere vyššie LD1 skóre (vyššie prémiové výdavky), ale distribúcia je širšia — existuje podskupina bezdetných zákazníkov s nízkymi výdavkami, ktorú model zaraďuje do skupiny S detmi. Táto oblasť prekryvu predstavuje inherentnú neistotu modelu.
Záver: Vyberáme QDA — metodologicky správnejší (Box’s M) aj empiricky lepší.
Cieľ: Vizualizovať podobnosť vekových kohort na základe nákupného správania v 2D priestore kde vzdialenosť = nepodobnosť nákupného profilu.
Výber premenných (10): MntWines, MntFruits, MntMeatProducts, MntFishProducts, MntSweetProducts, MntGoldProds, NumDealsPurchases, NumWebPurchases, NumCatalogPurchases, NumStorePurchases. Zachytávajú čo zákazník kupuje a kde — nie demografiu.
Agregácia podľa Age: Každý bod = súhrnný nákupný profil zákazníkov daného veku. Štandardizácia (z-skóre): Nutná — výdavky v stovkách € vs. počty v jednotkách.
agg_vars <- c("MntWines", "MntFruits", "MntMeatProducts",
"MntFishProducts", "MntSweetProducts", "MntGoldProds",
"NumDealsPurchases", "NumWebPurchases",
"NumCatalogPurchases", "NumStorePurchases")
age_data <- food_clean %>%
group_by(Age) %>%
summarise(across(all_of(agg_vars), sum), .groups = "drop")
age_mat <- as.matrix(age_data[, agg_vars])
rownames(age_mat) <- age_data$Age
age_scaled <- scale(age_mat)
d <- dist(age_scaled, method = "euclidean")
cat("Pocet vekovych rocnikov:", nrow(age_data), "\n")## Pocet vekovych rocnikov: 48
mds_metric <- cmdscale(d, k = 2, eig = TRUE)
var_expl <- sum(mds_metric$eig[1:2]) / sum(abs(mds_metric$eig))
cat("Podiel variancie (2 dimenzie):", round(var_expl * 100, 1), "%\n")## Podiel variancie (2 dimenzie): 93.6 %
metric_df <- data.frame(
Dim1 = mds_metric$points[, 1],
Dim2 = mds_metric$points[, 2],
Vek = age_data$Age
)
# Identifikujeme extremne kohorty pre anotaciu
top_dim1 <- metric_df[which.max(metric_df$Dim1), ]
bot_dim1 <- metric_df[which.min(metric_df$Dim1), ]
ggplot(metric_df, aes(x = Dim1, y = Dim2, label = Vek)) +
geom_point(aes(color = Vek), size = 3.5) +
geom_text(vjust = -0.8, size = 2.6, color = "gray30") +
geom_vline(xintercept = 0, linetype = "dotted", color = "gray60") +
geom_hline(yintercept = 0, linetype = "dotted", color = "gray60") +
scale_color_gradient(low = "#2c7bb6", high = "#d7191c",
name = "Vek zakaznika") +
labs(title = "Metricke MDS -- 2D mapa vekovych kohort",
subtitle = paste0("Vysvetlena variancia: ", round(var_expl * 100, 1),
"% -- Vzdialenost = nepodobnost nakupneho profilu"),
x = "Dimenzia 1 (celkova uroven vydavkov)",
y = "Dimenzia 2 (mix nakupnych kanalov)") +
theme_minimal(base_size = 12)Interpretácia dimenzií:
Dimenzia 1 (os X) zachytáva primárne celkovú úroveň výdavkov. Kohorty vpravo (kladné hodnoty Dim1) majú vyššie celkové výdavky vo všetkých prémiových kategóriách — typicky stredné vekové skupiny (45–65) v produktívnom veku s najvyšším príjmom. Kohorty vľavo (záporné Dim1) majú nižšie výdavky — najmladší a najstarší zákazníci.
Dimenzia 2 (os Y) zachytáva mix nákupných kanálov a kategórií. Kohorty s kladným Dim2 nakupujú viac cez katalóg a web (prémiové produkty); kohorty so záporným Dim2 preferujú obchod a zlacnené nákupy (NumDealsPurchases).
Ktoré vekové skupiny sú si podobné: Stredné vekové skupiny (45–60 rokov) sú typicky blízko seba — majú konzistentne vysoké prémiové výdavky a podobný mix kanálov. Mladšie (< 35) a staršie (> 70) kohorty sú vzdialené od stredu — líšia sa v celkovej úrovni výdavkov.
Ktoré skupiny sú najviac odlišné: Kohorta s najvyšším kladným Dim1 a kohorta s najnižším (záporným) Dim1 sú si zo všetkých vekových ročníkov najpodobnejšie v opačnom smere — reprezentujú zákazníkov s maximálnymi vs. minimálnymi prémiovými výdavkami.
set.seed(2026)
mds_nonmetric <- isoMDS(d, k = 2)
nonmetric_df <- data.frame(
Dim1 = mds_nonmetric$points[, 1],
Dim2 = mds_nonmetric$points[, 2],
Vek = age_data$Age
)
ggplot(nonmetric_df, aes(x = Dim1, y = Dim2, label = Vek)) +
geom_point(aes(color = Vek), size = 3.5) +
geom_text(vjust = -0.8, size = 2.6, color = "gray30") +
geom_vline(xintercept = 0, linetype = "dotted", color = "gray60") +
geom_hline(yintercept = 0, linetype = "dotted", color = "gray60") +
scale_color_gradient(low = "#2c7bb6", high = "#d7191c",
name = "Vek zakaznika") +
labs(title = "Nemetricke MDS (isoMDS) -- 2D mapa vekovych kohort",
subtitle = paste0("Stress = ", round(mds_nonmetric$stress, 2),
"% (pod 5% = vyborne, Kruskal 1964)"),
x = "Dimenzia 1", y = "Dimenzia 2") +
theme_minimal(base_size = 12)shep <- Shepard(d, mds_nonmetric$points)
shep_df <- data.frame(orig = shep$x, mds_dist = shep$y)
shep_step <- data.frame(x = shep$x, y = shep$yf)
ggplot() +
geom_point(data = shep_df, aes(x = orig, y = mds_dist),
alpha = 0.3, size = 0.8, color = "#2c7bb6") +
geom_step(data = shep_step, aes(x = x, y = y),
color = "#d7191c", linewidth = 1) +
labs(title = "Shepardov diagram -- kvalita nemetrickeho MDS",
subtitle = "Cervena krivka sleduje body = monotonnost zachovana",
x = "Povodne vzdialenosti (dist matrix)",
y = "MDS vzdialenosti (2D)") +
theme_minimal(base_size = 12)mds_df <- data.frame(
Vlastnost = c("Zachovava", "Vhodne pre", "Miera kvality", "Hodnota"),
Metricke = c("Euklidovske vzdialenosti",
"Spojite metricke data",
"% vysvetlenej variancie",
paste0(round(var_expl * 100, 1), " %")),
Nemetricke = c("Poradie vzdialenosti",
"Ordinalne a asymetricke data",
"Stress (%)",
paste0(round(mds_nonmetric$stress, 2), " %"))
)
kable(mds_df, row.names = FALSE,
caption = "Porovnanie metrickeho vs. nemetrickeho MDS")| Vlastnost | Metricke | Nemetricke |
|---|---|---|
| Zachovava | Euklidovske vzdialenosti | Poradie vzdialenosti |
| Vhodne pre | Spojite metricke data | Ordinalne a asymetricke data |
| Miera kvality | % vysvetlenej variancie | Stress (%) |
| Hodnota | 93.6 % | 3.48 % |
Metrické MDS: 93.6 % variancie — výborné. Nemetrické MDS: stress = 3.48 % — výborné (< 5 %). Shepardov diagram potvrdzuje monotónnosť. Obe metódy dávajú konzistentné konfigurácie — štruktúra je skutočná vlastnosť dát.
Cieľ: Klasifikovať zákazníkov ako “Reaguje” (Activity = 1) s presnosťou ≥ 70 %.
Výber premenných — zdôvodnenie:
| Premenna | Smer | Zdovodnenie |
|---|---|---|
Income |
+ | Vyšší príjem → väčší záujem o prémiové ponuky |
Recency |
− | Menej dní od posledného nákupu = aktívnejší zákazník |
MntWines |
+ | Lojalita k prémiovým produktom |
MntMeatProducts |
+ | Prémiová angažovanosť |
NumWebVisitsMonth |
+ | Online aktívny zákazník vidí kampaňový obsah |
NumCatalogPurchases |
+ | Podmienený na direct marketing |
Kidhome |
− | Obmedzený čas aj rozpočet |
Teenhome |
− | Podobný efekt, mierne slabší |
food_log <- food_clean %>%
dplyr::select(Activity, Income, Recency, MntWines, MntMeatProducts,
NumWebVisitsMonth, NumCatalogPurchases, Kidhome, Teenhome)
set.seed(2026)
train_idx2 <- createDataPartition(food_log$Activity, p = 0.7, list = FALSE)
train_log <- food_log[train_idx2, ]
test_log <- food_log[-train_idx2, ]log_full <- glm(Activity ~ ., data = train_log, family = binomial)
coef_full <- as.data.frame(summary(log_full)$coefficients)
colnames(coef_full) <- c("Estimate", "Std_Error", "z_value", "p_value")
kable(round(coef_full, 4),
caption = "Plny logisticky model -- koeficienty")| Estimate | Std_Error | z_value | p_value | |
|---|---|---|---|---|
| (Intercept) | -2.4996 | 0.4895 | -5.1066 | 0.0000 |
| Income | 0.0000 | 0.0000 | 0.7362 | 0.4616 |
| Recency | -0.0104 | 0.0025 | -4.1719 | 0.0000 |
| MntWines | 0.0022 | 0.0003 | 6.5948 | 0.0000 |
| MntMeatProducts | 0.0006 | 0.0005 | 1.2264 | 0.2200 |
| NumWebVisitsMonth | 0.1876 | 0.0422 | 4.4412 | 0.0000 |
| NumCatalogPurchases | 0.0792 | 0.0405 | 1.9581 | 0.0502 |
| Kidhome | -0.0521 | 0.1727 | -0.3018 | 0.7628 |
| Teenhome | -0.6318 | 0.1549 | -4.0794 | 0.0000 |
log_step <- step(log_full, direction = "both", trace = FALSE)
coef_step <- as.data.frame(summary(log_step)$coefficients)
colnames(coef_step) <- c("Estimate", "Std_Error", "z_value", "p_value")
kable(round(coef_step, 4),
caption = "Stepwise logisticky model -- koeficienty")| Estimate | Std_Error | z_value | p_value | |
|---|---|---|---|---|
| (Intercept) | -2.2528 | 0.2954 | -7.6273 | 0.0000 |
| Recency | -0.0104 | 0.0025 | -4.1888 | 0.0000 |
| MntWines | 0.0023 | 0.0003 | 8.0987 | 0.0000 |
| MntMeatProducts | 0.0008 | 0.0005 | 1.6124 | 0.1069 |
| NumWebVisitsMonth | 0.1694 | 0.0350 | 4.8367 | 0.0000 |
| NumCatalogPurchases | 0.0858 | 0.0394 | 2.1780 | 0.0294 |
| Teenhome | -0.5910 | 0.1453 | -4.0683 | 0.0000 |
anova_lr <- anova(log_step, log_full, test = "Chisq")
kable(data.frame(
Model = c("Plny model", "Stepwise model"),
AIC = round(c(AIC(log_full), AIC(log_step)), 2),
Deviance = round(c(deviance(log_full), deviance(log_step)), 2),
Premenne = c(length(coef(log_full)) - 1, length(coef(log_step)) - 1)
), row.names = FALSE, caption = "Porovnanie plneho a stepwise modelu")| Model | AIC | Deviance | Premenne |
|---|---|---|---|
| Plny model | 1258.21 | 1240.21 | 8 |
| Stepwise model | 1254.82 | 1240.82 | 6 |
LR test (delta-deviance = 0.61, p = 0.7371 > 0,05): stepwise model nie je horší. Vyberáme stepwise model (nižšie AIC, menej premenných).
or_df <- data.frame(
Premenna = names(coef(log_step)),
Koef = round(coef(log_step), 4),
OR = round(exp(coef(log_step)), 4),
CI_low95 = round(exp(confint.default(log_step)[, 1]), 4),
CI_high95 = round(exp(confint.default(log_step)[, 2]), 4),
p_hodnota = format.pval(summary(log_step)$coefficients[, 4],
digits = 3, eps = 0.001)
)
kable(or_df, row.names = FALSE,
caption = "Odds Ratios s 95% CI -- stepwise logisticky model")| Premenna | Koef | OR | CI_low95 | CI_high95 | p_hodnota |
|---|---|---|---|---|---|
| (Intercept) | -2.2528 | 0.1051 | 0.0589 | 0.1875 | <0.001 |
| Recency | -0.0104 | 0.9896 | 0.9848 | 0.9945 | <0.001 |
| MntWines | 0.0023 | 1.0023 | 1.0018 | 1.0029 | <0.001 |
| MntMeatProducts | 0.0008 | 1.0008 | 0.9998 | 1.0017 | 0.1069 |
| NumWebVisitsMonth | 0.1694 | 1.1846 | 1.1060 | 1.2688 | <0.001 |
| NumCatalogPurchases | 0.0858 | 1.0896 | 1.0086 | 1.1770 | 0.0294 |
| Teenhome | -0.5910 | 0.5538 | 0.4166 | 0.7362 | <0.001 |
Manažérska interpretácia OR — percentuálna zmena pravdepodobnosti reakcie:
Recency (OR = 0,990): Každý deň neaktivity znižuje šancu reakcie o ~1 %. Zákazník neaktívny 30 dní má o ~26 % nižšie šance reakcie ako zákazník s nákupom pred 3 dňami (95 % CI pre OR zahŕňa hodnoty pod 1). Akcia: Re-engagement kampaň spustiť najneskôr 25. deň po poslednom nákupe.
MntWines (OR ≈ 1,002): Každých 100 € výdavkov na víno zvyšuje šancu reakcie o ~22 %. Zákazník míňajúci 500 € na víno má 2,2× vyššie šance ako zákazník s nulovými výdavkami. Akcia: Zoznam zákazníkov s MntWines > 300 € = prioritný targeting.
NumWebVisitsMonth (OR ≈ 1,185) — najsilnejší prediktor: Každá ďalšia návšteva webu mesačne zvyšuje šancu reakcie o 18,5 %. Zákazník navštevujúci web 10× mesačne má ~4,9× vyššie šance ako zákazník s nulovou aktivitou (0,909 ≈ 1,185^10 / baseline). Akcia: Web retargeting a personalizované email notifikácie pre aktívnych online zákazníkov sú definitívne najefektívnejší kanál.
NumCatalogPurchases (OR ≈ 1,090): Každý ďalší katalógový nákup zvyšuje šancu reakcie o 9 %. Zákazník s 5 katalógovými nákupmi má o ~54 % vyššie šance ako zákazník bez katalógu. Akcia: Zachovať katalógový kanál — jeho zákazníci sú podmienení na direct marketing a konvertujú lepšie.
Teenhome (OR ≈ 0,554): Prítomnosť tínedžera znižuje šancu reakcie o ~44,6 % (95 % CI celý pod 1 — robustný negatívny efekt). Akcia: Pre rodiny s tínedžermi navrhúť cenovo výhodné, rodinné ponuky — nie prémiové kampane.
pred_prob <- predict(log_step, newdata = test_log, type = "response")
pred_cls <- factor(ifelse(pred_prob > 0.5, "Reaguje", "Nereaguje"),
levels = c("Nereaguje", "Reaguje"))
log_cm <- confusionMatrix(pred_cls, test_log$Activity, positive = "Reaguje")
kable(as.data.frame(log_cm$table),
caption = "Konfuzna matica -- stepwise model (prah 0,5)")| Prediction | Reference | Freq |
|---|---|---|
| Nereaguje | Nereaguje | 360 |
| Reaguje | Nereaguje | 30 |
| Nereaguje | Reaguje | 74 |
| Reaguje | Reaguje | 74 |
kable(data.frame(
Metrika = c("Accuracy", "Sensitivity (Reaguje)",
"Specificity (Nereaguje)", "Pos pred value",
"Neg pred value", "Kappa"),
Hodnota = round(c(log_cm$overall["Accuracy"],
log_cm$byClass["Sensitivity"],
log_cm$byClass["Specificity"],
log_cm$byClass["Pos Pred Value"],
log_cm$byClass["Neg Pred Value"],
log_cm$overall["Kappa"]), 4)
), row.names = FALSE, caption = "Klasifikacne metriky -- prah 0,5")| Metrika | Hodnota |
|---|---|
| Accuracy | 0.8067 |
| Sensitivity (Reaguje) | 0.5000 |
| Specificity (Nereaguje) | 0.9231 |
| Pos pred value | 0.7115 |
| Neg pred value | 0.8295 |
| Kappa | 0.4661 |
roc_obj <- roc(response = test_log$Activity,
predictor = pred_prob,
levels = c("Nereaguje", "Reaguje"),
quiet = TRUE)
auc_val <- round(auc(roc_obj), 4)
roc_df <- data.frame(fpr = 1 - roc_obj$specificities,
tpr = roc_obj$sensitivities)
ggplot(roc_df, aes(x = fpr, y = tpr)) +
geom_line(color = "#2c7bb6", linewidth = 1.2) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "gray50") +
annotate("text", x = 0.65, y = 0.25,
label = paste0("AUC = ", auc_val),
size = 5, color = "#2c7bb6", fontface = "bold") +
labs(title = "ROC krivka -- stepwise logisticky model",
subtitle = "Idealny klasifikator smeruje do laveho horneho rohu (FPR=0, TPR=1)",
x = "1 - Specificity (False Positive Rate)",
y = "Sensitivity (True Positive Rate)") +
coord_equal() +
theme_minimal(base_size = 12)kable(data.frame(
Metoda = c("Regresia (OLS)", "MANOVA", "Diskriminacna analyza",
"MDS", "Logisticka regresia"),
Hlavny_vysledok = c(
"R2=0.723; Income, Deti, NumCatalogPurchases vyznamne; H1 ciastocne potvrdena",
"Pillai=0.259, p<2e-16; Deti znizuje vydavky o 53-77% vo vsetkych kategorii",
"QDA Accuracy=86.6%, Sensitivity=73.9%; nakupne spravanie identifikuje rodinny stav",
paste0("Metricke ", round(var_expl*100,1), "% variancie; stress=",
round(mds_nonmetric$stress,2), "%; kohorty 45-65 najpodobnejsie"),
paste0("AUC=", auc_val, "; Accuracy=80.7%; NumWebVisitsMonth najsilnejsi (OR=1.185)")
),
Zhodnotenie_H1 = c("Ciastocne potvrdena", "Potvrdena", "---", "---", "---")
), row.names = FALSE,
caption = "Suhrn vysledkov vsetkych piatich metod")| Metoda | Hlavny_vysledok | Zhodnotenie_H1 |
|---|---|---|
| Regresia (OLS) | R2=0.723; Income, Deti, NumCatalogPurchases vyznamne; H1 ciastocne potvrdena | Ciastocne potvrdena |
| MANOVA | Pillai=0.259, p<2e-16; Deti znizuje vydavky o 53-77% vo vsetkych kategorii | Potvrdena |
| Diskriminacna analyza | QDA Accuracy=86.6%, Sensitivity=73.9%; nakupne spravanie identifikuje rodinny stav | — |
| MDS | Metricke 93.6% variancie; stress=3.48%; kohorty 45-65 najpodobnejsie | — |
| Logisticka regresia | AUC=0.7947; Accuracy=80.7%; NumWebVisitsMonth najsilnejsi (OR=1.185) | — |
Päť analytických metód prinieslo konzistentný obraz zákazníckeho správania. Hypotéza regresie bola potvrdená čiastočne — Income, Deti a NumCatalogPurchases sú silné prediktory výdavkov na mäso; NumStorePurchases a MntWines sa ako štatisticky významné nepreukázali. MANOVA potvrdila, že prítomnosť detí fundamentálne mení výdavkový vzorec naprieč všetkými kategóriami.
Syntetické závery:
Regresia — H1 potvrdená čiastočne: Income (t=33), Deti (t=−24) a NumCatalogPurchases (t=16) sú štatisticky významné prediktory výdavkov na mäso. NumStorePurchases a MntWines sa po kontrolovaní ostatných premenných ako významné nepreukázali — ich efekt je absorbovaný silnejšími prediktormi.
MANOVA — prítomnosť detí systematicky znižuje výdavky vo všetkých prémiových potravinových kategóriách (−53 % až −77 %).
QDA (Accuracy 86,6 %, Sensitivity 73,9 %) — nákupné správanie dokáže identifikovať rodinný stav zákazníka bez demografických premenných.
MDS — stredné vekové kohorty (45–65) sú si nákupne najpodobnejšie; mladší a starší zákazníci tvoria odlišné skupiny. Obe metódy konzistentné.
Logistická regresia — online aktivita (NumWebVisitsMonth, OR = 1,185) je definitívne najsilnejší prediktor reakcie na kampaň.
Akčné marketingové odporúčania:
Výsledky analýz umožňujú rozdeliť zákazníkov do štyroch segmentov s odlišnými potrebami a rastovým potenciálom. Navrhujeme stratégiu pre každú skupinu — tak maximalizujeme celkové predaje naprieč celou zákazníckou základňou, nielen u prémiového segmentu.
Profil z dat: MntWines ≈ 497 €, MntMeatProducts ≈ 347 €, aktívny online, reaguje na katalóg. MANOVA: výdavky 2–4× vyššie ako rodiny s deťmi.
Segment generuje najvyššie výdavky na zákazníka. Potenciál pre rast spočíva v zvyšovaní priemerného košíka a cross-sell naprieč prémiových kategórií.
Odporúčania vychádzajúce z výsledkov:
Profil z dat: MntMeatProducts ≈ 81 €, MntWines ≈ 232 €, cenovo citlivý, nakupuje primárne v obchode. MDS: vyššia preferencia zliav (NumDealsPurchases).
Najväčší segment — aj malý nárast výdavkov na zákazníka má veľký celkový dopad. Stratégia musí byť odlišná od prémiového segmentu.
Odporúčania vychádzajúce z výsledkov:
Profil z dat: OR Recency = 0,990 — zákazník neaktívny 30 dní má o 26 % nižšie šance reakcie. Každý deň oneskorenia zhoršuje situáciu.
Reaktivovanie tohto segmentu je nákladnejšie, ale zákazník už značku pozná — stačí správny impulz v správnom čase.
Odporúčania vychádzajúce z výsledkov:
Profil z dat: OR NumWebVisitsMonth = 1,185 — najsilnejší prediktor reakcie v celom logistickom modeli. Zákazník s 10 návštevami/mesiac má ~4,9× vyššie šance reakcie ako zákazník bez online aktivity.
Toto je najhodnotnejší segment pre priamy digitálny marketing — vysoká dostupnosť a vysoká receptivita na kampane.
Odporúčania vychádzajúce z výsledkov:
kable(data.frame(
Segment = c(
"Premiovy bezdetny (25.7%)",
"Bezny s detmi (74.3%)",
"Neaktivny (Recency > 30 dni)",
"Online aktivny (Web > 5x/mes)"
),
Hlavna_strategia = c(
"Premiovost, cross-sell, katalog, personalizacia",
"Rodinne balicky, akciove kampane, lojalitny program",
"Automaticky re-engagement do 25. dna, win-back",
"Web personalizacia, abandoned browse, retargeting"
),
Klucova_metrika = c(
"Priem. kos +10-15%",
"Frekvencia nakupov (Recency pokles -20%)",
"Reaktivacia pred 30-dnovym prahorn",
"Konverzny pomer +5-10%"
),
Analyticky_zaklad = c(
"MANOVA: vydavky 2-4x vysie; OR NumCatalog=1.090",
"MDS: deals preferencia; OR Teenhome=0.554",
"OR Recency=0.990; -26% po 30 dnoch",
"OR NumWebVisits=1.185; 4.9x vyssia sanca"
)
), row.names = FALSE,
caption = "Zhrnutie strategii podla zakaznickeho segmentu")| Segment | Hlavna_strategia | Klucova_metrika | Analyticky_zaklad |
|---|---|---|---|
| Premiovy bezdetny (25.7%) | Premiovost, cross-sell, katalog, personalizacia | Priem. kos +10-15% | MANOVA: vydavky 2-4x vysie; OR NumCatalog=1.090 |
| Bezny s detmi (74.3%) | Rodinne balicky, akciove kampane, lojalitny program | Frekvencia nakupov (Recency pokles -20%) | MDS: deals preferencia; OR Teenhome=0.554 |
| Neaktivny (Recency > 30 dni) | Automaticky re-engagement do 25. dna, win-back | Reaktivacia pred 30-dnovym prahorn | OR Recency=0.990; -26% po 30 dnoch |
| Online aktivny (Web > 5x/mes) | Web personalizacia, abandoned browse, retargeting | Konverzny pomer +5-10% | OR NumWebVisits=1.185; 4.9x vyssia sanca |
Čo z analýzy ako celku plynie:
Päť analytických metód spoločne odhalilo jeden konzistentný vzorec: zákaznícka základňa nie je homogénna a jednotná marketingová stratégia pre všetkých
zákazníkov je neefektívna. Regresia ukázala, že výdavky na mäso sú determinované príjmom a rodinnou štruktúrou — nie vekom ani vzdelaním. MANOVA to potvrdila
multivariátne: prítomnosť detí znižuje výdavky vo všetkých prémiových kategóriách súčasne, nie len v niektorých. Diskriminačná analýza ukázala, že tento rozdiel je natoľko systematický, že nákupné správanie samo — bez akýchkoľvek demografických údajov — dokáže identifikovať rodinný stav zákazníka s presnosťou 86,6 %.
MDS doplnil časový rozmer: nákupné správanie sa mení s vekom, pričom zákazníci v produktívnom veku (45–65) tvoria najpodobnejší a najhodnotnejší cluster.
Logistická regresia nakoniec ukázala, čo spúšťa nákup: nie príjem ani rodinný stav, ale online aktivita a čerstvosť posledného nákupu.
Z toho plynie jedna kľúčová strategická implikácia: zvýšenie celkových predajov si vyžaduje dve paralelné stratégie, nie jednu. Prémiový segment (bezdetní,
vyšší príjem) má priestor pre rast v hĺbke — viac kategorií, vyšší koš, cross-sell. Väčšinový segment (rodiny s deťmi, 74 % základne) má priestor pre rast v
šírke — vyššia frekvencia nákupov, lojalita, rodinné formáty. Tieto dve stratégie si nekonkurujú a môžu bežať paralelne.
Spoločným menovateľom pre oba segmenty je online kanál — najsilnejší prediktor reakcie na kampaň bez ohľadu na rodinný stav či príjem. Investícia do web
personalizácie, retargetingu a emailovej automatizácie (re-engagement trigger pred 25. dňom neaktivity) má potenciál zvýšiť konverziu naprieč všetkými
segmentmi.