Factor

Factor adalah salah satu tipe struktur data dalam R bersama dengan vector, list, matriks, dan dataframe. Factor adalah jenis struktur data satu dimensi yang khusus digunakan untuk menampung data tipe kategorikal. Kebiasaan ku hingga saat ini adalah langsung mengubah data tipe character menjadi factor karena kemudahan untuk manipulasinya.

Untuk dapat memanfaatkan fungsi factor secara optimal, kita akan menggunakan tool bernama forcats yang juga berada dalam package ‘tidyverse’

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.4     v dplyr   1.0.7
## v tidyr   1.1.4     v stringr 1.4.0
## v readr   2.0.2     v forcats 0.5.1
## Warning: package 'tidyr' was built under R version 4.1.2
## Warning: package 'dplyr' was built under R version 4.1.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

Pernah kita bahas sebelumnya, tapi ini ada rangkuman singkat soal factor

# Membuat factor
x1 <- c("TS","SD","SMP","SMA","S1","S2","S3")
x2 <- c("SMP","SMP","SMA","TS","S2","S1","S1")
pendidikan <- factor(x2, levels = x1)
pendidikan
## [1] SMP SMP SMA TS  S2  S1  S1 
## Levels: TS SD SMP SMA S1 S2 S3
# akses ke level
levels(pendidikan)
## [1] "TS"  "SD"  "SMP" "SMA" "S1"  "S2"  "S3"
# Menjadi level sebagaimana kemunculan data
pendidikan2 <- factor(x2, levels = unique(x2))
pendidikan2
## [1] SMP SMP SMA TS  S2  S1  S1 
## Levels: SMP SMA TS S2 S1

Mari kita coba dengan data lain. Di sini kita menggunakan package data gss_cat

gss_cat
## # A tibble: 21,483 x 9
##     year marital         age race  rincome        partyid  relig  denom  tvhours
##    <int> <fct>         <int> <fct> <fct>          <fct>    <fct>  <fct>    <int>
##  1  2000 Never married    26 White $8000 to 9999  Ind,nea~ Prote~ South~      12
##  2  2000 Divorced         48 White $8000 to 9999  Not str~ Prote~ Bapti~      NA
##  3  2000 Widowed          67 White Not applicable Indepen~ Prote~ No de~       2
##  4  2000 Never married    39 White Not applicable Ind,nea~ Ortho~ Not a~       4
##  5  2000 Divorced         25 White Not applicable Not str~ None   Not a~       1
##  6  2000 Married          25 White $20000 - 24999 Strong ~ Prote~ South~      NA
##  7  2000 Never married    36 White $25000 or more Not str~ Chris~ Not a~       3
##  8  2000 Divorced         44 White $7000 to 7999  Ind,nea~ Prote~ Luthe~      NA
##  9  2000 Married          44 White $25000 or more Not str~ Prote~ Other        0
## 10  2000 Married          47 White $25000 or more Strong ~ Prote~ South~       3
## # ... with 21,473 more rows

Dalam bentuk tibble, kita akan agak sulit untuk melihat levels yg ada secara langsung. Untuk melihatnya, kita bisa mengakali dengan menggunakan fungsi count() atau plot bar.

gss_cat %>% count(race)
## # A tibble: 3 x 2
##   race      n
##   <fct> <int>
## 1 Other  1959
## 2 Black  3129
## 3 White 16395

Oke, kita jadi tahu bahwa dalam variabel race, ada 3 level (other, black, dan white).

gss_cat %>% ggplot() + geom_bar(aes(x = race)) + scale_x_discrete(drop = FALSE)

Exercise 1. eksplor distribusi rincome (reported income). Apa yang membuat plot barnya agak susah untuk dipahami?

gss_cat %>% count(rincome)
## # A tibble: 16 x 2
##    rincome            n
##    <fct>          <int>
##  1 No answer        183
##  2 Don't know       267
##  3 Refused          975
##  4 $25000 or more  7363
##  5 $20000 - 24999  1283
##  6 $15000 - 19999  1048
##  7 $10000 - 14999  1168
##  8 $8000 to 9999    340
##  9 $7000 to 7999    188
## 10 $6000 to 6999    215
## 11 $5000 to 5999    227
## 12 $4000 to 4999    226
## 13 $3000 to 3999    276
## 14 $1000 to 2999    395
## 15 Lt $1000         286
## 16 Not applicable  7043

