Dokumen ini menyajikan dua visualisasi inti — line plot deret waktu harian dan smoothing (LOESS + Moving Average) — beserta interpretasi mendalam tentang pola, tren, dan siklus musiman yang tertangkap dari data penyewaan sepeda 2011 hingga 2012.
library(tidyverse)
library(lubridate)
library(zoo)
library(scales)
library(knitr)
library(kableExtra)# Load dataset
bike_data <- read.csv("C:/Users/yolan/Downloads/bike_sharing_dataset_by-day.csv")
# Parsing & feature engineering
bike_data <- bike_data %>%
mutate(
dteday = as.Date(dteday),
yr_label = factor(yr, labels = c("2011", "2012")),
season_label = factor(season, levels = 1:4,
labels = c("Spring","Summer","Fall","Winter")),
mnth_label = factor(mnth, levels = 1:12, labels = month.abb),
ma7 = rollmean(cnt, 7, fill = NA, align = "right"),
ma30 = rollmean(cnt, 30, fill = NA, align = "right"),
ma60 = rollmean(cnt, 60, fill = NA, align = "right")
)
cat("Periode :", format(min(bike_data$dteday)), "s.d.",
format(max(bike_data$dteday)), "\n")## Periode : 2011-01-01 s.d. 2012-12-31
## Baris : 731 | Kolom: 22
## Total cnt: 3,292,679
bike_data %>%
select(dteday, season_label, yr_label, temp, hum,
casual, registered, cnt, ma7, ma30) %>%
head(10) %>%
kable(
caption = "Tabel 1 — 10 Observasi Pertama (dengan kolom Moving Average)",
digits = 3,
col.names = c("Tanggal","Musim","Tahun","Suhu","Kelembaban",
"Kasual","Terdaftar","Total","MA-7","MA-30"),
format.args = list(big.mark = ",")
) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = TRUE, font_size = 13) %>%
column_spec(8, bold = TRUE, color = "#00dcff") %>%
row_spec(0, bold = TRUE, color = "#2d5070")| Tanggal | Musim | Tahun | Suhu | Kelembaban | Kasual | Terdaftar | Total | MA-7 | MA-30 |
|---|---|---|---|---|---|---|---|---|---|
| 2011-01-01 | Spring | 2011 | 0.344 | 0.806 | 331 | 654 | 985 | NA | NA |
| 2011-01-02 | Spring | 2011 | 0.363 | 0.696 | 131 | 670 | 801 | NA | NA |
| 2011-01-03 | Spring | 2011 | 0.196 | 0.437 | 120 | 1,229 | 1,349 | NA | NA |
| 2011-01-04 | Spring | 2011 | 0.200 | 0.590 | 108 | 1,454 | 1,562 | NA | NA |
| 2011-01-05 | Spring | 2011 | 0.227 | 0.437 | 82 | 1,518 | 1,600 | NA | NA |
| 2011-01-06 | Spring | 2011 | 0.204 | 0.518 | 88 | 1,518 | 1,606 | NA | NA |
| 2011-01-07 | Spring | 2011 | 0.197 | 0.499 | 148 | 1,362 | 1,510 | 1,344.714 | NA |
| 2011-01-08 | Spring | 2011 | 0.165 | 0.536 | 68 | 891 | 959 | 1,341.000 | NA |
| 2011-01-09 | Spring | 2011 | 0.138 | 0.434 | 54 | 768 | 822 | 1,344.000 | NA |
| 2011-01-10 | Spring | 2011 | 0.151 | 0.483 | 41 | 1,280 | 1,321 | 1,340.000 | NA |
Line plot ini menampilkan seluruh 731 titik observasi harian dari Januari 2011 hingga Desember 2012. Setiap titik pada garis mewakili total penyewaan sepeda dalam satu hari, sehingga fluktuasi jangka pendek maupun pola jangka panjang terlihat bersamaan dalam satu tampilan.
cb <- "#04090f"
cp <- "#08111f"
cg <- "#0b1e36"
ct <- "#5a88aa"
craw <- "#3ab8d8"
peak <- bike_data %>% slice_max(cnt, n = 1)
low <- bike_data %>% slice_min(cnt, n = 1)
ggplot(bike_data, aes(x = dteday, y = cnt)) +
geom_area(fill = craw, alpha = 0.07) +
geom_line(color = craw, alpha = 0.55, linewidth = 0.5) +
geom_point(data = peak, color = "#ff6b35", size = 3.5, shape = 18) +
geom_point(data = low, color = "#ff3e9d", size = 3.5, shape = 18) +
annotate("text",
x = peak$dteday - 18, y = peak$cnt + 320,
label = paste0("Puncak: ", format(peak$cnt, big.mark = ",")),
color = "#ff6b35", family = "mono", size = 3.2, hjust = 1) +
annotate("segment",
x = peak$dteday - 16, xend = peak$dteday - 2,
y = peak$cnt + 230, yend = peak$cnt + 60,
color = "#ff6b35", linewidth = 0.4,
arrow = arrow(length = unit(4,"pt"), type = "closed")) +
annotate("text",
x = low$dteday + 28, y = low$cnt - 300,
label = paste0("Terendah: ", format(low$cnt, big.mark = ",")),
color = "#ff3e9d", family = "mono", size = 3.2, hjust = 0) +
geom_vline(xintercept = as.numeric(as.Date("2012-01-01")),
color = "#1e3a55", linetype = "dashed", linewidth = 0.7) +
annotate("text", x = as.Date("2012-01-12"), y = 8600,
label = "Masuk 2012", color = "#2d5070",
family = "mono", size = 3, hjust = 0) +
scale_x_date(date_breaks = "2 months", date_labels = "%b\n%Y",
expand = expansion(mult = 0.01)) +
scale_y_continuous(labels = comma, breaks = seq(0, 9000, 1500),
expand = expansion(mult = c(0.02, 0.09))) +
labs(
title = "Total Penyewaan Sepeda Harian — Januari 2011 s.d. Desember 2012",
subtitle = "Setiap titik pada garis = 1 hari observasi | 731 data point",
x = NULL, y = "Jumlah Penyewaan (unit/hari)"
) +
theme_minimal(base_family = "mono") +
theme(
plot.background = element_rect(fill = cb, color = NA),
panel.background = element_rect(fill = cp, color = NA),
panel.grid.major = element_line(color = cg, linewidth = 0.45),
panel.grid.minor = element_blank(),
plot.title = element_text(color = "#ddeeff", size = 14,
face = "bold", margin = margin(b = 5)),
plot.subtitle = element_text(color = ct, size = 11, margin = margin(b = 18)),
axis.text = element_text(color = ct, size = 10),
axis.title.y = element_text(color = ct, size = 11, margin = margin(r = 10)),
plot.margin = margin(22, 22, 16, 22)
)Smoothing diterapkan untuk menekan noise harian dan memunculkan struktur tersembunyi dalam data. Tiga lapis smoothing digunakan dengan fungsi berbeda: MA-7 memperlihatkan dinamika mingguan, MA-30 mengungkap siklus bulanan, dan LOESS menangkap tren keseluruhan secara fleksibel tanpa asumsi bentuk kurva tertentu.
cma7 <- "#ff3e9d"
cma3 <- "#a8ff3e"
clos <- "#ff6b35"
ggplot(bike_data, aes(x = dteday, y = cnt)) +
geom_line(color = craw, alpha = 0.16, linewidth = 0.45) +
geom_smooth(method = "loess", span = 0.28,
color = clos, fill = clos, alpha = 0.13,
linewidth = 2.2, se = TRUE) +
geom_line(aes(y = ma30), color = cma3, linewidth = 1.4, na.rm = TRUE) +
geom_line(aes(y = ma7), color = cma7, linewidth = 0.85, alpha = 0.85, na.rm = TRUE) +
geom_vline(xintercept = as.numeric(as.Date("2012-01-01")),
color = "#1e3a55", linetype = "dashed", linewidth = 0.7) +
annotate("segment",
x = as.Date("2011-01-05"), xend = as.Date("2011-02-08"),
y = c(500, 850, 1200), yend = c(500, 850, 1200),
color = c(cma7, cma3, clos), linewidth = c(0.85, 1.4, 2.2)) +
annotate("text",
x = as.Date("2011-02-18"),
y = c(500, 850, 1200),
label = c("MA-7 — Pola Mingguan",
"MA-30 — Siklus Bulanan",
"LOESS — Tren Global"),
color = c(cma7, cma3, clos),
hjust = 0, family = "mono", size = 3) +
scale_x_date(date_breaks = "2 months", date_labels = "%b\n%Y",
expand = expansion(mult = 0.01)) +
scale_y_continuous(labels = comma, breaks = seq(0, 9000, 1500),
expand = expansion(mult = c(0.02, 0.09))) +
labs(
title = "Smoothing Time Series — LOESS · MA-30 · MA-7",
subtitle = "Noise harian diredam; tren dan siklus musiman terlihat jelas",
x = NULL, y = "Jumlah Penyewaan (unit/hari)"
) +
theme_minimal(base_family = "mono") +
theme(
plot.background = element_rect(fill = cb, color = NA),
panel.background = element_rect(fill = cp, color = NA),
panel.grid.major = element_line(color = cg, linewidth = 0.45),
panel.grid.minor = element_blank(),
plot.title = element_text(color = "#ddeeff", size = 14,
face = "bold", margin = margin(b = 5)),
plot.subtitle = element_text(color = ct, size = 11, margin = margin(b = 18)),
axis.text = element_text(color = ct, size = 10),
axis.title.y = element_text(color = ct, size = 11, margin = margin(r = 10)),
plot.margin = margin(22, 22, 16, 22)
)bike_data %>%
group_by(Tahun = yr_label, Musim = season_label) %>%
summarise(
`Rata-rata/Hari` = round(mean(cnt)),
`Minimum` = min(cnt),
`Maksimum` = max(cnt),
`Std. Deviasi` = round(sd(cnt)),
.groups = "drop"
) %>%
kable(
caption = "Tabel 2 — Statistik Penyewaan per Musim dan Tahun",
format.args = list(big.mark = ","),
align = c("c","l","r","r","r","r")
) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = TRUE, font_size = 13) %>%
column_spec(3, bold = TRUE, color = "#00dcff") %>%
column_spec(6, color = "#ff6b35") %>%
row_spec(0, bold = TRUE, color = "#2d5070")| Tahun | Musim | Rata-rata/Hari | Minimum | Maksimum | Std. Deviasi |
|---|---|---|---|---|---|
| 2011 | Spring | 1,667 | 431 | 3,239 | 614 |
| 2011 | Summer | 3,775 | 795 | 5,805 | 1,139 |
| 2011 | Fall | 4,464 | 1,115 | 6,043 | 798 |
| 2011 | Winter | 3,664 | 627 | 5,511 | 983 |
| 2012 | Spring | 3,531 | 441 | 7,836 | 1,341 |
| 2012 | Summer | 6,209 | 1,027 | 8,362 | 1,221 |
| 2012 | Fall | 6,824 | 4,073 | 8,714 | 913 |
| 2012 | Winter | 5,792 | 22 | 8,555 | 1,599 |