Central Tendency
Practicum ~ Week 6
1. Definisi Central Tendency
Central Tendency adalah ukuran statistik yang merepresentasikan nilai tipikal atau sentral dari suatu kumpulan data. Ukuran ini bertujuan untuk memberikan satu nilai yang paling mewakili keseluruhan data, sehingga memungkinkan kita memahami di mana sebagian besar nilai data terkonsentrasi. Tiga ukuran tendensi sentral yang paling umum adalah: Mean, Median, dan Modus.
1.1 Mean
Rata-rata diperoleh dengan membagi jumlah semua nilai data dengan jumlah total observasi. Nilai ini cocok untuk tipe data interval dan rasio.
\[ \bar{X} = \frac{\sum_{i=1}^{n} X_i}{n} \] Di mana:
- \(\bar{X}\) = rata-rata
- \(X_i\) = setiap nilai data
- \(n\) = jumlah pengamatan
1.2 Median
Median adalah nilai tengah dari kumpulan data yang diurutkan. Median cocok untuk data ordinal, interval, dan rasio. Langkah-langkah untuk Mencari Median:
Susunlah data dalam urutan menaik.
Jika jumlah titik data ganjil berada pada posisi \(\frac{n+1}{2}\)
Jika genap, median adalah rata-rata dari dua nilai tengah.
1.3 Modus
Modus adalah nilai yang paling sering muncul dalam suatu dataset. Modus dapat digunakan untuk data nominal, ordinal, interval, atau rasio.
2. Visualisasi untuk Central Tendency
Memahami ukuran tendensi sentral mean median, dan modus -lebih intuitif jika didukung oleh visualisasi. Representasi grafis seperti histogram dan boxplot membantu mengungkap bentuk, sebaran, dan keseimbangan yang mendasari suatu kumpulan data. Melalui alat visual ini, kita dapat mengidentifikasi apakah data tersebut simetris miring, kategoris atau multimodal.
Setiap visualisasi memberikan wawasan yang unik:
Histogram menunjukkan distribusi frekuensi dan bagaimana ukuran sentral selaras dengan konsentrasi data.
Kotak-kotak menyorot median, kuartil, dan keberadaan outlier dalam format yang ringkas.
Pada subbagian berikut, kita akan mengeksplorasi bagaimana kecenderungan sentral berperilaku dalam kondisi yang berbeda visualisasi histogram dan boxplot: menggunakan
Simetris dan Tanpa Outlier ketika data terdistribusi secara merata di sekitar pusat.
Nilai Ekstrem (Miring) ketika outlier menarik nilai rata-rata ke satu arah.
Variabel Kategorikal - ketika data mewakili kelompok atau kelas yang berbeda.
Lebih Dari Satu Modus ketika data memiliki beberapa puncak atau pusat konsentrasi.
2.1 Simetris dan Tidak Ada Outlier
Distribusi simetris terjadi ketika nilai-nilai data tersebar merata di sekitar titik pusat, menciptakan pola yang seimbang dan berbentuk lonceng. Dalam hal ini, nilai rata-rata median, dan modus semuanya berada pada atau mendekati titik pusat yang sama. Hal ini menunjukkan bahwa tidak ada outlier atau kemiringan signifikan yang menarik data ke satu sisi.
2.2 Nilai Ekstrem (Miring)
Distribusi miring terjadi ketika nilai-nilai data tidak terdistribusi secara simetris di sekitar pusat artinya salah satu ekor distribusi lebih panjang atau lebih melebar daripada yang lain. Kemiringan ini sering kali disebabkan oleh nilai-nilai ekstrem (outlier) yang menarik rata-rata ke satu arah, sementara median dan modus tetap mendekati puncak data.
Ketika suatu set data berisi nilai ekstrem tinggi atau rendah, distribusinya menjadi miring positif (miring ke kanan) atau miring negatif (miring ke kiri). Distorsi ini memengaruhi posisi ukuran tendensi sentral dan memberikan wawasan berharga tentang perilaku data yang mendasarinya.
2.3 Variabel Kategori
Variabel kategori membagi data ke dalam kelompok atau kategori yang berbeda. Ketika dikombinasikan dengan variabel numerik, kita dapat menganalisis perbedaan distribusi nilai numerik di berbagai kategori. Boxplot merupakan visualisasi yang sangat baik untuk tujuan ini diagram ini menunjukkan median, kuartil, rentang, dan outlier dalam setiap kelompok.
2.4 Lebih Dari Satu Modus
Dalam banyak kumpulan data dunia nyata, distribusi nilai tidak selalu membentuk satu puncak yang halus. Sebaliknya, beberapa kumpulan data menunjukkan dua atau lebih puncak yang berbeda, yang dikenal sebagai beberapa modus. Setiap modus mewakili sebuah klaster tempat nilai-nilai cenderung terkonsentrasi artinya data memiliki beberapa wilayah dengan frekuensi tinggi, alih-alih satu lokasi sentral.
Tidak seperti histogram, boxplot tidak menampilkan jumlah puncak yang tepat, tetapi menunjukkan dengan jelas bahwa data tidak terdistribusi secara simetris misalnya, garis median mungkin tidak berada di tengah, dan kumis mungkin memanjang tidak merata ke satu sisi. Bersama-sama, histogram dan boxplot memberikan wawasan yang saling melengkapi:
histogram mengungkapkan keseluruhan (dan beberapa mode), bentuk
sementara boxplot menekankan penyebaran dan kemiringan data.
3. Persiapan Data
# Persiapan Data: Bersihkan, Proses, and Tampilkan tabel interaktif
library(readxl)
library(dplyr)
library(reactable)
library(htmltools)
# 1. Mengimpor dataset
data_raw <- read.csv("4 Central Tendency – Introduction to Statistics.csv")
# 2. Bersihkan dan mempersiapkan data
data_clean <- data_raw %>%
rename_with(~ gsub("\\s+", "_", .x)) %>%
mutate(across(where(is.character), trimws)) %>%
mutate(
RecordID = sprintf("R%04d", 1:n()),
EntryDate = Sys.Date(),
)
# 3. Buat tabel interaktif dengan dropdown + animated pagination
htmltools::browsable(
htmltools::tagList(
# Control dropdown untuk jumlah data yang ditampilkan per halaman
tags$div(
style = "display:flex; align-items:center; gap:6px; margin-bottom:10px; font-size:14px;",
tags$span("Showing"),
tags$select(
id = "pageSizeSelect",
style = "padding:3px 6px; border-radius:4px; border:1px solid #ccc; font-size:14px;",
tags$option(value = 10, "10"),
tags$option(value = 25, "25"),
tags$option(value = 50, "50"),
tags$option(value = 100, "100")
),
tags$span("entries")
),
# Reactable table
reactable(
data_clean,
elementId = "myTable",
searchable = TRUE,
bordered = TRUE,
striped = TRUE,
highlight = TRUE,
resizable = TRUE,
defaultPageSize = 10,
wrap = FALSE,
fullWidth = TRUE,
defaultColDef = colDef(align = "center"),
theme = reactableTheme(
headerStyle = list(
background = "#f7f7f7",
fontWeight = "bold",
borderBottom = "2px solid #ddd"
),
# Pagination area (clear background)
paginationStyle = list(
background = "transparent",
borderTop = "1px solid #ddd",
padding = "8px 0"
),
# Pagination buttons with animation
pageButtonStyle = list(
background = "#ffffff",
border = "1px solid #90CAF9",
color = "#0D47A1",
borderRadius = "6px",
padding = "4px 10px",
margin = "0 3px",
transition = "all 0.2s ease-in-out",
boxShadow = "0 1px 3px rgba(0,0,0,0.1)",
fontWeight = "500"
),
pageButtonHoverStyle = list(
background = "#E3F2FD",
border = "1px solid #42A5F5",
transform = "scale(1.05)"
),
pageButtonActiveStyle = list(
background = "#1E88E5",
color = "white",
transform = "scale(1.05)"
)
)
),
# Menggunakan JavaScript untuk mengubah jumlah data yang ditampilkan secara dinamis
tags$script(HTML("
document.getElementById('pageSizeSelect').addEventListener('change', function() {
const newSize = parseInt(this.value);
const tbl = window.reactable.getInstance('myTable');
if (tbl) tbl.setPageSize(newSize);
});
"))
)
)4. Central Tendency dari Setiap Variabel
Berdasarkan data yang kami pakai kolom-kolom yang termasuk varibel numerik adalah:
- Age
- Total Purchase
- Number Of Visit
- Feedback Score
Berdasarkan data yang kami pakai kolom-kolom yang termasuk varibel kategori adalah:
- Gender
- Store Location
- Product Categry
Berikut adalah ringkasan Central Tendency mulai dari Mean (rata-rata), Median (nilai tengah), dan Modus (nilai yang paling sering muncul) untuk setiap kolom/variabel numerik.
4.1 Age
# Bersihkan Environment dulu biar tidak error
rm(list = ls())
# Library
library(readr)
library(dplyr)
library(plotly)
# Load Data
df <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Function: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
x <- .data[[col_name]]
x <- x[!is.na(x)]
mean_val <- mean(x)
median_val <- median(x)
mode_val <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
dens <- density(x)
hist_cal <- hist(x, plot = FALSE)
scale_factor <- max(hist_cal$counts) / max(dens$y)
plot_ly() %>%
# Histogram
add_histogram(
x = x, nbinsx = 15, opacity = 0.55,
marker = list(color = "#6FB7FF"),
name = "Histogram",
showlegend = show_legend
) %>%
# Kurva Density
add_lines(
x = dens$x, y = dens$y * scale_factor,
name = "Density Curve",
line = list(width = 3, color = "#0B3C5D"),
showlegend = show_legend
) %>%
# Garis Rata-rata
add_segments(
x = mean_val, xend = mean_val,
y = 0, yend = max(hist_cal$counts),
name = "Mean",
line = list(color = "red", width = 3),
showlegend = show_legend
) %>%
# Garis Median
add_segments(
x = median_val, xend = median_val,
y = 0, yend = max(hist_cal$counts),
name = "Median",
line = list(color = "green", width = 3, dash = "dash"),
showlegend = show_legend
) %>%
# Garis Modus
add_segments(
x = mode_val, xend = mode_val,
y = 0, yend = max(hist_cal$counts),
name = "Mode",
line = list(color = "blue", width = 3, dash = "dot"),
showlegend = show_legend
) %>%
# Layout Title and Axis Label
layout(
title = list(
text = paste("<b>Distribusi", col_name, "</b>"),
x = 0.5, xanchor = "center",
font = list(size = 20)
),
xaxis = list(title = col_name),
yaxis = list(title = "Frequency"),
legend = list(orientation = "h", y = -0.2),
margin = list(t = 80, b = 70)
)
}
create_hist_plot(df, "Age", TRUE)Interpretasi:
- Distribusi cenderung mendekati normal namun sedikit condong ke kanan (positively skewed).
- Mean > Median = Mode, menunjukkan adanya beberapa responden yang lebih tua sehingga menarik rata-rata ke kanan.
- Sebagian besar responden berada pada rentang usia muda hingga dewasa awal.
- Tidak terdapat nilai ekstrem yang terlalu mencolok.
Kesimpulan: Mayoritas pelanggan merupakan usia produktif sehingga potensi keterlibatan terhadap layanan masih tinggi.
4.2 Total Purchase
# Bersihkan Environment dulu biar tidak error
rm(list = ls())
# Library
library(readr)
library(dplyr)
library(plotly)
# Load Data
df <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Function: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
x <- .data[[col_name]]
x <- x[!is.na(x)]
mean_val <- mean(x)
median_val <- median(x)
mode_val <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
dens <- density(x)
hist_cal <- hist(x, plot = FALSE)
scale_factor <- max(hist_cal$counts) / max(dens$y)
plot_ly() %>%
# Histogram
add_histogram(
x = x, nbinsx = 15, opacity = 0.55,
marker = list(color = "#6FB7FF"),
name = "Histogram",
showlegend = show_legend
) %>%
# Kurva Density
add_lines(
x = dens$x, y = dens$y * scale_factor,
name = "Density Curve",
line = list(width = 3, color = "#0B3C5D"),
showlegend = show_legend
) %>%
# Garis Rata-rata
add_segments(
x = mean_val, xend = mean_val,
y = 0, yend = max(hist_cal$counts),
name = "Mean",
line = list(color = "red", width = 3),
showlegend = show_legend
) %>%
# Garis Median
add_segments(
x = median_val, xend = median_val,
y = 0, yend = max(hist_cal$counts),
name = "Median",
line = list(color = "green", width = 3, dash = "dash"),
showlegend = show_legend
) %>%
# Garis Modus
add_segments(
x = mode_val, xend = mode_val,
y = 0, yend = max(hist_cal$counts),
name = "Mode",
line = list(color = "blue", width = 3, dash = "dot"),
showlegend = show_legend
) %>%
# Layout Title and Axis Label
layout(
title = list(
text = paste("<b>Distribusi", col_name, "</b>"),
x = 0.5, xanchor = "center",
font = list(size = 20)
),
xaxis = list(title = col_name),
yaxis = list(title = "Frequency"),
legend = list(orientation = "h", y = -0.2),
margin = list(t = 80, b = 70)
)
}
create_hist_plot(df, "TotalPurchase", TRUE)Interpretasi:
- Distribusi tampak skewed ke kanan, karena banyak pelanggan memiliki total pembelian rendah, dan sedikit yang melakukan pembelian tinggi.
- Mean jauh lebih besar daripada Median dan Mode, mempertegas adanya pelanggan dengan pembelian sangat besar (outliers).
- Kebanyakan pelanggan belanja dalam jumlah yang tidak terlalu besar.
Kesimpulan: Pelanggan high-spender jumlahnya sedikit tetapi berpengaruh besar terhadap rata-rata revenue. Perlu strategi retensi untuk segmen ini.
4.3 Number Of Visit
# Bersihkan Environment dulu biar tidak error
rm(list = ls())
# Library
library(readr)
library(dplyr)
library(plotly)
# Load Data
df <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Function: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
x <- .data[[col_name]]
x <- x[!is.na(x)]
mean_val <- mean(x)
median_val <- median(x)
mode_val <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
dens <- density(x)
hist_cal <- hist(x, plot = FALSE)
scale_factor <- max(hist_cal$counts) / max(dens$y)
plot_ly() %>%
# Histogram
add_histogram(
x = x, nbinsx = 15, opacity = 0.55,
marker = list(color = "#6FB7FF"),
name = "Histogram",
showlegend = show_legend
) %>%
# Kurva Density
add_lines(
x = dens$x, y = dens$y * scale_factor,
name = "Density Curve",
line = list(width = 3, color = "#0B3C5D"),
showlegend = show_legend
) %>%
# Garis Rata-rata
add_segments(
x = mean_val, xend = mean_val,
y = 0, yend = max(hist_cal$counts),
name = "Mean",
line = list(color = "red", width = 3),
showlegend = show_legend
) %>%
# Garis Median
add_segments(
x = median_val, xend = median_val,
y = 0, yend = max(hist_cal$counts),
name = "Median",
line = list(color = "green", width = 3, dash = "dash"),
showlegend = show_legend
) %>%
# Garis Modus
add_segments(
x = mode_val, xend = mode_val,
y = 0, yend = max(hist_cal$counts),
name = "Mode",
line = list(color = "blue", width = 3, dash = "dot"),
showlegend = show_legend
) %>%
# Layout Judul and Axis Label
layout(
title = list(
text = paste("<b>Distribusi", col_name, "</b>"),
x = 0.5, xanchor = "center",
font = list(size = 20)
),
xaxis = list(title = col_name),
yaxis = list(title = "Frequency"),
legend = list(orientation = "h", y = -0.2),
margin = list(t = 80, b = 70)
)
}
create_hist_plot(df, "NumberOfVisits", TRUE)Interpretasi:
- Distribusi sangat miring ke kanan (high positive skewness).
- Mayoritas pelanggan hanya melakukan kunjungan sedikit, sementara ada segelintir yang sangat sering berkunjung.
- Mode berada pada nilai kunjungan yang rendah, frequent customers sedikit.
Kesimpulan: Loyalitas pelanggan masih rendah dan perlu strategi peningkatan kunjungan berulang seperti membership atau promo.
4.4 Feedback Score
# Bersihkan Environment dulu biar tidak error
rm(list = ls())
# Library
library(readr)
library(dplyr)
library(plotly)
# Load Data
df <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Function: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
x <- .data[[col_name]]
x <- x[!is.na(x)]
mean_val <- mean(x)
median_val <- median(x)
mode_val <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
dens <- density(x)
hist_cal <- hist(x, plot = FALSE)
scale_factor <- max(hist_cal$counts) / max(dens$y)
plot_ly() %>%
# Histogram
add_histogram(
x = x, nbinsx = 15, opacity = 0.55,
marker = list(color = "#6FB7FF"),
name = "Histogram",
showlegend = show_legend
) %>%
# Kurva Density
add_lines(
x = dens$x, y = dens$y * scale_factor,
name = "Density Curve",
line = list(width = 3, color = "#0B3C5D"),
showlegend = show_legend
) %>%
# Garis Rata-rata
add_segments(
x = mean_val, xend = mean_val,
y = 0, yend = max(hist_cal$counts),
name = "Mean",
line = list(color = "red", width = 3),
showlegend = show_legend
) %>%
# Garis Median
add_segments(
x = median_val, xend = median_val,
y = 0, yend = max(hist_cal$counts),
name = "Median",
line = list(color = "green", width = 3, dash = "dash"),
showlegend = show_legend
) %>%
# Garis Modus
add_segments(
x = mode_val, xend = mode_val,
y = 0, yend = max(hist_cal$counts),
name = "Mode",
line = list(color = "blue", width = 3, dash = "dot"),
showlegend = show_legend
) %>%
# Layout Title and Axis Label
layout(
title = list(
text = paste("<b>Distribusi", col_name, "</b>"),
x = 0.5, xanchor = "center",
font = list(size = 20)
),
xaxis = list(title = col_name),
yaxis = list(title = "Frequency"),
legend = list(orientation = "h", y = -0.2),
margin = list(t = 80, b = 70)
)
}
create_hist_plot(df, "FeedbackScore", TRUE)Interpretasi:
- Distribusi condong ke kiri (negatively skewed).
- Artinya sebagian besar pelanggan memberikan nilai tinggi, seperti skor 4–5.
- Mode berada di skor tertinggi, pelanggan puas dengan layanan.
- Mean dan median keduanya tinggi dan dekat, menandakan konsistensi persepsi positif.
Kesimpulan: Customer experience berjalan baik dan tingkat kepuasan tinggi.
5. Analisis Perbandingan Variabel, Visualisasi & Interpretasi
5.1 Total Purchase vs Product Category
Grafik ini menampilkan distribusi Total Purchase berdasarkan Product Category, dengan garis Mean, Median, dan Mode sebagai pembanding nilai pusat secara keseluruhan.
# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
# Load data
data <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Pilih variabel
df <- data %>% select(ProductCategory, TotalPurchase)
# Global stats
global_mean <- mean(df$TotalPurchase, na.rm = TRUE)
global_median <- median(df$TotalPurchase, na.rm = TRUE)
global_mode <- as.numeric(names(sort(table(df$TotalPurchase), decreasing = TRUE)[1]))
line_data <- data.frame(
Type = c("Mean", "Median", "Mode"),
y = c(global_mean, global_median, global_mode)
)
# ggplot
p <- ggplot(df, aes(x = ProductCategory, y = TotalPurchase)) +
geom_boxplot(aes(fill = ProductCategory), alpha = 0.6, outlier.color = "red", show.legend = FALSE) +
geom_hline(data = line_data, aes(yintercept = y, linetype = Type, color = Type), size = 1.2) +
scale_color_manual(values = c("Mean" = "green", "Median" = "black", "Mode" = "orange")) +
scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
labs(
title = "Boxplot of Total Purchases by Product Category",
subtitle = "Hanya garis Mean, Median, Mode yang ditampilkan di legend",
x = "Product Category",
y = "Total Purchases",
color = "Measure",
linetype = "Measure"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12)
)
# Convert ke plotly
pp <- ggplotly(p)
# Sembunyikan legend boxplot, hanya tampil garis
for (i in seq_along(pp$x$data)) {
if (pp$x$data[[i]]$type %in% c("box", "scatter")) {
if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
pp$x$data[[i]]$showlegend <- FALSE
}
}
}
# Ganti nama legend garis
pp$x$data[[length(pp$x$data)-2]]$name <- "Mean"
pp$x$data[[length(pp$x$data)-1]]$name <- "Median"
pp$x$data[[length(pp$x$data)]]$name <- "Mode"
ppInterpretasi
- Median tiap kategori berbeda-beda, dan kebanyakan berada di bawah median global, mayoritas pelanggan berbelanja dalam jumlah relatif kecil
- Box (IQR) Electronics & Sports lebih tinggi dan lebar, pembelian di kategori ini lebih besar dan bervariasi dibanding kategori lain
- Books & Clothing punya persebaran rendah, pembelian kecil dan relatif konsisten
- Outlier terutama muncul pada Electronics & Sports, ada beberapa
pelanggan dengan pembelian sangat besar, sehingga:
- Mean global (garis hijau) tertarik naik
- Distribusi menjadi right-skewed (lebih banyak pembelian kecil, sedikit yang besar)
- Mode global (garis oranye) berada di bagian bawah grafik, nilai pembelian yang paling sering adalah pembelian kecil
5.2 Feedback Score vs Product Category
Perbandingan ini bertujuan untuk memahami bagaimana tingkat kepuasan pelanggan (Feedback Score) untuk setiap kategori produk (Product Category).
# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
# Load data
data <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
# Pilih variabel yang dipakai
df <- data %>% select(ProductCategory, FeedbackScore)
# Global stats
global_mean <- mean(df$FeedbackScore, na.rm = TRUE)
global_median <- median(df$FeedbackScore, na.rm = TRUE)
global_mode <- as.numeric(names(sort(table(df$FeedbackScore), decreasing = TRUE)[1]))
line_data <- data.frame(
Type = c("Mean", "Median", "Mode"),
y = c(global_mean, global_median, global_mode)
)
# ggplot
p <- ggplot(df, aes(x = ProductCategory, y = FeedbackScore)) +
geom_boxplot(aes(fill = ProductCategory), alpha = 0.6, outlier.color = "red", show.legend = FALSE) +
geom_hline(data = line_data, aes(yintercept = y, linetype = Type, color = Type), size = 1.2) +
scale_color_manual(values = c("Mean" = "green", "Median" = "black", "Mode" = "orange")) +
scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
labs(
title = "Boxplot of FeedbackScore by ProductCategory",
subtitle = "Hanya garis Mean, Median, Mode ditampilkan di legend",
x = "ProductCategory",
y = "FeedbackScore",
color = "Measure",
linetype = "Measure"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12)
)
# Convert ke Plotly
pp <- ggplotly(p)
# Sembunyikan legend boxplot, hanya tampil garis
for (i in seq_along(pp$x$data)) {
if (pp$x$data[[i]]$type %in% c("box", "scatter")) {
if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
pp$x$data[[i]]$showlegend <- FALSE
}
}
}
# Ganti nama legend garis
pp$x$data[[length(pp$x$data)-2]]$name <- "Mean"
pp$x$data[[length(pp$x$data)-1]]$name <- "Median"
pp$x$data[[length(pp$x$data)]]$name <- "Mode"
ppInterpretasi
- Median skor tiap kategori = sama (tepat di angka 3), mayoritas pelanggan di semua kategori memberi penilaian sedang
- Mean global (garis hijau) sedikit di bawah median global, menunjukkan kecenderungan sedikit left-skewed (ada beberapa penilaian rendah)
- Mode global (garis oranye) berada pada skor 1, skor paling sering diberikan adalah nilai terendah, meskipun bukan mayoritas
- IQR (box) relatif sama di semua kategori, persebaran nilai umpan balik konsisten
- Whisker mencapai skor 1 hingga 5, semua kategori punya respon dari sangat buruk hingga sangat baik
- Outlier tidak terlalu mencolok, pola penilaian cukup stabil tanpa nilai ekstrem yang dominan
5.3 Number Of Visits vs Gender
Grafik ini menunjukkan perbandingan jumlah kunjungan pelanggan (Number Of Visits) berdasarkan jenis kelamin (Gender) dengan tambahan garis Mean, Median, dan Mode sebagai indikator ukuran pemusatan data.
# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
# Load data
data <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
df <- data %>% select(Gender, NumberOfVisits)
# Fix label gender biar rapi (optional)
df$Gender <- factor(df$Gender, levels = c("F","M"), labels = c("Female","Male"))
# Global stats
global_mean <- mean(df$NumberOfVisits, na.rm = TRUE)
global_median <- median(df$NumberOfVisits, na.rm = TRUE)
global_mode <- as.numeric(names(sort(table(df$NumberOfVisits), decreasing = TRUE)[1]))
line_data <- data.frame(
Type = c("Mean", "Median", "Mode"),
y = c(global_mean, global_median, global_mode)
)
# ggplot
p <- ggplot(df, aes(x = Gender, y = NumberOfVisits)) +
geom_boxplot(aes(fill = Gender), alpha = 0.6, outlier.color = "red", show.legend = FALSE) +
geom_hline(data = line_data, aes(yintercept = y, linetype = Type, color = Type), size = 1.2) +
scale_fill_manual(values = c("Female" = "pink", "Male" = "lightblue")) +
scale_color_manual(values = c("Mean" = "green", "Median" = "black", "Mode" = "orange")) +
scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
labs(
title = "Boxplot of NumberOfVisits by Gender",
subtitle = "Hanya garis Mean, Median, Mode ditampilkan di legend",
x = "Gender",
y = "NumberOfVisits",
color = "Measure",
linetype = "Measure"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12)
)
# Convert ke plotly
pp <- ggplotly(p)
# FIX LEGEND
for (i in seq_along(pp$x$data)) {
# Sembunyikan boxplot dari legend
if (pp$x$data[[i]]$type %in% c("box", "scatter")) {
if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
pp$x$data[[i]]$showlegend <- FALSE
}
}
}
# ganti nama 3 baris terakhir dalam legend ke Mean, Median, Modus
pp$x$data[[length(pp$x$data)-2]]$name <- "Mean"
pp$x$data[[length(pp$x$data)-1]]$name <- "Median"
pp$x$data[[length(pp$x$data)]]$name <- "Mode"
ppInterpretasi
- Median Female dan Male berada di angka yang sama, frekuensi kunjungan rata-rata kedua gender setara
- Mean global (garis hijau) berada sedikit di atas median, menandakan masih ada beberapa kunjungan lebih tinggi yang menaikkan rata-rata
- Mode global (garis oranye) juga dekat dengan median, angka kunjungan yang paling sering terjadi hampir sama dengan titik tengah distribusi
- Sebaran data (IQR) sedikit lebih besar pada Male, menunjukkan variasi kunjungan pria lebih beragam
- Whisker mencapai nilai cukup tinggi pada kedua gender, ada pelanggan tertentu yang melakukan kunjungan lebih sering
- Tidak ada outlier mencolok, pola kunjungan konsisten dan tidak ada nilai ekstrem yang signifikan
5.4 Number Of Visits vs Store Location
Grafik ini membandingkan jumlah Number of Visits pada setiap Store Location.
# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
# Load data
data <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
df <- data %>% select(StoreLocation, NumberOfVisits)
# Global stats
global_mean <- mean(df$NumberOfVisits, na.rm = TRUE)
global_median <- median(df$NumberOfVisits, na.rm = TRUE)
global_mode <- as.numeric(names(sort(table(df$NumberOfVisits), decreasing = TRUE)[1]))
line_data <- data.frame(
Type = c("Mean", "Median", "Mode"),
y = c(global_mean, global_median, global_mode)
)
# ggplot
p <- ggplot(df, aes(x = StoreLocation, y = NumberOfVisits)) +
geom_boxplot(aes(fill = StoreLocation), alpha = 0.6, outlier.color = "red", show.legend = FALSE) +
geom_hline(data = line_data, aes(yintercept = y, linetype = Type, color = Type), size = 1.2) +
scale_color_manual(values = c("Mean" = "green", "Median" = "black", "Mode" = "orange")) +
scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
labs(
title = "Boxplot of NumberOfVisits by StoreLocation",
subtitle = "Hanya garis Mean, Median, Mode yang ditampilkan di legend",
x = "StoreLocation",
y = "NumberOfVisits",
color = "Measure",
linetype = "Measure"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12)
)
# Convert ke plotly
pp <- ggplotly(p)
# FIX LEGEND
for (i in seq_along(pp$x$data)) {
# sembunyikan semua trace boxplot dari legend
if (pp$x$data[[i]]$type %in% c("box", "scatter")) {
if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
pp$x$data[[i]]$showlegend <- FALSE
}
}
}
# Ganti nama legend baris
pp$x$data[[length(pp$x$data)-2]]$name <- "Mean"
pp$x$data[[length(pp$x$data)-1]]$name <- "Median"
pp$x$data[[length(pp$x$data)]]$name <- "Mode"
ppInterpretasi
- Median tiap lokasi (East, North, South, West) hampir sama, tidak ada perbedaan signifikan dalam rata-rata pelanggan berkunjung antar lokasi
- North & West memiliki IQR lebih besar, variasi kunjungan lebih tinggi, ada pelanggan yang jauh lebih sering datang
- East punya sebaran lebih kecil, perilaku kunjungan lebih konsisten
- Whisker North & West mencapai nilai tertinggi, potensi pelanggan loyal lebih banyak di dua lokasi tersebut
- Garis Mean (hijau), Median (hitam), dan Mode (oranye) saling berdekatan, distribusi kunjungan relatif simetris dan tidak ada bias kuat ke nilai ekstrem
- Tidak tampak outlier ekstrem, pola kunjungan masih wajar dan stabil di semua lokasi
5.5 Age vs Product Category
Grafik ini membandingkan Age terhadap setiap Product Category.
# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
# Load Data
data <- read_csv("4 Central Tendency – Introduction to Statistics.csv")
df <- data %>% select(ProductCategory, Age)
# Global Central Tendency
global_mean <- mean(df$Age, na.rm = TRUE)
global_median <- median(df$Age, na.rm = TRUE)
global_mode <- as.numeric(names(sort(table(df$Age), decreasing = TRUE)[1]))
line_data <- data.frame(
Type = c("Mean", "Median", "Mode"),
y = c(global_mean, global_median, global_mode)
)
# ggplot Boxplot
p <- ggplot(df, aes(x = ProductCategory, y = Age)) +
geom_boxplot(aes(fill = ProductCategory), alpha = 0.6, outlier.color = "red", show.legend = FALSE) +
# Central lines
geom_hline(data = line_data, aes(yintercept = y, linetype = Type, color = Type), size = 1.2) +
scale_color_manual(values = c("Mean" = "green", "Median" = "black", "Mode" = "orange")) +
scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
labs(
title = "Boxplot of Age by ProductCategory",
subtitle = "Menampilkan garis Mean, Median, Mode sebagai referensi global",
x = "ProductCategory",
y = "Age",
color = "Measure",
linetype = "Measure"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12)
)
# Convert ke Plotly
pp <- ggplotly(p)
# Sembunyikan boxplot dari legend
for (i in seq_along(pp$x$data)) {
if (pp$x$data[[i]]$type %in% c("box","scatter")) {
if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
pp$x$data[[i]]$showlegend <- FALSE
}
}
}
# Ganti nama legend agar rapi (remove angka 1)
trace_count <- length(pp$x$data)
pp$x$data[[trace_count-2]]$name <- "Mean"
pp$x$data[[trace_count-1]]$name <- "Median"
pp$x$data[[trace_count]]$name <- "Mode"
ppInterpretasi
- Median usia tiap kategori relatif mirip, tidak ada kategori dengan gap usia pelanggan yang terlalu mencolok
- Electronics & Sports memiliki median sedikit lebih tinggi → lebih banyak pelanggan usia dewasa membeli kategori ini
- Home & Clothing punya sebaran usia lebih luas, menjangkau segmen usia yang lebih beragam
- Books punya median terendah, lebih diminati pelanggan usia lebih muda
- Whisker mencapai usia 60–70 pada semua kategori, tetap ada pelanggan lebih senior yang berbelanja semua kategori
- Mean (hijau) lebih tinggi dari median (hitam) di semua kategori, distribusi sedikit condong ke pelanggan lebih tua
- Mode (oranye) berada di bawah median, usia muda muncul lebih sering dalam data
- Tidak ada outlier ekstrem, data usia konsisten dan stabil