Analisa rerata waktu menonton TV berdasarkan agama

relig_summary <- gss_cat %>% group_by(relig) %>% 
  summarise(
    age = mean(age, na.rm = TRUE),
    tvhours = mean(tvhours, na.rm = TRUE),
    jumlah = n()
  )
relig_summary
## # A tibble: 15 x 4
##    relig                     age tvhours jumlah
##    <fct>                   <dbl>   <dbl>  <int>
##  1 No answer                49.5    2.72     93
##  2 Don't know               35.9    4.62     15
##  3 Inter-nondenominational  40.0    2.87    109
##  4 Native american          38.9    3.46     23
##  5 Christian                40.1    2.79    689
##  6 Orthodox-christian       50.4    2.42     95
##  7 Moslem/islam             37.6    2.44    104
##  8 Other eastern            45.9    1.67     32
##  9 Hinduism                 37.7    1.89     71
## 10 Buddhism                 44.7    2.38    147
## 11 Other                    41.0    2.73    224
## 12 None                     41.2    2.71   3523
## 13 Jewish                   52.4    2.52    388
## 14 Catholic                 46.9    2.96   5124
## 15 Protestant               49.9    3.15  10846
relig_summary %>% ggplot() + geom_point(aes(x = tvhours, y = relig))

Sayangnya, plot yang terlihat di atas tidak memberikan hasil yang bisa dimaknai dengan jelas. Mungkin ada yang bisa kita lakukan? Bagaimana kalau kita melakukan sedikit perubahan pada urutan level agamanya?

relig_summary %>% ggplot() + geom_point(aes(tvhours, fct_reorder(relig,tvhours)))

Nah, mulai terlihat polanya kan? Di sini kita bisa menghipotesiskan bahwa ada perbedaan rata-rata antara orang yang memiliki jalur keagamaan tertentu dengan yang tidak jelas keagamaannya terhadap lama mereka mengonsumsi televisi.

Di sini kita menggunakan fct_reorder() untuk mengurutkan level ‘relig’ berdasarkan nilai ‘tvhours’. Note : fct_inorder() digunakan untuk mengatur urutan level berdasarkan tampilan pertama pada factor, frequency factor itu sendiri, atau numeric order.

Exercise 2

  1. Apa variabel ‘relig’ paling umum? dan apa variabel ‘partyid’(kelompok politik) paling umum?
relig_general <- gss_cat %>% group_by(relig) %>% summarise(jumlah = n()) %>%
  arrange(desc(jumlah))
relig_general
## # A tibble: 15 x 2
##    relig                   jumlah
##    <fct>                    <int>
##  1 Protestant               10846
##  2 Catholic                  5124
##  3 None                      3523
##  4 Christian                  689
##  5 Jewish                     388
##  6 Other                      224
##  7 Buddhism                   147
##  8 Inter-nondenominational    109
##  9 Moslem/islam               104
## 10 Orthodox-christian          95
## 11 No answer                   93
## 12 Hinduism                    71
## 13 Other eastern               32
## 14 Native american             23
## 15 Don't know                  15
relig_general %>% ggplot() + geom_col(aes(fct_reorder(relig,jumlah),jumlah)) + coord_flip()

Untuk bidang politik ‘partyid’

jawab :

party_summary <- gss_cat %>% group_by(partyid) %>% summarise(jumlah = n())
party_summary %>% ggplot() + geom_col(aes(fct_reorder(partyid,jumlah),jumlah))+
  coord_flip()

Contoh lain :

by_age <- gss_cat %>%
  filter(!is.na(age)) %>%
  count(age, marital) %>%
  group_by(age) %>%
  mutate(prop = n/sum(n))

