Memuat Package yang digunakan
library(tidyverse)
library(modelr)
options(na.action = na.warn)
library(nycflights13)
library(lubridate)
library(splines)
library(MASS)
Dataset
flights
## # A tibble: 336,776 x 19
## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
## <int> <int> <int> <int> <int> <dbl> <int> <int>
## 1 2013 1 1 517 515 2 830 819
## 2 2013 1 1 533 529 4 850 830
## 3 2013 1 1 542 540 2 923 850
## 4 2013 1 1 544 545 -1 1004 1022
## 5 2013 1 1 554 600 -6 812 837
## 6 2013 1 1 554 558 -4 740 728
## 7 2013 1 1 555 600 -5 913 854
## 8 2013 1 1 557 600 -3 709 723
## 9 2013 1 1 557 600 -3 838 846
## 10 2013 1 1 558 600 -2 753 745
## # ... with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
Banyaknya penerbangan berdasarkan waktu (per hari).
daily <- flights %>%
mutate(date = make_date(year, month, day)) %>%
group_by(date) %>%
summarize(n = n())
daily
## # A tibble: 365 x 2
## date n
## <date> <int>
## 1 2013-01-01 842
## 2 2013-01-02 943
## 3 2013-01-03 914
## 4 2013-01-04 915
## 5 2013-01-05 720
## 6 2013-01-06 832
## 7 2013-01-07 933
## 8 2013-01-08 899
## 9 2013-01-09 902
## 10 2013-01-10 932
## # ... with 355 more rows
Visualisasi data banyaknya penerbangan berdasarkan waktu.
ggplot(daily, aes(date, n)) +
geom_line()
Pada grafik diatas terlihat terdapat efek sebuah hari dalam seminggu yang sangat kuat dan mendominasi sehingga grafik berbentuk pola yang curam.
Distribusi penerbangan berdasarkan hari dalam seminggu.
daily <- daily %>%
mutate(wday = wday(date, label = TRUE)) %>%
mutate(month=month(date, label = T))
ggplot(daily, aes(wday, n)) +
geom_boxplot()
Pada grafik diatas terlihat bahwa pada weekend terdapat lebih sedikit penerbangan, hal ini karena banyak perjalan adalah untuk bisnis. Efek tersebut terlihat jelas pada hari sabtu.
Untuk menghilangkan efek kuat tersebut adalah menggunkan model tersebut.
Model
mod <- lm(n ~ wday, data = daily)
mod
##
## Call:
## lm(formula = n ~ wday, data = daily)
##
## Coefficients:
## (Intercept) wday.L wday.Q wday.C wday^4 wday^5
## 922.595 -83.322 -155.111 -62.834 -80.126 -4.967
## wday^6
## -16.934
Prediksi berdasarkan model.
grid <- daily %>% data_grid(wday) %>%
add_predictions(mod, "n")
grid
## # A tibble: 7 x 2
## wday n
## <ord> <dbl>
## 1 Sun 891.
## 2 Mon 975.
## 3 Tue 951.
## 4 Wed 963.
## 5 Thu 966.
## 6 Fri 967.
## 7 Sat 745.
Distribusi penerbangan berdasarkan hari daam seminggu dengan prediksinya.
ggplot(daily, aes(wday, n)) +
geom_boxplot() +
geom_point(data = grid, color = "red", size = 4)
Residual
daily <- daily %>%
add_residuals(mod)
daily
## # A tibble: 365 x 5
## date n wday month resid
## <date> <int> <ord> <ord> <dbl>
## 1 2013-01-01 842 Tue Jan -109.
## 2 2013-01-02 943 Wed Jan -19.7
## 3 2013-01-03 914 Thu Jan -51.8
## 4 2013-01-04 915 Fri Jan -52.5
## 5 2013-01-05 720 Sat Jan -24.6
## 6 2013-01-06 832 Sun Jan -59.5
## 7 2013-01-07 933 Mon Jan -41.8
## 8 2013-01-08 899 Tue Jan -52.4
## 9 2013-01-09 902 Wed Jan -60.7
## 10 2013-01-10 932 Thu Jan -33.8
## # ... with 355 more rows
Visualisasi dari residual
daily %>%
ggplot(aes(date, resid)) +
geom_ref_line(h = 0) +
geom_line()
Pada visualisasi diatas terlihat penyimpangan pada perkiraan banyaknya penerbangan.
Pada visualisasi tersebut juga berguna karena telah menghapus banyak efek dari hari dalam seminggu sebelumnya. Namun disini masih tersisa beberapa pola curam.
Pada model tersebut terlihat gagal pada juni, karena terlihat pola curam.
Agar mudah dilihat, graph dibuat untuk tiap-tiap hari dalam seminggu.
ggplot(daily, aes(date, resid, color = wday)) +
geom_ref_line(h = 0) +
geom_line()
Data dengan residual lebih atau kurang dari 100.
daily %>% filter(resid < -100 )
## # A tibble: 11 x 5
## date n wday month resid
## <date> <int> <ord> <ord> <dbl>
## 1 2013-01-01 842 Tue Jan -109.
## 2 2013-01-20 786 Sun Jan -105.
## 3 2013-05-26 729 Sun May -162.
## 4 2013-07-04 737 Thu Jul -229.
## 5 2013-07-05 822 Fri Jul -145.
## 6 2013-09-01 718 Sun Sep -173.
## 7 2013-11-28 634 Thu Nov -332.
## 8 2013-11-29 661 Fri Nov -306.
## 9 2013-12-24 761 Tue Dec -190.
## 10 2013-12-25 719 Wed Dec -244.
## 11 2013-12-31 776 Tue Dec -175.
daily %>% filter(resid > 100 )
## # A tibble: 1 x 5
## date n wday month resid
## <date> <int> <ord> <ord> <dbl>
## 1 2013-11-30 857 Sat Nov 112.
Dilihat dari data diatas penyimpangan yang terjadi pada visualisasi sebelumnya adalah karena hari-hari tersebut merupakan hari-hari besar atau hari libur.
Berikut trend menurut pola.
daily %>% ggplot(aes(date, resid)) +
geom_ref_line(h = 0) +
geom_line(color = "grey50") +
geom_smooth(se = FALSE, span = 0.20)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Pada grafik sebelumnya terlihat bahwa hari sabtu (warna kuning), terlihat pola musiman. Pada bulan juni - september jumlah penerbangan lebih besar dari prediksi (expected) dan pada bulan september - Januari jumlah penerbangan lebih kecil dari predeksi (expected).
Berikut visualisasi hari sabtu setiap bulannya
daily %>%
filter(wday == "Sat") %>%
ggplot(aes(date, n)) +
geom_point() +
geom_line() +
scale_x_date( NULL,
date_breaks = "1 month",
date_labels = "%b" )
Visualisasi hari sabtu berdasarkan three school term.
term <- function(date) {
cut(date,
breaks = ymd(20130101, 20130605, 20130825, 20140101),
labels = c("spring", "summer", "fall")
)
}
daily <- daily %>%
mutate(term = term(date))
daily %>%
filter(wday == "Sat") %>%
ggplot(aes(date, n, color = term)) +
geom_point(alpha = 1/3) +
geom_line() +
scale_x_date( NULL,
date_breaks = "1 month",
date_labels = "%b" )
Distribusi penerbangan berdasarkan hari daam seminggu berdasarkan three school term sebelumnya.
daily %>%
ggplot(aes(wday, n, color = term)) +
geom_boxplot()
Pada garfik diatas terlihat terdapat variasi(perbedaan) yang signifikan antara masing-masing term. Jadi disini dipisahkan pada hari dalam seminggu berdasarkan term.
Berikut perbandingan model sebelumnya dengan model yang diperbaiki dan juga visualisasinya.
mod1 <- lm(n ~ wday, data = daily)
mod2 <- lm(n ~ wday * term, data = daily)
mod1
##
## Call:
## lm(formula = n ~ wday, data = daily)
##
## Coefficients:
## (Intercept) wday.L wday.Q wday.C wday^4 wday^5
## 922.595 -83.322 -155.111 -62.834 -80.126 -4.967
## wday^6
## -16.934
mod2
##
## Call:
## lm(formula = n ~ wday * term, data = daily)
##
## Coefficients:
## (Intercept) wday.L wday.Q wday.C
## 912.8684 -71.4674 -161.0112 -65.6215
## wday^4 wday^5 wday^6 termsummer
## -82.0997 -1.3425 -12.4501 37.6922
## termfall wday.L:termsummer wday.Q:termsummer wday.C:termsummer
## 3.7598 -6.2215 26.4121 26.7451
## wday^4:termsummer wday^5:termsummer wday^6:termsummer wday.L:termfall
## 23.5933 -13.1343 -5.0026 -31.9048
## wday.Q:termfall wday.C:termfall wday^4:termfall wday^5:termfall
## -0.6959 -8.8349 -9.8570 -3.2107
## wday^6:termfall
## -8.2061
daily %>%
gather_residuals(without_term = mod1, with_term = mod2) %>%
ggplot(aes(date, resid, color = model)) +
geom_line(alpha = 0.75)
Distribusi penerbangan berdasarkan hari daam seminggu dengan prediksinya pada model yang telah diperbaiki.
grid <- daily %>%
data_grid(wday, term) %>%
add_predictions(mod2, "n")
ggplot(daily, aes(wday, n)) +
geom_boxplot() +
geom_point(data = grid, color = "red") +
facet_wrap(~ term)
Seharusnya hasil prediksi mendekati rata-rata. Pada visualisasi diatas terlihat prediksi jauh dari rata-rata. Hal ini dikarenakan oleh adanya outlier yang cukup banyak. Masalah outlier dapat diatasi dengan menggunakan M estimator atau menggunakan perintah rlm pada package MASS.
mod3 <- MASS::rlm(n ~ wday * term, data = daily)
mod3
## Call:
## rlm(formula = n ~ wday * term, data = daily)
## Converged in 17 iterations
##
## Coefficients:
## (Intercept) wday.L wday.Q wday.C
## 922.4857006 -79.3059001 -153.7810509 -67.7749553
## wday^4 wday^5 wday^6 termsummer
## -74.9294649 -6.4803220 -9.7257891 32.9796852
## termfall wday.L:termsummer wday.Q:termsummer wday.C:termsummer
## 1.9847024 9.5345903 12.3444851 17.0750064
## wday^4:termsummer wday^5:termsummer wday^6:termsummer wday.L:termfall
## 11.0812708 -3.5357217 0.3378038 -31.7324552
## wday.Q:termfall wday.C:termfall wday^4:termfall wday^5:termfall
## -33.1644078 -23.8270526 -22.5287983 -4.9156541
## wday^6:termfall
## -3.3798444
##
## Degrees of freedom: 365 total; 344 residual
## Scale estimate: 17.6
summary(mod3)
##
## Call: rlm(formula = n ~ wday * term, data = daily)
## Residuals:
## Min 1Q Median 3Q Max
## -347.537 -12.899 3.915 11.500 160.101
##
## Coefficients:
## Value Std. Error t value
## (Intercept) 922.4857 1.5914 579.6839
## wday.L -79.3059 4.2202 -18.7920
## wday.Q -153.7811 4.2136 -36.4961
## wday.C -67.7750 4.2081 -16.1056
## wday^4 -74.9295 4.2229 -17.7437
## wday^5 -6.4803 4.1961 -1.5444
## wday^6 -9.7258 4.2011 -2.3151
## termsummer 32.9797 2.7178 12.1349
## termfall 1.9847 2.3615 0.8404
## wday.L:termsummer 9.5346 7.2110 1.3222
## wday.Q:termsummer 12.3445 7.1875 1.7175
## wday.C:termsummer 17.0750 7.2040 2.3702
## wday^4:termsummer 11.0813 7.1885 1.5415
## wday^5:termsummer -3.5357 7.1969 -0.4913
## wday^6:termsummer 0.3378 7.1550 0.0472
## wday.L:termfall -31.7325 6.2480 -5.0788
## wday.Q:termfall -33.1644 6.2524 -5.3043
## wday.C:termfall -23.8271 6.2399 -3.8185
## wday^4:termfall -22.5288 6.2606 -3.5985
## wday^5:termfall -4.9157 6.2318 -0.7888
## wday^6:termfall -3.3798 6.2550 -0.5403
##
## Residual standard error: 17.58 on 344 degrees of freedom
grid2 <- daily %>%
data_grid(wday, term) %>%
add_predictions(mod3, "n")
ggplot(daily, aes(wday, n)) +
geom_boxplot() +
geom_point(data = grid2, color = "red") +
facet_wrap(~ term)+
labs(title = "Model Sesudah Diperbaiki")
ggplot(daily, aes(wday, n)) +
geom_boxplot() +
geom_point(data = grid, color = "red") +
facet_wrap(~ term)+
labs(title = "Model Sebelum Diperbaiki")
Visualisasi residual pada model yang telah diperbaiki.
daily <- daily %>%
add_residuals(mod3, "resid")
daily %>%
ggplot(aes(date, resid)) +
geom_hline(yintercept = 0, size = 2, color = "blue") +
geom_line()
Pada grafik diatas terlihat bahwa model berhasil menghilangkan pola hari dalam seminggu (Residual mendaki nol). Berikut perbandingan antara model menggunakan lm dan rlm.
daily %>%
gather_residuals(menggunakan_lm = mod2, menggunakan_rlm = mod3) %>%
ggplot(aes(date, resid, color = model)) +
geom_hline(yintercept = 0, size = 2, color = "blue") +
geom_line()
APABILA DIBUAT MENJADI SUATU FUNCTION
Untuk mencari model. Untuk function wday gunakan wday2 atau yang lain selain wday, karena function wday sudah ada di library lubridate/tidyverse.
daily <- flights %>%
mutate(date = make_date(year, month, day)) %>%
group_by(date) %>%
summarize(n = n())
## `summarise()` ungrouping output (override with `.groups` argument)
term <- function(date) {
cut(date,
breaks = ymd(20130101, 20130605, 20130825, 20140101),
labels = c("spring", "summer", "fall")
)
}
wday2 <- function(x) {
wday(x, label = TRUE)
}
mod4 <- rlm(n ~ wday2(date) * term(date), data = daily)
mod4
## Call:
## rlm(formula = n ~ wday2(date) * term(date), data = daily)
## Converged in 17 iterations
##
## Coefficients:
## (Intercept) wday2(date).L
## 922.4857006 -79.3059001
## wday2(date).Q wday2(date).C
## -153.7810509 -67.7749553
## wday2(date)^4 wday2(date)^5
## -74.9294649 -6.4803220
## wday2(date)^6 term(date)summer
## -9.7257891 32.9796852
## term(date)fall wday2(date).L:term(date)summer
## 1.9847024 9.5345903
## wday2(date).Q:term(date)summer wday2(date).C:term(date)summer
## 12.3444851 17.0750064
## wday2(date)^4:term(date)summer wday2(date)^5:term(date)summer
## 11.0812708 -3.5357217
## wday2(date)^6:term(date)summer wday2(date).L:term(date)fall
## 0.3378038 -31.7324552
## wday2(date).Q:term(date)fall wday2(date).C:term(date)fall
## -33.1644078 -23.8270526
## wday2(date)^4:term(date)fall wday2(date)^5:term(date)fall
## -22.5287983 -4.9156541
## wday2(date)^6:term(date)fall
## -3.3798444
##
## Degrees of freedom: 365 total; 344 residual
## Scale estimate: 17.6
Untuk memasukan variabel pada dataset gunakan function:
compute_vars <- function(data) {
data %>%
mutate( term = term(date),
wday = wday(date, label = TRUE)
)
}
daily<-compute_vars(daily)
daily
## # A tibble: 365 x 4
## date n term wday
## <date> <int> <fct> <ord>
## 1 2013-01-01 842 spring Tue
## 2 2013-01-02 943 spring Wed
## 3 2013-01-03 914 spring Thu
## 4 2013-01-04 915 spring Fri
## 5 2013-01-05 720 spring Sat
## 6 2013-01-06 832 spring Sun
## 7 2013-01-07 933 spring Mon
## 8 2013-01-08 899 spring Tue
## 9 2013-01-09 902 spring Wed
## 10 2013-01-10 932 spring Thu
## # ... with 355 more rows
Sebelumnya model diperbaiki dengan pengetahuan tentang three term school. Sebagai alternatif dapat digunakan natural spline agar pengetahuan kita dapat masuk dalam model secara explisit.
mod <- MASS::rlm(n ~ wday * ns(date, 5), data = daily)
mod
## Call:
## rlm(formula = n ~ wday * ns(date, 5), data = daily)
## Converged in 14 iterations
##
## Coefficients:
## (Intercept) wday.L wday.Q wday.C
## 839.1368183 -58.0966417 -177.5614443 -76.1745048
## wday^4 wday^5 wday^6 ns(date, 5)1
## -106.5456685 14.7851980 -18.4661221 90.3704238
## ns(date, 5)2 ns(date, 5)3 ns(date, 5)4 ns(date, 5)5
## 133.7193537 41.3816719 180.6645268 28.9177394
## wday.L:ns(date, 5)1 wday.Q:ns(date, 5)1 wday.C:ns(date, 5)1 wday^4:ns(date, 5)1
## -35.0804683 11.6485897 -6.8750934 23.7107143
## wday^5:ns(date, 5)1 wday^6:ns(date, 5)1 wday.L:ns(date, 5)2 wday.Q:ns(date, 5)2
## -21.0684733 6.6102716 19.8439518 66.9609288
## wday.C:ns(date, 5)2 wday^4:ns(date, 5)2 wday^5:ns(date, 5)2 wday^6:ns(date, 5)2
## 54.5911251 59.4655330 -21.2689663 8.7438786
## wday.L:ns(date, 5)3 wday.Q:ns(date, 5)3 wday.C:ns(date, 5)3 wday^4:ns(date, 5)3
## -104.5352071 -83.6926248 -77.0186820 -36.3447345
## wday^5:ns(date, 5)3 wday^6:ns(date, 5)3 wday.L:ns(date, 5)4 wday.Q:ns(date, 5)4
## -25.0391121 0.8459285 -29.5596025 58.6435656
## wday.C:ns(date, 5)4 wday^4:ns(date, 5)4 wday^5:ns(date, 5)4 wday^6:ns(date, 5)4
## 32.5922420 61.0040478 -41.3647943 13.1681565
## wday.L:ns(date, 5)5 wday.Q:ns(date, 5)5 wday.C:ns(date, 5)5 wday^4:ns(date, 5)5
## 39.3654330 59.7652461 39.0232787 22.0796539
## wday^5:ns(date, 5)5 wday^6:ns(date, 5)5
## 2.1498306 -4.9029910
##
## Degrees of freedom: 365 total; 323 residual
## Scale estimate: 10.7
daily %>%
data_grid(wday, date = seq_range(date, n = 13)) %>%
add_predictions(mod)%>%
ggplot(aes(date, pred, color = wday)) +
geom_line() +
geom_point()