Industri kopi merupakan salah satu segmen bisnis minuman yang berkembang pesat. Dalam pengelolaan bisnis coffee chain, keputusan terkait strategi penjualan dan alokasi anggaran pemasaran (marketing) menjadi dua faktor kritis yang secara langsung memengaruhi profitabilitas perusahaan. Namun, efektivitas kedua faktor tersebut tidak selalu sama di setiap segmen pasar. Ukuran pasar (market size) dapat memoderasi hubungan antara upaya penjualan dan pemasaran terhadap keuntungan yang diraih.
Dataset Coffee Chain mencatat transaksi dari berbagai negara bagian Amerika Serikat selama periode 2012–2013, mencakup empat jenis produk utama: Coffee, Espresso, Tea, dan Herbal Tea. Dataset ini menyediakan informasi lengkap mengenai penjualan (Sales), biaya (COGS, Marketing, Total Expenses), dan keuntungan (Profit) yang memungkinkan analisis multivariat.
library(readxl)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(lmtest)
library(car)
library(knitr)
library(kableExtra)
df <- read_excel("C:/Users/lenovo/Downloads/Coffee Chain Datasets.xlsx",
sheet = "data")
# Ringkasan dimensi
cat("Jumlah baris :", nrow(df), "\n")## Jumlah baris : 4248
## Jumlah kolom : 20
## Periode data : January 2012 – December 2013
Berikut adalah variabel-variabel yang digunakan dalam analisis ini:
| Variabel | Tipe | Keterangan |
|---|---|---|
| Sales | Numerik | Total nilai penjualan produk (dalam satuan mata uang) |
| Marketing | Numerik | Biaya pemasaran yang dikeluarkan |
| COGS | Numerik | Cost of Goods Sold – biaya pokok penjualan |
| Total Expenses | Numerik | Total pengeluaran operasional |
| Profit | Numerik | Keuntungan bersih (Sales – COGS – Total Expenses) |
| Market Size | Kategorik | Ukuran pasar: Major Market atau Small Market |
| Product Type | Kategorik | Jenis produk: Coffee, Espresso, Tea, Herbal Tea |
# Cek missing values
missing_check <- data.frame(
Variabel = names(df),
Missing = colSums(is.na(df))
)
missing_check <- missing_check[missing_check$Missing > 0, ]
if (nrow(missing_check) == 0) {
cat("✓ Tidak ditemukan missing value pada seluruh variabel.\n")
} else {
kable(missing_check)
}## ✓ Tidak ditemukan missing value pada seluruh variabel.
vars_num <- df %>% select(Sales, Marketing, COGS, `Total Expenses`, Profit)
stat_desc <- data.frame(
Variabel = names(vars_num),
Min = round(sapply(vars_num, min), 2),
Q1 = round(sapply(vars_num, quantile, 0.25), 2),
Median = round(sapply(vars_num, median), 2),
Mean = round(sapply(vars_num, mean), 2),
Q3 = round(sapply(vars_num, quantile, 0.75), 2),
Max = round(sapply(vars_num, max), 2),
SD = round(sapply(vars_num, sd), 2)
)
kable(stat_desc, caption = "Statistik Deskriptif Variabel Numerik",
col.names = c("Variabel","Min","Q1","Median","Mean","Q3","Max","Std. Dev")) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Variabel | Min | Q1 | Median | Mean | Q3 | Max | Std. Dev | |
|---|---|---|---|---|---|---|---|---|
| Sales | Sales | 17 | 100 | 138 | 192.99 | 230 | 912 | 151.13 |
| Marketing | Marketing | 0 | 13 | 22 | 31.19 | 39 | 156 | 27.02 |
| COGS | COGS | 0 | 43 | 60 | 84.43 | 100 | 364 | 67.25 |
| Total Expenses | Total Expenses | 10 | 33 | 46 | 54.06 | 65 | 190 | 32.35 |
| Profit | Profit | -638 | 17 | 40 | 61.10 | 92 | 778 | 101.71 |
Distribusi Profit menunjukkan nilai minimum yang sangat rendah (\(\min = -638\)) dan nilai maksimum yang tinggi (\(\max = 778\)), dengan rata-rata \(\bar{x} = 61.1\) dan standar deviasi \(s = 101.71\). Hal ini mengindikasikan variabilitas yang cukup besar, kemungkinan dipengaruhi oleh segmentasi pasar.
Rata-rata Profit berdasarkan Market Size dan Product Type:
profit_tbl <- df %>%
group_by(`Market Size`, `Product Type`) %>%
summarise(
N = n(),
Mean_Profit = round(mean(Profit), 2),
SD_Profit = round(sd(Profit), 2),
.groups = "drop"
) %>%
tidyr::pivot_wider(names_from = `Market Size`,
values_from = c(N, Mean_Profit, SD_Profit))
kable(profit_tbl, caption = "Rata-rata Profit per Jenis Produk dan Ukuran Pasar") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Product Type | N_Major Market | N_Small Market | Mean_Profit_Major Market | Mean_Profit_Small Market | SD_Profit_Major Market | SD_Profit_Small Market |
|---|---|---|---|---|---|---|
| Coffee | 408 | 648 | 130.22 | 33.26 | 170.93 | 31.78 |
| Espresso | 432 | 744 | 99.10 | 34.69 | 134.23 | 34.42 |
| Herbal Tea | 456 | 600 | 63.65 | 57.05 | 100.97 | 71.21 |
| Tea | 408 | 552 | 75.42 | 40.25 | 47.28 | 136.23 |
Terlihat bahwa pada Major Market, produk Coffee menghasilkan rata-rata profit tertinggi, sedangkan pada Small Market selisih antar produk relatif kecil. Ini menjadi dasar hipotesis bahwa Market Size memoderasi hubungan antara Sales/Marketing dan Profit.
ggplot(df, aes(x = `Product Type`, y = Profit, fill = `Market Size`)) +
geom_boxplot(outlier.size = 0.8, outlier.alpha = 0.4, alpha = 0.85) +
scale_fill_manual(values = c("Major Market" = "#2E86AB", "Small Market" = "#E84855")) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray40", linewidth = 0.6) +
labs(
title = "Distribusi Profit berdasarkan Market Size dan Product Type",
subtitle = "Garis putus-putus menunjukkan batas profit = 0",
x = "Jenis Produk",
y = "Profit",
fill = "Market Size"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))Gambar 1. Distribusi Profit berdasarkan Market Size dan Product Type
Interpretasi visualisasi: Boxplot di atas memperlihatkan bahwa distribusi Profit pada Major Market (biru) secara konsisten lebih tinggi dan lebih lebar dibandingkan Small Market (merah) untuk seluruh jenis produk. Median Profit Major Market berada jauh di atas median Small Market, terutama pada produk Coffee dan Espresso. Keberadaan outlier di bawah garis putus-putus (Profit = 0) di kedua kelompok menunjukkan bahwa kerugian dapat terjadi di segmen manapun, namun frekuensi dan magnitude kerugian tampak lebih besar di Small Market. Pola ini menunjukkam bahwa skala pasar berperan penting dalam menentukan tingkat keuntungan
Analisis yang digunakan adalah Regresi Linier Berganda yang dijalankan secara terpisah untuk Major Market dan Small Market, sehingga dapat dibandingkan besar dan arah pengaruh Sales dan Marketing terhadap Profit di kedua segmen.
\[\text{Profit}_i = \beta_0 + \beta_1 \cdot \text{Sales}_i + \beta_2 \cdot \text{Marketing}_i + \varepsilon_i\]
di mana:
df_major <- df %>% filter(`Market Size` == "Major Market")
df_small <- df %>% filter(`Market Size` == "Small Market")
cat("Jumlah observasi Major Market:", nrow(df_major), "\n")## Jumlah observasi Major Market: 1704
## Jumlah observasi Small Market: 2544
##
## Call:
## lm(formula = Profit ~ Sales + Marketing, data = df_major)
##
## Residuals:
## Min 1Q Median 3Q Max
## -235.250 -14.951 -1.301 18.998 261.289
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -26.181496 1.816300 -14.41 <2e-16 ***
## Sales 0.896038 0.007898 113.46 <2e-16 ***
## Marketing -2.799807 0.048023 -58.30 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 41.5 on 1701 degrees of freedom
## Multiple R-squared: 0.8886, Adjusted R-squared: 0.8885
## F-statistic: 6786 on 2 and 1701 DF, p-value: < 2.2e-16
Interpretasi (Major Market): Berdasarkan output di atas, koefisien Sales sebesar \(\hat{\beta}_1 = 0.896\) menunjukkan bahwa setiap kenaikan satu unit Sales dengan Marketing dianggap konstan dimaknai dengan kenaikan Profit rata-rata sebesar \(0.896\) unit, dan hasil ini signifikan secara statistik (\(p\text{-value} < 0.05\)). Sebaliknya, koefisien Marketing sebesar \(\hat{\beta}_2 = -2.7998\) bernilai negatif, yang berarti penambahan biaya pemasaran justru dikaitkan dengan penurunan Profit saat Sales dikendalikan. Model ini mampu menjelaskan \(88.9\%\) variasi Profit pada Major Market (\(R^2 = 0.8886\)).
##
## Call:
## lm(formula = Profit ~ Sales + Marketing, data = df_small)
##
## Residuals:
## Min 1Q Median 3Q Max
## -358.94 -12.61 2.30 14.64 124.89
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -24.41175 1.06510 -22.92 <2e-16 ***
## Sales 0.83018 0.00779 106.57 <2e-16 ***
## Marketing -2.37944 0.03731 -63.78 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 32.47 on 2541 degrees of freedom
## Multiple R-squared: 0.8216, Adjusted R-squared: 0.8215
## F-statistic: 5852 on 2 and 2541 DF, p-value: < 2.2e-16
Interpretasi (Small Market): Pada segmen Small Market, koefisien Sales sebesar \(\hat{\beta}_1 = 0.8302\) tetap positif dan signifikan, namun nilainya lebih kecil dibanding Major Market. Ini berarti efek marginal setiap unit penjualan terhadap profit lebih rendah di pasar kecil. Koefisien Marketing sebesar \(\hat{\beta}_2 = -2.3794\) juga bernilai negatif, sehingga berarti pengeluaran pemasaran yang lebih besar tidak menjamin kenaikan profit. Nilai \(R^2 = 0.8216\) yang lebih rendah dari Major Market menandakan bahwa Sales dan Marketing saja belum cukup untuk menjelaskan variasi profit di Small Market.
coef_major <- summary(model_major)$coefficients
coef_small <- summary(model_small)$coefficients
tbl_coef <- data.frame(
Variabel = rownames(coef_major),
`Beta Major` = round(coef_major[, "Estimate"], 4),
`p-val Major` = round(coef_major[, "Pr(>|t|)"], 4),
`Beta Small` = round(coef_small[, "Estimate"], 4),
`p-val Small` = round(coef_small[, "Pr(>|t|)"], 4)
)
kable(tbl_coef,
caption = "Perbandingan Koefisien Regresi: Major Market vs Small Market",
col.names = c("Variabel","β Major","p-value Major","β Small","p-value Small")) %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Variabel | β Major | p-value Major | β Small | p-value Small | |
|---|---|---|---|---|---|
| (Intercept) | (Intercept) | -26.1815 | 0 | -24.4117 | 0 |
| Sales | Sales | 0.8960 | 0 | 0.8302 | 0 |
| Marketing | Marketing | -2.7998 | 0 | -2.3794 | 0 |
Hipotesis:
Taraf signifikansi: \(\alpha = 0.05\)
sw_major <- shapiro.test(model_major$residuals)
sw_small <- shapiro.test(model_small$residuals)
cat("=== Major Market ===\n")## === Major Market ===
##
## Shapiro-Wilk normality test
##
## data: model_major$residuals
## W = 0.88685, p-value < 2.2e-16
##
## === Small Market ===
##
## Shapiro-Wilk normality test
##
## data: model_small$residuals
## W = 0.72086, p-value < 2.2e-16
par(mfrow = c(1, 2))
qqnorm(model_major$residuals, main = "QQ-Plot: Major Market",
col = "#2E86AB", pch = 16, cex = 0.5)
qqline(model_major$residuals, col = "red", lwd = 1.5)
qqnorm(model_small$residuals, main = "QQ-Plot: Small Market",
col = "#E84855", pch = 16, cex = 0.5)
qqline(model_small$residuals, col = "red", lwd = 1.5)Gambar 2. QQ-Plot Residual Model Regresi
Interpretasi: Uji Shapiro-Wilk pada Major Market menghasilkan \(p\text{-value} = 0\) dan pada Small Market \(p\text{-value} = 0\). Karena jumlah observasi yang besar (\(n > 1000\)), uji Shapiro-Wilk menjadi sensitif dan cenderung menolak \(H_0\) meskipun penyimpangan dari normalitas sangat kecil. Oleh karena itu, QQ-Plot dijadikan acuan utama. Titik-titik pada kedua panel terlihat mengikuti garis diagonal merah dengan cukup baik di bagian tengah distribusi, meski terdapat sedikit penyimpangan di bagian ekor (tails). Secara keseluruhan, asumsi normalitas residual dapat dianggap terpenuhi secara praktis dan model masih layak untuk diinterpretasikan.
Hipotesis:
## === Major Market ===
##
## studentized Breusch-Pagan test
##
## data: model_major
## BP = 200.01, df = 2, p-value < 2.2e-16
##
## === Small Market ===
##
## studentized Breusch-Pagan test
##
## data: model_small
## BP = 691.15, df = 2, p-value < 2.2e-16
par(mfrow = c(1, 2))
plot(model_major$fitted.values, model_major$residuals,
main = "Residual vs Fitted: Major Market",
xlab = "Fitted Values", ylab = "Residuals",
col = "#2E86AB", pch = 16, cex = 0.5)
abline(h = 0, col = "red", lty = 2)
plot(model_small$fitted.values, model_small$residuals,
main = "Residual vs Fitted: Small Market",
xlab = "Fitted Values", ylab = "Residuals",
col = "#E84855", pch = 16, cex = 0.5)
abline(h = 0, col = "red", lty = 2)Gambar 3. Plot Residual vs Fitted Values
Interpretasi: Uji Breusch-Pagan menguji apakah variansi residual bersifat konstan di sepanjang nilai prediksi. Apabila \(p\text{-value} < 0.05\), maka \(H_0\) (variansi homogen) ditolak dan terdapat indikasi heteroskedastisitas. Dari plot Residual vs Fitted di atas, dapat diamati bahwa sebaran titik-titik residual cenderung melebar seiring bertambahnya nilai fitted. Pola ini merupakan ciri khas heteroskedastisitas. Kondisi ini umum terjadi pada data bisnis dengan rentang nilai yang lebar, dan tidak membatalkan kesimpulan analisis, namun perlu dicatat sebagai keterbatasan model bahwa estimasi standard error koefisien mungkin kurang efisien.
Nilai Variance Inflation Factor (VIF) \(> 10\) mengindikasikan multikolinearitas serius.
## === VIF Major Market ===
## Sales Marketing
## 1.878332 1.878332
##
## === VIF Small Market ===
## Sales Marketing
## 2.075058 2.075058
Interpretasi: Nilai VIF untuk variabel Sales dan Marketing pada kedua model berada jauh di bawah ambang batas 10. Hal ini menunjukkan bahwa tidak terdapat multikolinearitas. Dengan demikian, koefisien regresi yang dihasilkan dapat diinterpretasikan secara terpisah untuk masing-masing prediktor tanpa bias yang disebabkan oleh kolinearitas.
r2_major <- summary(model_major)$r.squared
r2_small <- summary(model_small)$r.squared
adj_r2_major <- summary(model_major)$adj.r.squared
adj_r2_small <- summary(model_small)$adj.r.squared
fstat_major <- summary(model_major)$fstatistic
fstat_small <- summary(model_small)$fstatistic
pval_f_major <- pf(fstat_major[1], fstat_major[2], fstat_major[3], lower.tail = FALSE)
pval_f_small <- pf(fstat_small[1], fstat_small[2], fstat_small[3], lower.tail = FALSE)
gof_tbl <- data.frame(
Metrik = c("R²", "Adjusted R²", "F-statistic", "p-value (F)"),
`Major Market` = c(round(r2_major, 4), round(adj_r2_major, 4),
round(fstat_major[1], 2), formatC(pval_f_major, format = "e", digits = 3)),
`Small Market` = c(round(r2_small, 4), round(adj_r2_small, 4),
round(fstat_small[1], 2), formatC(pval_f_small, format = "e", digits = 3))
)
kable(gof_tbl, caption = "Ringkasan Goodness of Fit Model Regresi") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Metrik | Major.Market | Small.Market |
|---|---|---|
| R² | 0.8886 | 0.8216 |
| Adjusted R² | 0.8885 | 0.8215 |
| F-statistic | 6785.6 | 5851.78 |
| p-value (F) | 0.000e+00 | 0.000e+00 |
Pada Major Market, koefisien Sales sebesar \(\hat{\beta}_1 = 0.896\) menunjukkan bahwa setiap kenaikan satu unit Sales diasosiasikan dengan kenaikan Profit sebesar \(0.896\) unit, dengan \(p\text{-value} < 0.05\) (signifikan). Pada Small Market, koefisien Sales sebesar \(\hat{\beta}_1 = 0.8302\) — lebih kecil dari Major Market, namun tetap signifikan.
Koefisien Marketing bernilai negatif di kedua model:
Hasil ini, dikontrol terhadap Sales, mengindikasikan bahwa pengeluaran Marketing yang lebih tinggi tidak serta-merta meningkatkan Profit, bahkan berpotensi menguranginya jika tidak diimbangi peningkatan penjualan.
Nilai \(R^2\) pada Major Market (\(R^2 = 0.8886\)) lebih tinggi dibandingkan Small Market (\(R^2 = 0.8216\)). Artinya, variabel Sales dan Marketing mampu menjelaskan lebih banyak variasi Profit di pasar besar dibanding pasar kecil. Di pasar kecil, terdapat faktor-faktor lain di luar model (seperti kondisi lokal, kompetisi, atau fluktuasi biaya) yang lebih berperan.