by_age
## # A tibble: 351 x 4
## # Groups:   age [72]
##      age marital           n    prop
##    <int> <fct>         <int>   <dbl>
##  1    18 Never married    89 0.978  
##  2    18 Married           2 0.0220 
##  3    19 Never married   234 0.940  
##  4    19 Divorced          3 0.0120 
##  5    19 Widowed           1 0.00402
##  6    19 Married          11 0.0442 
##  7    20 Never married   227 0.904  
##  8    20 Separated         1 0.00398
##  9    20 Divorced          2 0.00797
## 10    20 Married          21 0.0837 
## # ... with 341 more rows

Pembuatan grafik

by_age %>% ggplot() + geom_line(aes(age,prop,color=marital), na.rm = T)

fct_infreq

fct_infreq adalah fungsi forcats yang mengatur level factor berdasarkan frequencinya. ini sangat berguna digunakan untuk geom_bar() yang hanya memiliki satu variabel diskrit.

gss_cat %>% mutate(relig = relig %>% fct_infreq()) %>% ggplot() + 
  geom_bar(aes(relig))

fct_recode

Fungsi ini digunakan untuk mengubah value level. (bukan levelnya, kecuali level dan valuenya memang sama.)

gss_cat %>% mutate(partyid = fct_recode(partyid, 
newvalue1 = level1,
newvalue2 = level2,
......))

Dengan fct_recode, kita bisa mengubah value level, atau collapse level.

Date and Times

Nilai datetime merupakan salah satu data yang cukup tricky untuk diolah. Hal ini karena faktor fisikal, geopolitik, dan adanya DST (Day Saving Time) yang membuat beberapa perbedaan rentang waktu.

Untuk mengolah datetime, kita akan menggunakan package ‘lubridate’. Meski merupakan bagian dari tidyverse, kita tetap harus meload library ini, karena datetime bukan core dari tidyverse.

library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union

Untuk pembahasan di sini, kita akan menggunakan paket dataset ‘nycflights13’

Membuat date/time

Ada tiga tipe date/time : * Date * Time * Datetime Pada pembahasan ini, kita akan coba fokus pada data ‘date’ dan ‘datetime’

today()
## [1] "2022-01-03"
now()
## [1] "2022-01-03 00:43:17 +07"

Ada tiga cara yang bisa dilakukan untuk membuat date/time : * Dengan string * dari komponen individu date-time * Dari objek date-time yang sudah ada

Dari string

Masih ingat dengan parsing datetime? itu adalah metode untuk mengubah string menjadi objek datetime. Cara lain adalah dengan menggunakan lubridate; tulis identifikasi objek date dan time sesuai urutan yang kita inginkan (y untuk tahun, m untuk bulan dan d untuk tanggal), diikuti dengan value yang ingin kita ubah.

ymd("2017-01-31")
## [1] "2017-01-31"
mdy("12-02-2021")
## [1] "2021-12-02"
dmy("24-1-2022")
## [1] "2022-01-24"
parse_date_time("1/4/2022", "dmy")
## [1] "2022-04-01 UTC"
parse_date_time("01042022", "dmy")
## [1] "2022-04-01 UTC"
mdy(01012022)
## [1] "2022-01-01"
ymd_hm(1101220811)
## [1] "2011-01-22 08:11:00 UTC"

Lihat? baik parse dan fungsi lubridate memiliki fungsi yang sama, hanya saja untuk fungsi dari lubridate dapat digunakan saat variabel bukan string sekalipun.

Dari komponen individu

Selain dari string, kita mungkin akan menemui data tanggal dan waktu yang terpecah dalam beberapa tabel, seperti yang kita temui dalam data flights.

library(nycflights13)
## Warning: package 'nycflights13' was built under R version 4.1.2
head(flights)
## # A tibble: 6 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
## # ... with 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>
flights %>% select(year, month, day, hour, minute)
## # A tibble: 336,776 x 5
##     year month   day  hour minute
##    <int> <int> <int> <dbl>  <dbl>
##  1  2013     1     1     5     15
##  2  2013     1     1     5     29
##  3  2013     1     1     5     40
##  4  2013     1     1     5     45
##  5  2013     1     1     6      0
##  6  2013     1     1     5     58
##  7  2013     1     1     6      0
##  8  2013     1     1     6      0
##  9  2013     1     1     6      0
## 10  2013     1     1     6      0
## # ... with 336,766 more rows

