Dataset yang digunakan dalam laporan ini adalah Coffee Chain Dataset yang berisi data transaksi penjualan produk kopi dari berbagai wilayah di Amerika Serikat, mencakup 4.248 observasi dengan 20 variabel. Dataset ini memuat informasi seputar produk, wilayah pemasaran, biaya produksi, pengeluaran marketing, margin, hingga profit aktual dan anggaran.
Sebagai dataset pendamping, digunakan US Household Income Statistics (sumber: Kaggle — US Household Income Stats & Geo Locations) yang berisi data pendapatan rumah tangga dari lebih dari 32.000 lokasi di Amerika Serikat dan akan diringkas ke tingkat negara bagian (state).
“Apa sebenarnya yang paling menentukan profit di bisnis Coffee Chain? Apakah cukup dengan meningkatkan marketing, atau justru faktor internal seperti efisiensi yang lebih berperan? Selain itu, apakah kondisi daya beli masyarakat di suatu negara bagian ikut memengaruhi hasil tiap transaksi?”
Insight ini diangkat karena beberapa temuan menarik dari eksplorasi data awal:
marketing berkorelasi rendah dengan
profit, padahal secara logika bisnis marketing seharusnya
mendorong profit.margin berkorelasi sangat kuat dengan profit,
mengindikasikan efisiensi operasional jauh lebih penting dari besarnya
pengeluaran marketing.median_mean_income) sebagai variabel eksternal memiliki
pengaruh signifikan terhadap profitabilitas Coffee Chain, baik
melalui analisis korelasi di level state maupun sebagai prediktor dalam
model regresi di level transaksi.library(dplyr)
library(ggplot2)
library(lubridate)
library(janitor)
library(tidyr)
library(corrplot)
library(scales)
library(gridExtra)
library(readxl)
# Import Coffee Chain Dataset dari file XLSX (dataset utama dari SPADA UNS)
coffeetugas <- read_xlsx("C:/Users/Lenovo/Downloads/1. Tugas SIM 2025B - Coffee Chain Datasets/1. Tugas SIM 2025B - Coffee Chain Datasets.xlsx")
coffeetugas <- clean_names(coffeetugas)
# Import dataset pendamping: US Household Income Statistics
income <- read.csv("C:/Users/Lenovo/Downloads/archive (2)/kaggle_income.csv")
income <- clean_names(income)
# Kolom date dari XLSX sudah bertipe POSIXct (cukup konversi ke Date)
coffeetugas$date <- as.Date(coffeetugas$date)
coffeetugas$bulan <- floor_date(coffeetugas$date, "month")
coffeetugas$tahun <- year(coffeetugas$date)
# Normalisasi nama state ke huruf kecil untuk keamanan merge
coffeetugas$state <- tolower(trimws(coffeetugas$state))
cat("Dimensi data coffee :", nrow(coffeetugas), "baris x", ncol(coffeetugas), "kolom\n")
## Dimensi data coffee : 4248 baris x 22 kolom
cat("Rentang tanggal :", as.character(min(coffeetugas$date)),
"s.d.", as.character(max(coffeetugas$date)), "\n")
## Rentang tanggal : 2012-01-01 s.d. 2013-12-01
cat("Jumlah missing value:", sum(is.na(coffeetugas)), "\n")
## Jumlah missing value: 0
cat("Jumlah negara bagian:", n_distinct(coffeetugas$state), "\n")
## Jumlah negara bagian: 20
cat("Jumlah produk :", n_distinct(coffeetugas$product), "\n")
## Jumlah produk : 13
cat("Dimensi data income :", nrow(income), "baris x", ncol(income), "kolom\n")
## Dimensi data income : 32526 baris x 19 kolom
cat("Jumlah missing value:", sum(is.na(income)), "\n")
## Jumlah missing value: 0
# Normalisasi nama state ke huruf kecil agar merge tidak gagal diam-diam
income$state_name <- tolower(trimws(income$state_name))
# Agregasi per negara bagian menggunakan MEDIAN dari kolom Mean.
# Kolom 'mean' merepresentasikan rata-rata income per wilayah administratif kecil (place).
# Jika dirata-ratakan kembali (mean of mean), hasilnya bisa bias karena wilayah kecil
# dan miskin cenderung lebih banyak jumlahnya. Median lebih robust terhadap
# ketidakseimbangan distribusi jumlah wilayah antar state.
income_state <- income %>%
group_by(state_name) %>%
summarise(
median_mean_income = median(mean, na.rm = TRUE),
median_income = median(median, na.rm = TRUE),
.groups = "drop"
)
cat("\nRingkasan median_mean_income per negara bagian:\n")
##
## Ringkasan median_mean_income per negara bagian:
print(summary(income_state$median_mean_income))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24382 54344 59471 62030 70123 91588
Catatan : Dalam analisis ini digunakan median sebagai representasi income per state, bukan rata-rata dari rata-rata. Alasannya untuk menghindari bias yang muncul akibat jumlah wilayah kecil (place) yang tidak seragam antar state. Median lebih robust terhadap distribusi yang skewed dan ketidakseimbangan jumlah observasi.
state_coffee <- unique(coffeetugas$state)
state_income <- unique(income_state$state_name)
state_tidak_cocok <- setdiff(state_coffee, state_income)
cat("State di coffee yang TIDAK ada di income:\n")
## State di coffee yang TIDAK ada di income:
if (length(state_tidak_cocok) == 0) {
cat(" --> Semua state cocok. Merge aman.\n")
} else {
print(state_tidak_cocok)
}
## --> Semua state cocok. Merge aman.
# --- Join Level STATE (untuk visualisasi konteks dan analisis korelasi daya beli) ---
coffee_state <- coffeetugas %>%
group_by(state, market) %>%
summarise(
total_profit = sum(profit),
total_sales = sum(sales),
total_cogs = sum(cogs),
total_margin = sum(margin),
avg_profit = mean(profit),
avg_marketing = mean(marketing),
jumlah_transaksi = n(),
.groups = "drop"
)
data_gabung <- coffee_state %>%
left_join(income_state, by = c("state" = "state_name")) %>%
na.omit()
cat("State berhasil di-merge :", nrow(data_gabung), "\n")
## State berhasil di-merge : 20
cat("Missing setelah merge :", sum(is.na(data_gabung)), "\n\n")
## Missing setelah merge : 0
knitr::kable(
data_gabung %>%
select(state, market, total_profit, median_mean_income, jumlah_transaksi) %>%
arrange(desc(total_profit)),
caption = "Ringkasan Data Gabungan: Coffee Chain & Household Income per State",
col.names = c("State", "Market", "Total Profit",
"Median Mean Income (USD)", "Jumlah Transaksi")
)
| State | Market | Total Profit | Median Mean Income (USD) | Jumlah Transaksi |
|---|---|---|---|---|
| california | West | 31785 | 72331.5 | 288 |
| illinois | Central | 30821 | 64024.0 | 216 |
| iowa | Central | 22212 | 60311.0 | 216 |
| new york | East | 20096 | 71152.5 | 192 |
| colorado | Central | 17743 | 70118.5 | 264 |
| massachusetts | East | 16442 | 83929.5 | 144 |
| texas | South | 15766 | 59660.0 | 168 |
| oregon | West | 12439 | 59333.0 | 264 |
| florida | East | 12310 | 55946.0 | 216 |
| washington | West | 11405 | 69906.5 | 240 |
| ohio | Central | 10773 | 56121.0 | 216 |
| nevada | West | 10616 | 62243.0 | 264 |
| wisconsin | Central | 8702 | 61217.5 | 216 |
| oklahoma | South | 8558 | 50914.5 | 168 |
| utah | West | 7751 | 68554.0 | 288 |
| connecticut | East | 7621 | 86702.0 | 168 |
| louisiana | South | 7355 | 52979.0 | 168 |
| missouri | Central | 3601 | 52084.0 | 216 |
| new hampshire | East | 2748 | 75274.0 | 168 |
| new mexico | South | 799 | 54767.0 | 168 |
# --- Join Level TRANSAKSI (untuk model regresi) ---
coffee_model <- coffeetugas %>%
left_join(income_state, by = c("state" = "state_name")) %>%
na.omit()
# Persiapan transformasi log untuk Model 3
# Karena profit bisa negatif, dilakukan shift agar seluruh nilai positif
min_profit <- min(coffee_model$profit)
coffee_model <- coffee_model %>%
mutate(profit_shifted = profit - min_profit + 1,
log_profit = log(profit_shifted))
cat("Dimensi data model :", nrow(coffee_model), "baris x",
ncol(coffee_model), "kolom\n")
## Dimensi data model : 4248 baris x 26 kolom
cat("Nilai min profit :", min_profit, "\n")
## Nilai min profit : -638
cat("Rentang log_profit :",
round(min(coffee_model$log_profit), 3), "s.d.",
round(max(coffee_model$log_profit), 3), "\n")
## Rentang log_profit : 0 s.d. 7.256
Catatan : Karena terdapat nilai profit negatif
(minimum = -638), transformasi log tidak bisa langsung diterapkan.
Dilakukan shift terlebih dahulu:
profit_shifted = profit - min(profit) + 1, sehingga seluruh
nilai menjadi positif (minimum = 1) sebelum ditransformasi ke skala log.
Ini adalah prosedur standar untuk menerapkan log-transform pada data
yang mengandung nilai nol atau negatif.
ggplot(coffeetugas, aes(x = profit)) +
geom_histogram(bins = 40, fill = "#6F4E37", color = "white", alpha = 0.85) +
geom_vline(xintercept = mean(coffeetugas$profit), color = "red",
linetype = "dashed", linewidth = 1) +
geom_vline(xintercept = median(coffeetugas$profit), color = "darkorange",
linetype = "dashed", linewidth = 1) +
annotate("text", x = mean(coffeetugas$profit) + 70, y = 300,
label = paste0("Mean = ", round(mean(coffeetugas$profit), 1)),
color = "red", size = 3.5) +
annotate("text", x = median(coffeetugas$profit) - 90, y = 270,
label = paste0("Median = ", round(median(coffeetugas$profit), 1)),
color = "darkorange", size = 3.5) +
labs(title = "Distribusi Profit per Transaksi",
subtitle = "Data Coffee Chain (4.248 observasi)",
x = "Profit", y = "Frekuensi") +
theme_minimal()
Interpretasi: Distribusi profit bersifat right-skewed (menjulur ke kanan). Mayoritas transaksi menghasilkan profit rendah hingga sedang, dengan mean 61.1 dan median 40. Selisih antara keduanya mengindikasikan adanya transaksi dengan profit sangat tinggi yang menarik rata-rata ke atas. Terdapat pula transaksi dengan profit sangat negatif (hingga -638). Skewness dan outlier ekstrem ini menjadi justifikasi utama diperlukannya Model 3 berbasis transformasi log.
profit_produk <- coffeetugas %>%
group_by(product, product_type) %>%
summarise(total_profit = sum(profit), .groups = "drop") %>%
arrange(desc(total_profit))
ggplot(profit_produk,
aes(x = reorder(product, total_profit),
y = total_profit, fill = product_type)) +
geom_col(alpha = 0.9) +
geom_text(aes(label = comma(total_profit),
hjust = ifelse(total_profit >= 0, -0.1, 1.1)), size = 3) +
geom_hline(yintercept = 0, linewidth = 0.5, color = "black") +
coord_flip() +
scale_fill_brewer(palette = "Set2") +
scale_y_continuous(labels = comma,
expand = expansion(mult = c(0.12, 0.15))) +
labs(title = "Total Profit berdasarkan Produk",
subtitle = "Green Tea adalah satu-satunya produk dengan profit negatif",
x = "Produk", y = "Total Profit", fill = "Tipe Produk") +
theme_minimal() +
theme(legend.position = "bottom")
Interpretasi: Colombian (Coffee) menjadi produk paling menguntungkan, diikuti Lemon (Tea) dan Decaf Espresso. Satu-satunya produk yang mengalami kerugian adalah Green Tea dengan total profit negatif sehingga perlu dievaluasi dari sisi harga jual, COGS, maupun permintaan pasar.
profit_state_viz <- coffeetugas %>%
group_by(state, market) %>%
summarise(total_profit = sum(profit), .groups = "drop") %>%
arrange(desc(total_profit))
ggplot(profit_state_viz,
aes(x = reorder(state, total_profit),
y = total_profit, fill = market)) +
geom_col(alpha = 0.9) +
geom_text(aes(label = comma(total_profit)), hjust = -0.1, size = 2.8) +
coord_flip() +
scale_fill_brewer(palette = "Set1") +
scale_y_continuous(labels = comma,
expand = expansion(mult = c(0, 0.15))) +
labs(title = "Total Profit berdasarkan Negara Bagian",
subtitle = "Diwarnai berdasarkan wilayah market (Central / East / South / West)",
x = "Negara Bagian", y = "Total Profit", fill = "Market Region") +
theme_minimal() +
theme(legend.position = "bottom")
Interpretasi: California (West) dan Illinois (Central) adalah dua negara bagian dengan profit tertinggi. New Mexico (South) merupakan yang terendah. Wilayah South secara konsisten menunjukkan performa lebih rendah dibanding wilayah lain.
ggplot(coffeetugas, aes(x = market, y = profit, fill = market)) +
geom_boxplot(alpha = 0.8, outlier.color = "red", outlier.size = 1) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 3.5, color = "black") +
scale_fill_brewer(palette = "Set1") +
labs(title = "Distribusi Profit per Market Region",
subtitle = "Titik hitam = mean; titik merah = outlier",
x = "Market Region", y = "Profit") +
theme_minimal() +
theme(legend.position = "none")
Interpretasi: Keempat market region memiliki distribusi profit yang serupa. Market West menunjukkan nilai median dan mean yang sedikit lebih tinggi. Adanya outlier negatif di semua region menunjukkan bahwa transaksi tidak menguntungkan bukan hanya terjadi di wilayah tertentu saja.
num_data <- coffeetugas %>%
select(budget_cogs, budget_margin, budget_profit,
budget_sales, cogs, inventory, margin,
marketing, profit, sales, total_expenses)
cor_matrix <- cor(num_data)
corrplot(cor_matrix,
method = "color",
type = "upper",
addCoef.col = "black",
number.cex = 0.62,
tl.cex = 0.72,
col = colorRampPalette(c("#D73027", "white", "#1A9850"))(200),
title = "Heatmap Korelasi Variabel Numerik Coffee Chain",
mar = c(0, 0, 2, 0))
Interpretasi: Temuan utama dari heatmap korelasi:
margin → profit: r =
0.92. Hubungan sangat kuat dan positif, menunjukkan
margin sebagai penentu utama profit.budget_profit → profit: r
= 0.94. Perencanaan anggaran berkorelasi erat dengan
realisasi profit.sales → profit: r =
0.8 . Hubungan kuat, volume penjualan berkontribusi
langsung terhadap profit.marketing → profit: r =
0.23 . Signifikan secara statistik, namun lemah
secara praktis. Menunjukkan bahwa Marketing bukan penentu utama
profit.marketing →
total_expenses: r = 0.97 .
Menunjukkan bahwa marketing adalah komponen dominan pengeluaran.inventory → profit: r =
-0.09 . Hubungan negatif lemah, penumpukan stok tidak
memberikan kontribusi terhadap profit.Bagian ini secara langsung menjawab pertanyaan utama insight: apakah daya beli masyarakat di suatu negara bagian berhubungan dengan profitabilitas Coffee Chain?
ggplot(data_gabung, aes(x = median_mean_income, y = total_profit)) +
geom_point(aes(size = jumlah_transaksi, color = market), alpha = 0.8) +
geom_smooth(method = "lm", se = TRUE, color = "black",
linetype = "dashed", linewidth = 1) +
geom_text(aes(label = state), vjust = -0.8, size = 2.8, color = "gray30") +
scale_color_brewer(palette = "Set1") +
scale_size_continuous(range = c(3, 10)) +
scale_x_continuous(labels = comma) +
scale_y_continuous(labels = comma) +
labs(title = "Hubungan Daya Beli (Income) dan Total Profit per State",
subtitle = "Ukuran titik = jumlah transaksi; garis = tren regresi linear",
x = "Median Mean Household Income (USD)",
y = "Total Profit",
color = "Market Region",
size = "Jumlah Transaksi") +
theme_minimal() +
theme(legend.position = "bottom")
Interpretasi: Scatter plot menunjukkan arah hubungan
positif antara median_mean_income dan
total_profit per state. Negara bagian dengan tingkat
pendapatan rumah tangga lebih tinggi cenderung menghasilkan total profit
lebih besar. Namun, sebaran titik yang cukup lebar mengindikasikan bahwa
income bukan satu-satunya penentu: jumlah transaksi
(ukuran titik) tampaknya juga berperan penting. Uji korelasi formal
disajikan di Bagian 4.
ggplot(coffeetugas, aes(x = margin, y = profit, color = product_type)) +
geom_point(alpha = 0.3, size = 1) +
geom_smooth(method = "lm", se = FALSE, linewidth = 1.1) +
scale_color_brewer(palette = "Dark2") +
labs(title = "Hubungan Margin dan Profit per Tipe Produk",
subtitle = "Garis = tren regresi linear masing-masing tipe produk",
x = "Margin", y = "Profit", color = "Tipe Produk") +
theme_minimal() +
theme(legend.position = "bottom")
Interpretasi: Hubungan linear positif yang sangat kuat antara margin dan profit konsisten di seluruh tipe produk. Kemiringan garis regresi hampir seragam, pengaruh margin terhadap profit tidak berbeda jauh antar tipe produk. Produk Espresso dan Coffee memiliki rentang nilai lebih lebar, sementara Herbal Tea lebih terkonsentrasi di nilai rendah.
budget_vs_actual <- coffeetugas %>%
group_by(product) %>%
summarise(Realisasi = sum(profit),
Anggaran = sum(budget_profit),
.groups = "drop") %>%
pivot_longer(cols = c(Realisasi, Anggaran),
names_to = "Jenis", values_to = "Nilai")
ggplot(budget_vs_actual,
aes(x = reorder(product, Nilai), y = Nilai, fill = Jenis)) +
geom_col(position = "dodge", alpha = 0.9) +
geom_hline(yintercept = 0, linewidth = 0.5) +
coord_flip() +
scale_fill_manual(values = c("Anggaran" = "#AED6F1",
"Realisasi" = "#6F4E37")) +
scale_y_continuous(labels = comma) +
labs(title = "Budget Profit vs Realisasi Profit per Produk",
subtitle = "Biru = Anggaran; Coklat = Realisasi",
x = "Produk", y = "Total Profit", fill = "") +
theme_minimal() +
theme(legend.position = "bottom")
Interpretasi: Hampir semua produk berhasil mencapai atau melampaui anggaran profit. Colombian mencatat realisasi jauh di atas anggaran. Green Tea adalah kasus kritis: tidak hanya gagal memenuhi anggaran, tetapi menghasilkan profit negatif yang mengindikasikan masalah fundamental pada penetapan harga atau biaya produksi.
tren_bulanan <- coffeetugas %>%
group_by(bulan) %>%
summarise(total_profit = sum(profit), .groups = "drop")
ggplot(tren_bulanan, aes(x = bulan, y = total_profit)) +
geom_line(color = "#6F4E37", linewidth = 1.1) +
geom_point(color = "#6F4E37", size = 2) +
geom_smooth(method = "loess", se = TRUE, color = "steelblue",
linetype = "dashed", alpha = 0.12) +
scale_x_date(date_labels = "%b %Y", date_breaks = "3 months") +
scale_y_continuous(labels = comma) +
labs(title = "Tren Total Profit per Bulan",
subtitle = "Garis biru putus-putus = tren LOESS (smoothed)",
x = "Bulan", y = "Total Profit") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Interpretasi: Profit bulanan berfluktuasi namun secara keseluruhan relatif stabil. Garis tren LOESS menunjukkan kenaikan di awal-pertengahan periode dan sedikit penurunan di akhir. Fluktuasi tajam di beberapa bulan kemungkinan mencerminkan pengaruh musiman atau perubahan strategi pemasaran.
p1 <- ggplot(coffee_model, aes(x = profit)) +
geom_histogram(bins = 40, fill = "#6F4E37", color = "white", alpha = 0.85) +
labs(title = "Distribusi Profit Asli",
subtitle = "Right-skewed, outlier ekstrem",
x = "Profit", y = "Frekuensi") +
theme_minimal()
p2 <- ggplot(coffee_model, aes(x = log_profit)) +
geom_histogram(bins = 40, fill = "#2471A3", color = "white", alpha = 0.85) +
labs(title = "Distribusi Log(Profit Shifted)",
subtitle = "Lebih simetris, mendekati normal",
x = "log(profit_shifted)", y = "Frekuensi") +
theme_minimal()
grid.arrange(p1, p2, ncol = 2)
Interpretasi: Distribusi profit asli (kiri) jelas right-skewed dengan ekor panjang dan outlier negatif ekstrem. Kondisi ini berpotensi melanggar asumsi normalitas residual dalam OLS. Setelah ditransformasi ke skala log (kanan), distribusinya jauh lebih simetris dan mendekati normal, sehingga asumsi regresi lebih terpenuhi dan estimasi koefisien lebih stabil.
cat("=== Uji Korelasi Pearson: Variabel Prediktor vs Profit (n =",
nrow(coffee_model), ") ===\n\n")
## === Uji Korelasi Pearson: Variabel Prediktor vs Profit (n = 4248 ) ===
vars_uji <- c("margin", "sales", "marketing", "cogs", "total_expenses")
for (v in vars_uji) {
kor <- cor.test(coffee_model[[v]], coffee_model$profit, method = "pearson")
cat(sprintf("%-20s | r = %6.4f | p-value = %.4f | %s\n",
v, kor$estimate, kor$p.value,
ifelse(kor$p.value < 0.05, "SIGNIFIKAN *", "tidak signifikan")))
}
## margin | r = 0.9206 | p-value = 0.0000 | SIGNIFIKAN *
## sales | r = 0.7973 | p-value = 0.0000 | SIGNIFIKAN *
## marketing | r = 0.2255 | p-value = 0.0000 | SIGNIFIKAN *
## cogs | r = 0.4648 | p-value = 0.0000 | SIGNIFIKAN *
## total_expenses | r = 0.2000 | p-value = 0.0000 | SIGNIFIKAN *
Interpretasi: margin memiliki korelasi
tertinggi dengan profit. Ini merupakan insight terkuat
dalam dataset. sales juga berkorelasi kuat.
marketing memiliki korelasi yang signifikan secara
statistik (p < 0.05, didorong oleh besarnya n = 4.248),
namun hubungannya lemah secara praktis. Oleh karena
itu, tidak tepat menyimpulkan bahwa marketing adalah penentu utama
profit hanya karena p-value-nya kecil.
Bagian ini secara langsung menjawab pertanyaan utama insight dengan uji statistik formal.
cat("=== Uji Korelasi Pearson: Daya Beli vs Total Profit per State ===\n\n")
## === Uji Korelasi Pearson: Daya Beli vs Total Profit per State ===
kor_income <- cor.test(data_gabung$median_mean_income,
data_gabung$total_profit,
method = "pearson")
cat(sprintf("Variabel : median_mean_income vs total_profit\n"))
## Variabel : median_mean_income vs total_profit
cat(sprintf("n (state) : %d\n", nrow(data_gabung)))
## n (state) : 20
cat(sprintf("Koefisien Korelasi: r = %.4f\n", kor_income$estimate))
## Koefisien Korelasi: r = 0.2323
cat(sprintf("p-value : %.4f\n", kor_income$p.value))
## p-value : 0.3244
cat(sprintf("95%% CI : [%.4f, %.4f]\n",
kor_income$conf.int[1], kor_income$conf.int[2]))
## 95% CI : [-0.2343, 0.6119]
cat(sprintf("Kesimpulan : %s\n",
ifelse(kor_income$p.value < 0.05,
"SIGNIFIKAN * — terdapat hubungan linear antara income dan profit",
"Tidak signifikan — tidak cukup bukti adanya hubungan linear")))
## Kesimpulan : Tidak signifikan — tidak cukup bukti adanya hubungan linear
Interpretasi: Uji korelasi Pearson antara
median_mean_income dan total_profit di level
state memberikan jawaban langsung atas pertanyaan utama laporan ini.
Hasil menunjukkan korelasi positif namun tidak signifikan secara
statistik (p > 0.05), artinya tidak cukup bukti bahwa negara
bagian dengan income lebih tinggi secara konsisten menghasilkan profit
lebih besar, pada level agregat state dengan n yang kecil. Perlu
diperhatikan pula bahwa korelasi di level state ini juga dipengaruhi
oleh jumlah transaksi per state. Analisis lebih lanjut di level
transaksi dilakukan melalui model regresi.
model_1 <- lm(profit ~ margin, data = coffee_model)
summary(model_1)
##
## Call:
## lm(formula = profit ~ margin, data = coffee_model)
##
## Residuals:
## Min 1Q Median 3Q Max
## -295.859 -12.801 6.893 24.650 220.291
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -42.411601 0.908535 -46.68 <2e-16 ***
## margin 0.992483 0.006461 153.62 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 39.72 on 4246 degrees of freedom
## Multiple R-squared: 0.8475, Adjusted R-squared: 0.8475
## F-statistic: 2.36e+04 on 1 and 4246 DF, p-value: < 2.2e-16
Interpretasi: Model paling sederhana menggunakan
margin sebagai satu-satunya prediktor. R² yang diperoleh
menunjukkan bahwa margin tunggal sudah mampu menjelaskan sebagian besar
variasi profit per transaksi. Koefisien margin positif dan
sangat signifikan (p < 0.001). Ini menjadi baseline yang
kuat, sekaligus mengkonfirmasi bahwa margin adalah penggerak utama
profitabilitas Coffee Chain. Model ini belum memperhitungkan faktor
biaya, pengeluaran lain, maupun konteks daya beli yang secara teoritis
juga relevan.
Model 2 diperluas dengan menyertakan median_mean_income
sebagai representasi daya beli masyarakat per negara bagian. Ini
merupakan pengujian inferensial langsung atas pertanyaan utama
insight.
model_2 <- lm(profit ~ margin + sales + marketing + cogs + total_expenses +
median_mean_income,
data = coffee_model)
summary(model_2)
##
## Call:
## lm(formula = profit ~ margin + sales + marketing + cogs + total_expenses +
## median_mean_income, data = coffee_model)
##
## Residuals:
## Min 1Q Median 3Q Max
## -112.792 -5.661 0.024 5.431 112.825
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.873e+00 1.892e+00 2.047 0.0407 *
## margin -4.119e-01 2.966e-02 -13.884 < 2e-16 ***
## sales 1.614e+00 2.945e-02 54.814 < 2e-16 ***
## marketing 2.618e-01 3.987e-02 6.565 5.84e-11 ***
## cogs -1.659e+00 3.167e-02 -52.385 < 2e-16 ***
## total_expenses -1.455e+00 3.074e-02 -47.347 < 2e-16 ***
## median_mean_income -1.119e-05 2.790e-05 -0.401 0.6884
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 16.49 on 4241 degrees of freedom
## Multiple R-squared: 0.9738, Adjusted R-squared: 0.9737
## F-statistic: 2.622e+04 on 6 and 4241 DF, p-value: < 2.2e-16
Interpretasi: Dengan menambahkan lima prediktor
internal plus median_mean_income, R² meningkat signifikan
dari Model 1. Pengaruh masing-masing prediktor:
margin → pada output tampak
negatif, padahal korelasi bivariat margin–profit sangat
kuat positif. Ini bukan kesalahan hitung, melainkan konsekuensi
multikolinearitas: variabel margin,
sales, cogs, dan total_expenses
saling berkorelasi kuat karena secara akuntansi memang terkait dalam
satu persamaan (profit = sales − cogs − expenses; margin ≈ sales −
cogs). Ketika semua variabel ini masuk model secara bersamaan, koefisien
parsial masing-masing mencerminkan marginal effect setelah
variabel lain dikontrol, sehingga tanda bisa berubah. Interpretasi
koefisien individual dalam kondisi multikolinearitas tinggi perlu
dilakukan dengan hati-hati, sehingga fokus yang lebih tepat adalah pada
signifikansi model secara keseluruhan (F-test dan R²)
dan konsistensi tanda koefisien di Model 3.sales → positif: volume penjualan
lebih tinggi mendorong profit.cogs → negatif: biaya pokok produksi
menekan profit.marketing → koefisiennya
negatif setelah dikontrol variabel lain, hal ini juga
mencerminkan efek multikolinearitas dengan total_expenses.
Artinya marketing tidak bisa diinterpretasikan secara mandiri dari
komponen pengeluaran lainnya.total_expenses → negatif: beban total
langsung mengurangi profit akhir.median_mean_income → tidak
signifikan (p > 0.05) pada skala asli. Ini mengindikasikan
bahwa setelah faktor operasional internal dikontrol, daya beli
masyarakat tidak memberikan pengaruh tambahan yang terdeteksi secara
statistik terhadap profit per transaksi. Analisis Model 3 akan
memberikan gambaran yang lebih robust.model_3 <- lm(log_profit ~ margin + sales + marketing + cogs + total_expenses +
median_mean_income,
data = coffee_model)
summary(model_3)
##
## Call:
## lm(formula = log_profit ~ margin + sales + marketing + cogs +
## total_expenses + median_mean_income, data = coffee_model)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.2498 -0.0097 0.0028 0.0158 0.2733
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.502e+00 1.182e-02 550.227 < 2e-16 ***
## margin 1.087e-03 1.853e-04 5.868 4.74e-09 ***
## sales 1.213e-03 1.839e-04 6.595 4.77e-11 ***
## marketing 2.432e-04 2.490e-04 0.976 0.3289
## cogs -2.075e-03 1.978e-04 -10.491 < 2e-16 ***
## total_expenses -2.214e-03 1.920e-04 -11.533 < 2e-16 ***
## median_mean_income -3.860e-07 1.743e-07 -2.215 0.0268 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.103 on 4241 degrees of freedom
## Multiple R-squared: 0.7331, Adjusted R-squared: 0.7327
## F-statistic: 1941 on 6 and 4241 DF, p-value: < 2.2e-16
Interpretasi: Model 3 menggunakan
spesifikasi berbeda secara fundamental dari Model 2:
variabel respons ditransformasi ke skala log
(log(profit_shifted)). Tujuannya adalah mengatasi skewness
dan outlier pada data profit asli, sehingga asumsi OLS lebih terpenuhi.
Temuan utama:
median_mean_income pada Model 3
kemungkinan menunjukkan signifikansi yang berbeda dari Model 2. Jika
signifikan di sini namun tidak di Model 2, ini menunjukkan bahwa
pengaruh income lemah dan sensitif terhadap distribusi
data yang hanya terdeteksi setelah transformasi meredam
distorsi outlier.median_mean_income pada skala log memiliki nilai yang
sangat kecil. Menggunakan rumus semi-log: kenaikan income sebesar
$10.000 menghasilkan perubahan profit_shifted sebesar
(exp(β × 10000) - 1) × 100%, yang secara praktis hampir
tidak berarti. Ini adalah contoh klasik di mana statistically
significant ≠ practically important.median_mean_income berada pada level agregat (state),
sementara variabel lain berada di level transaksi. Penggunaan variabel
level-state dalam model level-transaksi dapat menimbulkan
pseudo-replication, sehingga interpretasi koefisien income
perlu dilakukan dengan kehati-hatian tambahan.par(mfrow = c(2, 2))
plot(model_2,
sub.caption = "Diagnostik Asumsi: Model 2 — Regresi Berganda Skala Asli")
par(mfrow = c(1, 1))
par(mfrow = c(2, 2))
plot(model_3,
sub.caption = "Diagnostik Asumsi: Model 3 — Regresi Berganda Skala Log")
par(mfrow = c(1, 1))
Interpretasi Perbandingan Diagnostik:
| Asumsi | Model 2 (Skala Asli) | Model 3 (Skala Log) |
|---|---|---|
| Linieritas (Res. vs Fitted) | Relatif terpenuhi, sedikit pola | Lebih acak, pola berkurang |
| Normalitas residual (Q-Q) | Deviasi di kedua ekor | Lebih mendekati garis diagonal |
| Homoskedastisitas (Scale-Location) | Garis tidak sepenuhnya datar | Lebih mendatar, varians lebih stabil |
| Influential points (Cook’s distance) | Beberapa titik leverage tinggi | Lebih merata |
Model 3 memenuhi asumsi regresi secara lebih baik
dibanding Model 2, terutama pada aspek normalitas residual dan
homoskedastisitas. Oleh karena itu, kesimpulan inferensial
tentang pengaruh median_mean_income sebaiknya didasarkan
pada hasil Model 3.
# RMSE Model 3 dihitung setelah back-transform ke skala profit asli
# agar perbandingan dengan Model 1 dan 2 adil
pred_log_m3 <- fitted(model_3)
profit_hat_m3 <- exp(pred_log_m3) + min_profit - 1
rmse_m3 <- sqrt(mean((coffee_model$profit - profit_hat_m3)^2))
hasil_perbandingan <- data.frame(
Model = c(
"Model 1: Sederhana — profit ~ margin",
"Model 2: Berganda Skala Asli — profit ~ 6 prediktor (+ income)",
"Model 3: Berganda Skala Log — log(profit_shifted) ~ 6 prediktor (+ income)"
),
Pendekatan = c(
"OLS, 1 prediktor",
"OLS, 6 prediktor, skala asli",
"OLS, 6 prediktor, transformasi log (robust)"
),
N = rep(nrow(coffee_model), 3),
R2 = c(
round(summary(model_1)$r.squared, 4),
round(summary(model_2)$r.squared, 4),
round(summary(model_3)$r.squared, 4)
),
Adj_R2 = c(
round(summary(model_1)$adj.r.squared, 4),
round(summary(model_2)$adj.r.squared, 4),
round(summary(model_3)$adj.r.squared, 4)
),
RMSE = c(
round(sqrt(mean(model_1$residuals^2)), 2),
round(sqrt(mean(model_2$residuals^2)), 2),
round(rmse_m3, 2)
)
)
knitr::kable(hasil_perbandingan,
col.names = c("Model", "Pendekatan", "n", "R²", "Adj. R²",
"RMSE (skala profit asli)"),
caption = "Perbandingan Performa Ketiga Model Regresi",
align = c("l", "l", "r", "r", "r", "r"))
| Model | Pendekatan | n | R² | Adj. R² | RMSE (skala profit asli) |
|---|---|---|---|---|---|
| Model 1: Sederhana — profit ~ margin | OLS, 1 prediktor | 4248 | 0.8475 | 0.8475 | 39.71 |
| Model 2: Berganda Skala Asli — profit ~ 6 prediktor (+ income) | OLS, 6 prediktor, skala asli | 4248 | 0.9738 | 0.9737 | 16.48 |
| Model 3: Berganda Skala Log — log(profit_shifted) ~ 6 prediktor (+ income) | OLS, 6 prediktor, transformasi log (robust) | 4248 | 0.7331 | 0.7327 | 51.26 |
Catatan: R² Model 3 dihitung dalam skala log sehingga tidak dapat dibandingkan langsung dengan R² Model 1 & 2. Untuk keadilan perbandingan, RMSE Model 3 dihitung setelah back-transforming prediksi ke skala profit asli.
Interpretasi:
Rekomendasi: Model 2 untuk prediksi numerik; Model 3 untuk inferensi dan pengambilan keputusan, khususnya dalam mengevaluasi apakah daya beli masyarakat benar-benar memengaruhi profit secara statistik.
fmt_koef <- function(model, caption_text) {
koef <- as.data.frame(summary(model)$coefficients)
koef$Variabel <- rownames(koef)
rownames(koef) <- NULL
koef <- koef[, c("Variabel", "Estimate", "Std. Error", "t value", "Pr(>|t|)")]
names(koef) <- c("Variabel", "Estimasi", "Std. Error", "t-value", "p-value")
koef[, 2:5] <- round(koef[, 2:5], 6)
knitr::kable(koef, caption = caption_text,
align = c("l", "r", "r", "r", "r"))
}
fmt_koef(model_2,
"Koefisien Model 2: profit ~ margin + sales + marketing + cogs + total_expenses + median_mean_income")
| Variabel | Estimasi | Std. Error | t-value | p-value |
|---|---|---|---|---|
| (Intercept) | 3.872845 | 1.892112 | 2.046837 | 0.040736 |
| margin | -0.411855 | 0.029664 | -13.883905 | 0.000000 |
| sales | 1.614084 | 0.029447 | 54.813864 | 0.000000 |
| marketing | 0.261761 | 0.039873 | 6.564869 | 0.000000 |
| cogs | -1.658995 | 0.031669 | -52.384992 | 0.000000 |
| total_expenses | -1.455488 | 0.030741 | -47.347312 | 0.000000 |
| median_mean_income | -0.000011 | 0.000028 | -0.401031 | 0.688417 |
fmt_koef(model_3,
"Koefisien Model 3: log(profit_shifted) ~ margin + sales + marketing + cogs + total_expenses + median_mean_income")
| Variabel | Estimasi | Std. Error | t-value | p-value |
|---|---|---|---|---|
| (Intercept) | 6.502328 | 0.011818 | 550.227044 | 0.000000 |
| margin | 0.001087 | 0.000185 | 5.868211 | 0.000000 |
| sales | 0.001213 | 0.000184 | 6.595043 | 0.000000 |
| marketing | 0.000243 | 0.000249 | 0.976403 | 0.328920 |
| cogs | -0.002075 | 0.000198 | -10.491403 | 0.000000 |
| total_expenses | -0.002214 | 0.000192 | -11.532543 | 0.000000 |
| median_mean_income | 0.000000 | 0.000000 | -2.214825 | 0.026825 |
Interpretasi: Berdasarkan tabel koefisien di atas,
temuan untuk median_mean_income:
Inkonsistensi (atau kelemahan) signifikansi income antara kedua model mengindikasikan bahwa pengaruhnya lemah dan tidak stabil. Ini memperkuat kesimpulan bahwa daya beli masyarakat bukan penentu utama profitabilitas Coffee Chain.
Untuk variabel internal: tanda koefisien pada sales
(positif) dan cogs, total_expenses (negatif)
konsisten antara kedua model, hal ini memperkuat
validitas temuan bahwa faktor operasional internal adalah penggerak
dominan profit. Perubahan tanda margin di Model 2 merupakan
artefak multikolinearitas, sebagaimana telah dibahas di Bagian 4.4.
Catatan penting: Seluruh hubungan yang ditemukan dalam analisis ini bersifat asosiatif, bukan kausal. Korelasi dan regresi tidak membuktikan bahwa income menyebabkan perubahan profit. Faktor lain yang tidak terukur (confounding variables) mungkin menjelaskan hubungan yang teramati.
Berdasarkan seluruh analisis terhadap Coffee Chain Dataset yang diperkaya dengan US Household Income Dataset, diperoleh lima kesimpulan utama:
Produk Colombian adalah yang paling menguntungkan, sementara Green Tea satu-satunya produk dengan profit negatif. Green Tea perlu dievaluasi menyeluruh dari sisi harga jual, biaya produksi, dan permintaan pasar.
California dan Illinois adalah negara bagian dengan profit tertinggi. Wilayah South secara konsisten memiliki performa paling rendah, dengan New Mexico sebagai yang terendah.
Margin adalah faktor internal terkuat penentu
profit (r sangat kuat, mendekati 1). Marketing berpengaruh
signifikan secara statistik namun lemah secara praktis.
Menunjukkan bahwa pengeluaran marketing tidak serta-merta mendorong
profit tanpa didukung efisiensi margin. Strategi yang berfokus pada
peningkatan efisiensi margin terbukti lebih efektif secara
kuantitatif.
Daya beli masyarakat bukan penentu utama profitabilitas
(jawaban atas insight utama): Berdasarkan uji korelasi di level
state (tidak signifikan, p > 0.05) dan model regresi berganda,
median_mean_income tidak signifikan di Model 2 dan hanya
signifikan secara marginal di Model 3 dengan efek praktis yang sangat
kecil. Hal ini menunjukkan bahwa pengaruh income lemah, tidak
konsisten antar model, dan tidak signifikan secara praktis.
Dibandingkan dengan faktor internal seperti margin dan volume penjualan,
peran income jauh kurang dominan.Perbedaan profit antar negara bagian
lebih banyak dijelaskan oleh volume transaksi dan komposisi
produk, bukan oleh tingkat pendapatan rumah tangga di wilayah
tersebut. Perlu dicatat pula bahwa hubungan yang ditemukan bersifat
asosiatif, bukan kausal.
Ketiga model regresi memiliki peran berbeda yang saling melengkapi. Model 1 (sederhana) memberikan baseline yang kuat dan mudah dikomunikasikan. Model 2 (berganda skala asli) memberikan prediksi numerik terbaik sekaligus menguji pengaruh income secara langsung. Model 3 (berganda skala log) menghasilkan asumsi OLS yang lebih terpenuhi. Oleh karena itu, kesimpulan inferensial tentang pengaruh daya beli sebaiknya didasarkan pada Model 3 karena lebih robust terhadap outlier dan skewness data profit.