Untuk mendapatkan data datetime dari nilai yang terpecah ini, kita bisa menggunakan make_date() untuk membuat date, atau make_datetime() untuk date/time.

flights %>% select(year, month, day, hour, minute) %>% mutate(
  datetime = make_datetime(year, month, day, hour, minute))
## # A tibble: 336,776 x 6
##     year month   day  hour minute datetime           
##    <int> <int> <int> <dbl>  <dbl> <dttm>             
##  1  2013     1     1     5     15 2013-01-01 05:15:00
##  2  2013     1     1     5     29 2013-01-01 05:29:00
##  3  2013     1     1     5     40 2013-01-01 05:40:00
##  4  2013     1     1     5     45 2013-01-01 05:45:00
##  5  2013     1     1     6      0 2013-01-01 06:00:00
##  6  2013     1     1     5     58 2013-01-01 05:58:00
##  7  2013     1     1     6      0 2013-01-01 06:00:00
##  8  2013     1     1     6      0 2013-01-01 06:00:00
##  9  2013     1     1     6      0 2013-01-01 06:00:00
## 10  2013     1     1     6      0 2013-01-01 06:00:00
## # ... with 336,766 more rows

Sekarang, kita terapkan cara ini untuk memodifikasi data dept dan arrival pada flights. Seperti yang kalian perhatikan, data waktu itu sedikit aneh. Kita perlu mengubahnya sedikit.

Dari tampilan data, kita tahu bahwa ada seluruh dept dan arr time (juga schedule) ditulis dalam waktu jam dan menit yg ditulis gandeng renteng. Untuk mengatasi hal tersebut, valua keempat kolom tersebut harus dimodulasikan dengan 100.

make_datetime_100 <- function(year, month, day, time) {
  make_datetime(year, month, day, time%/%100, time%%100)
}

flights_dt <- flights %>% 
  filter(!is.na(dep_time),!is.na(arr_time)) %>%
  mutate(
    dep_time = make_datetime_100(year,month,day, dep_time),
    arr_time = make_datetime_100(year,month,day,arr_time),
    sched_dep_time = make_datetime_100(year,month,day,sched_dep_time),
    sched_arr_time = make_datetime_100(year,month, day, sched_arr_time)
  ) %>%
  select(origin, dest, ends_with("delay"),ends_with("time"))

flights_dt
## # A tibble: 328,063 x 9
##    origin dest  dep_delay arr_delay dep_time            sched_dep_time     
##    <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>             
##  1 EWR    IAH           2        11 2013-01-01 05:17:00 2013-01-01 05:15:00
##  2 LGA    IAH           4        20 2013-01-01 05:33:00 2013-01-01 05:29:00
##  3 JFK    MIA           2        33 2013-01-01 05:42:00 2013-01-01 05:40:00
##  4 JFK    BQN          -1       -18 2013-01-01 05:44:00 2013-01-01 05:45:00
##  5 LGA    ATL          -6       -25 2013-01-01 05:54:00 2013-01-01 06:00:00
##  6 EWR    ORD          -4        12 2013-01-01 05:54:00 2013-01-01 05:58:00
##  7 EWR    FLL          -5        19 2013-01-01 05:55:00 2013-01-01 06:00:00
##  8 LGA    IAD          -3       -14 2013-01-01 05:57:00 2013-01-01 06:00:00
##  9 JFK    MCO          -3        -8 2013-01-01 05:57:00 2013-01-01 06:00:00
## 10 LGA    ORD          -2         8 2013-01-01 05:58:00 2013-01-01 06:00:00
## # ... with 328,053 more rows, and 3 more variables: arr_time <dttm>,
## #   sched_arr_time <dttm>, air_time <dbl>

Dengan ini, kita bisa menganalisa data lebih baik. Contoh kita ingin melihat distribusi waktu departur, maka :

flights_dt %>% ggplot() + geom_freqpoly(aes(dep_time), 
                                        binwidth = 86400) # 86400 jumlah detik dalam 1 hari

Seluruh data datetime akan dihitung berdasarkan satuan terkecilnya, yaitu detik. Seperti pada binwidth di atas, kita memberikan nilai 86400, karena itu lah jumlah detik dalam satu hari, yang artinya kita membagi dept_time berdasarkan data harian.

Contoh lain di bawah ini adalah misal kita ingin membagi atau fokus melihat distribusi dep_time dalam satu hari di tanggal 1 Januari 2013.

flights_dt %>% filter(dep_time < ymd(20130102)) %>%
  ggplot() + geom_freqpoly(aes(dep_time), binwidth = 600)

Di sini, kita membagi waktu dep_time per 10 menit (1 menit = 60 detik, 10 menit = 600 detik).

Dari tipe lain

Ada kalanya kita juga ingin mengubah tipe dari datetime ke date atau dari date ke datetime. Untuk ini, kita bisa menggunakan as_datetime() atau as_date().

Latihan

  1. Apa yang terjadi saat kita mencoba mengubah string yang berisi date invalid?
ymd(c("2010-10-10","banana"))
## Warning: 1 failed to parse.
## [1] "2010-10-10" NA

Jawab: Secara otomatis, output yang dihasilkan adalah NA.

  1. Gunakan fungsi lubridate untuk mengubah string di bawah ini.
d1 <- "January 1, 2021"
d2 <- "2015-Mar-07"
d3 <- "06-Jun-2017"
d4 <- c("August 19 (2015)","July 1 (2015)")
d5 <- "12/30/14" # Des 30, 2014

# Jawaban

mdy(d1)
## [1] "2021-01-01"
ymd(d2)
## [1] "2015-03-07"
dmy(d3)
## [1] "2017-06-06"
mdy(d4)
## [1] "2015-08-19" "2015-07-01"
mdy(d5)
## [1] "2014-12-30"
parse_date_time(d1, "%B %d, %Y")
## [1] "2021-01-01 UTC"
parse_date_time(d2, "%Y-%b-%d")
## [1] "2015-03-07 UTC"
parse_date_time(d3, "%d-%b-%Y")
## [1] "2017-06-06 UTC"
parse_date_time(d4, "%B %d (%Y)")
## [1] "2015-08-19 UTC" "2015-07-01 UTC"
parse_date_time(d5, "%m/%d/%y")
## [1] "2014-12-30 UTC"

Komponen Date Time

Bagian ini akan fokus tentang pengambilan dan pengolahan komponen date time secara aritmatik. Berikut adalah fungsi-fungsi yang digunakan untuk mendapatkan komponen hari. * date() untuk mendapatkan komponen tanggal * year() untuk mendapatkan komponen tahun * month() untuk mendapatkan komponen bulan * note : tulis month(label = T, abbr = F) untuk mendapat output nama penuh bulan * day() untuk mendapatkan komponen hari dalam satu bulan itu. * yday() untuk mendapatkan komponen hari dalam satu tahun (hari keberapa dalam satu tahun) * wday() untuk mendapatkan komponen hari dalam satu minggu. * qday() untuk mendapatkan komponen hari dalam satu quarter * hour() untuk mendapatkan komponen jam * minute() untuk mendapat komponen menit * second() untuk mendapatkan komponen detik * tz() untuk mendapatkan komponen zona waktu * week() untuk mendapatkan komponen minggu dalam satu tahun. * isoweek() untuk mendapat komponen minggu dalam ISO 8601 standart (ISO 8601 adalah kalender standart di mana tidak ada DST, sehingga seluruh minggu berisi 7 hari, dengan tidak adanya minggu yang lewat dari satu tahun. ) * epiweek() untuk mendpat komponen minggu epidemiological (standart kalender yang digunakan ahli epidemi) * quarter(), untuk mendapatkan komponen kuartal dari datetime yg ada * semester(), untuk mendapatkan komponen semester * am() untuk melakukan tes pada datetime, apakah termasuk dalam am atau tidak * pm() untuk melakukan tes, menguji apakah datetime termasuk pm * dst(), untuk menguji apakah datetime termasuk daylight saving time * leap_year(), untuk menguji apakah datetime masuk dalam tahun kabisat * update(obj datetime, …), mengubah value objek datetime.

contoh :

dt <- now()

# Contoh seluruh set dan get timedate component
date(dt)
## [1] "2022-01-03"
year(dt)
## [1] 2022
month(dt, label = T, abbr = FALSE)
## [1] January
## 12 Levels: January < February < March < April < May < June < ... < December
day(dt)
## [1] 3
week(dt)
## [1] 1
wday(dt, label = T, abbr = FALSE)
## [1] Monday
## 7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
yday(dt)
## [1] 3
qday(dt)
## [1] 3
hour(dt)
## [1] 0
minute(dt)
## [1] 43
second(dt)
## [1] 33.51394
tz(dt)
## [1] ""
isoweek(dt)
## [1] 1
epiweek(dt)
## [1] 1
quarter(dt)
## [1] 1
semester(dt)
## [1] 1
am(dt)
## [1] TRUE
pm(dt)
## [1] FALSE
leap_year(dt)
## [1] FALSE
dst(dt)
## [1] FALSE

Kembali pada contoh data ‘flights’, sekarang kita bisa melakukan analisa dist departure time dalam satu minggu menggunakan fungsi ‘wday’ (hari dalam satu minggu)

flights_dt %>% 
  mutate(wday = wday(dep_time, label = T)) %>%
  ggplot() + geom_bar(aes(wday))

Di sini kita bisa ambil kesimpulan sementara bahwa ada lebih banyak penerbangan pada weekday daripada weekend. (Akan lebih baik lagi jika seandainya kita bisa melihat timeline harian dari minggu ke minggu)

Percobaan grafik (analisa dep_time harian di bulan Januari 2013)

flights_try <- flights_dt %>% 
  mutate(month = month(dep_time, label=T),
         week = week(dep_time),
         wday = wday(dep_time, label = T)) %>%
  filter(month == "Jan")

flights_try
## # A tibble: 26,468 x 12
##    origin dest  dep_delay arr_delay dep_time            sched_dep_time     
##    <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>             
##  1 EWR    IAH           2        11 2013-01-01 05:17:00 2013-01-01 05:15:00
##  2 LGA    IAH           4        20 2013-01-01 05:33:00 2013-01-01 05:29:00
##  3 JFK    MIA           2        33 2013-01-01 05:42:00 2013-01-01 05:40:00
##  4 JFK    BQN          -1       -18 2013-01-01 05:44:00 2013-01-01 05:45:00
##  5 LGA    ATL          -6       -25 2013-01-01 05:54:00 2013-01-01 06:00:00
##  6 EWR    ORD          -4        12 2013-01-01 05:54:00 2013-01-01 05:58:00
##  7 EWR    FLL          -5        19 2013-01-01 05:55:00 2013-01-01 06:00:00
##  8 LGA    IAD          -3       -14 2013-01-01 05:57:00 2013-01-01 06:00:00
##  9 JFK    MCO          -3        -8 2013-01-01 05:57:00 2013-01-01 06:00:00
## 10 LGA    ORD          -2         8 2013-01-01 05:58:00 2013-01-01 06:00:00
## # ... with 26,458 more rows, and 6 more variables: arr_time <dttm>,
## #   sched_arr_time <dttm>, air_time <dbl>, month <ord>, week <dbl>, wday <ord>
flights_try %>% ggplot() + geom_bar(aes(week, fill = wday), position = "dodge")

Di sini, kita menampilkan bahwa pada penerbangan selama bulan Januari, terdapat pola konsisten di mana penerbangan terendah ada pada Sabtu dan Minggu. Sementara Penerbangan berada di tingkat tertingginya untuk Senin di paruh pertama bulan, dan digantikan oleh hari Rabu di paruh kedua bulan.

Kita juga bisa mengulik lebih dalam dengan melihat dalam skala jam.

flights_dt %>% 
  mutate(minute = minute(dep_time)) %>%
  group_by(minute) %>%
  summarise(
    avg_delay = mean(arr_delay, na.rm = TRUE),
    n = n()) %>%
  ggplot() + geom_line(aes(minute, avg_delay))

flights_try %>% group_by(week,wday) %>% summarise(jumlah = n()) %>%
  ggplot() + geom_line(aes(week, jumlah, color = wday))
## `summarise()` has grouped output by 'week'. You can override using the `.groups` argument.

flights_dt%>%
  mutate(dep_hour = update(dep_time, yday = 1))
## # A tibble: 328,063 x 10
##    origin dest  dep_delay arr_delay dep_time            sched_dep_time     
##    <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>             
##  1 EWR    IAH           2        11 2013-01-01 05:17:00 2013-01-01 05:15:00
##  2 LGA    IAH           4        20 2013-01-01 05:33:00 2013-01-01 05:29:00
##  3 JFK    MIA           2        33 2013-01-01 05:42:00 2013-01-01 05:40:00
##  4 JFK    BQN          -1       -18 2013-01-01 05:44:00 2013-01-01 05:45:00
##  5 LGA    ATL          -6       -25 2013-01-01 05:54:00 2013-01-01 06:00:00
##  6 EWR    ORD          -4        12 2013-01-01 05:54:00 2013-01-01 05:58:00
##  7 EWR    FLL          -5        19 2013-01-01 05:55:00 2013-01-01 06:00:00
##  8 LGA    IAD          -3       -14 2013-01-01 05:57:00 2013-01-01 06:00:00
##  9 JFK    MCO          -3        -8 2013-01-01 05:57:00 2013-01-01 06:00:00
## 10 LGA    ORD          -2         8 2013-01-01 05:58:00 2013-01-01 06:00:00
## # ... with 328,053 more rows, and 4 more variables: arr_time <dttm>,
## #   sched_arr_time <dttm>, air_time <dbl>, dep_hour <dttm>

Exercise

  1. Bagaimana distribusi jam keberangkatan dalam sehari berubah sepanjang tahun
flights_dt %>% mutate(day = yday(dep_time)) %>%
  ggplot() + geom_freqpoly(aes(day), binwidth = 7)

Time Span

Selanjutnya kita akan belajar tentang mengolah objek datetime menggunakan operasi aritmatika. Ada tiga kelas penting yang merepresentasikan time span.

  • durasi : representasi rentang waktu dalam detik
  • period : representasi rentang waktu dalam minggu dan bulan
  • Interval : representasi titik awal dan akhir waktu

Durasi

Perlu kita tahu, bahwa saat kita mengurangi dua objek datetime, kita akan mendapat objek difftime.

h_age <- today() - ymd(19791014)
h_age
## Time difference of 15422 days

Lihat? hasil perbedaan antara dua objek datetime akan dimunculkan dalam bentuk hari. Objek difftime sendiri sebenarnya merekam rentang waktu dari detik, menit, jam, hari, atau minggu. Karena sifatnya yang ambigu, lubridate membaut tool alternatif sebesar ‘duration’.

Beberapa contoh :

as.duration(h_age)
## [1] "1332460800s (~42.22 years)"

Apa bedanya? duration akan menghasilkan objek baru yang berisi selisih waktu dengan satuan second. Di samppingnya, juga akan muncul konversi unit ke dalam tahun. Seluruh fungsi dan konstruktor dalam durasi adalah selisih atau difference waktu, dan dinyatakan dalam bentuk detik. Contoh saat kita menulis ddays(1); maka ini artinya, day 1- day 0 = 1 hari –> konversikan dari detik.

Selain ‘as.duration’, terdapat beberapa konstruktor lain dalam duration :

dyears(1) # Ini artinya selisih antara tahun 1 dengan tahun 0.
## [1] "31557600s (~1 years)"
dmonths(1) # ini artinya selisih antara bulan 1 dengan bulan 0
## [1] "2629800s (~4.35 weeks)"
dweeks(1) # Ini artinya durasi 1 minggu
## [1] "604800s (~1 weeks)"
ddays(1) # ini artinya durasi satu hari
## [1] "86400s (~1 days)"
dhours(1) # ini artinya durasi 1 jam
## [1] "3600s (~1 hours)"
dseconds(1) # ini artinya durasi satu detik
## [1] "1s"
# kelanjutannya sampai dmiliseconds dan dpiconds()

Operasi-operasi yng bisa dilakukan dengan datetime : * Penjumlahan dan perkalian waktu

2 * dyears(1)
## [1] "63115200s (~2 years)"
dyears(1) + dweeks(12) + dhours(15)
## [1] "38869200s (~1.23 years)"

Kita juga bisa melakukan operasi pengurangan

Period

Period adalah fungsi datatime yng juga sama-sama mencari rentang waktu, namun period tidak mengeluarkan output dalam bentuk second secara otomatis, melainkan menggunakan unit waktu yang lebih umum.

seconds(15)
## [1] "15S"
minutes(10)
## [1] "10M 0S"
hours(c(12,24))
## [1] "12H 0M 0S" "24H 0M 0S"

Nah bisa kita lihat bahwa period akan mengikuti satuannya berdasarkan kontruktor yg ada. (sama seperti senjatanya)

Interval

Salah satu alat lain adalah interval. Ciri khusus interval adalah menampilkan secara eksplisit kondisi rentang waktu tersebut. Untuk membuat interval, ada 2 cara : * interval(starting point, end point) * starting_point%–%end point

next_year <- today() + years(1)
next_year
## [1] "2023-01-03"
(today() %--% next_year) / ddays(1)
## [1] 365
(today()%--% next_year) / days(1)
## [1] 365
(today()%--% ymd("2022-04-13")) / ddays(1)
## [1] 100
(ymd("2023-03-18")%--%today())/ddays(30)
## [1] -14.63333
today() %within% (ymd("2023-03-18")%--%today())
## [1] FALSE
#int_diff
z <- ymd("2022-01-04")
int_diff(c(z,z+100,z+1000))
## [1] 2022-01-04 UTC--2022-04-14 UTC 2022-04-14 UTC--2024-09-30 UTC

Coba pada flights data

Jika kita perhatikan pada data flights, kita akan menemukan adanya jam arr_time yang lebih kecil daripada dep_time. Kenapa bisa terjadi? hal ini karena penerbangan tersebut tiba di hari berikutnya atau penerbangan overnight. Karena akan sedikit membingungkan kita memperbaikinya dengan menambahkan satu hari pada arr_time juga scheduled_arr_time

flights_dt <- flights_dt %>% mutate(
  overnight = arr_time < dep_time,
  arr_time = arr_time + days(overnight * 1),
  sched_arr_time = sched_arr_time + days(overnight * 1)
)

flights_dt %>% filter(overnight == TRUE)
## # A tibble: 10,633 x 10
##    origin dest  dep_delay arr_delay dep_time            sched_dep_time     
##    <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>             
##  1 EWR    BQN           9        -4 2013-01-01 19:29:00 2013-01-01 19:20:00
##  2 JFK    DFW          59        NA 2013-01-01 19:39:00 2013-01-01 18:40:00
##  3 EWR    TPA          -2         9 2013-01-01 20:58:00 2013-01-01 21:00:00
##  4 EWR    SJU          -6       -12 2013-01-01 21:02:00 2013-01-01 21:08:00
##  5 EWR    SFO          11       -14 2013-01-01 21:08:00 2013-01-01 20:57:00
##  6 LGA    FLL         -10        -2 2013-01-01 21:20:00 2013-01-01 21:30:00
##  7 EWR    MCO          41        43 2013-01-01 21:21:00 2013-01-01 20:40:00
##  8 JFK    LAX          -7       -24 2013-01-01 21:28:00 2013-01-01 21:35:00
##  9 EWR    FLL          49        28 2013-01-01 21:34:00 2013-01-01 20:45:00
## 10 EWR    FLL          -9       -14 2013-01-01 21:36:00 2013-01-01 21:45:00
## # ... with 10,623 more rows, and 4 more variables: arr_time <dttm>,
## #   sched_arr_time <dttm>, air_time <dbl>, overnight <lgl>