Studi Kasus dplyr

Pre-processing dengan dplyr

Offline di Departemen Matematika
Published

November 18, 2024

Pendahuluan

Visualisasi adalah alat penting untuk mendapatkan wawasan, tetapi jarang sekali data yang kita miliki sudah dalam bentuk yang pas untuk membuat grafik yang kita inginkan. Sering kali, kita perlu membuat variabel baru atau meringkas data untuk menjawab pertanyaan yang ada. Kadang-kadang, kita juga mungkin ingin mengganti nama variabel atau mengatur ulang urutan data supaya lebih mudah digunakan.

Pada Bagian ini, kamu akan belajar cara melakukan semua itu (dan lebih banyak lagi!) dengan menggunakan package dplyr serta dataset baru tentang penerbangan yang berangkat dari New York City pada tahun 2013.

Tujuan dari bab ini adalah memberikan gambaran umum tentang alat-alat penting untuk mentransformasi data frame. Kita akan mulai dengan fungsi yang bekerja pada baris dan kolom data frame, lalu beralih membahas tentang pipe, alat penting untuk menggabungkan berbagai fungsi. Setelah itu, kita akan mengenalkan cara bekerja dengan kelompok data (grouping). Bagian ini akan ditutup dengan sebuah studi kasus yang menunjukkan bagaimana semua fungsi ini digunakan.

Prerequisites

Di bab ini, kita akan fokus pada package dplyr, salah satu anggota inti dari ekosistem tidyverse. Kita akan menjelaskan konsep-konsep utama dengan menggunakan data dari package nycflights13 dan memanfaatkan ggplot2 untuk membantu memahami data tersebut.

library(nycflights13)
Warning: package 'nycflights13' was built under R version 4.4.2
library(tidyverse)
Warning: package 'tidyverse' was built under R version 4.4.2
Warning: package 'readr' was built under R version 4.4.2
Warning: package 'forcats' was built under R version 4.4.2
Warning: package 'lubridate' was built under R version 4.4.2
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Perhatikan dengan baik pesan conflicts yang muncul saat kamu memuat tidyverse. Pesan ini memberitahukan bahwa dplyr menggantikan beberapa fungsi bawaan dari base R. Jika kamu ingin menggunakan versi fungsi bawaan setelah memuat dplyr, kamu perlu menuliskan nama lengkapnya, seperti stats::filter() dan stats::lag().

Selama ini, kita cenderung mengabaikan asal paket suatu fungsi karena biasanya tidak terlalu penting. Namun, mengetahui asal paket dapat membantu kamu mencari dokumentasi atau menemukan fungsi-fungsi terkait. Oleh karena itu, saat kita perlu menyebutkan asal fungsi dengan jelas, kita akan menggunakan sintaks R seperti ini: packagename::functionname().

nycflights13

Untuk mempelajari dasar-dasar verbs dalam dplyr, kita akan menggunakan dataset nycflights13::flights. Dataset ini mencakup semua 336.776 penerbangan yang berangkat dari New York City pada tahun 2013. Data ini berasal dari US Bureau of Transportation Statistics dan dapat didokumentasikan lebih lanjut dengan menggunakan perintah ?flights.

flights
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 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 adalah sebuah tibble, yaitu tipe khusus dari data frame yang digunakan dalam tidyverse untuk menghindari beberapa masalah umum. Perbedaan utama antara tibble dan data frame terletak pada cara tibble ditampilkan. Tibble dirancang untuk menangani dataset besar, sehingga hanya menampilkan beberapa baris pertama dan kolom-kolom yang muat di layar.

Ada beberapa cara untuk melihat keseluruhan data:

  • Jika kamu menggunakan RStudio (kita memang pakai RStudio), cara paling nyaman adalah dengan menjalankan View(flights), yang membuka tampilan interaktif, dapat digulir, dan dapat difilter.
  • Kamu juga bisa menggunakan print(flights, width = Inf) untuk menampilkan semua kolom.
  • Atau gunakan glimpse() untuk melihat ringkasan struktur data secara keseluruhan.
glimpse(flights)
Rows: 336,776
Columns: 19
$ year           <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2…
$ month          <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ day            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ dep_time       <int> 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, …
$ sched_dep_time <int> 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, …
$ dep_delay      <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1…
$ arr_time       <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849,…
$ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851,…
$ arr_delay      <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -1…
$ carrier        <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "…
$ flight         <int> 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 4…
$ tailnum        <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N394…
$ origin         <chr> "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA",…
$ dest           <chr> "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD",…
$ air_time       <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 1…
$ distance       <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, …
$ hour           <dbl> 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6…
$ minute         <dbl> 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0…
$ time_hour      <dttm> 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 0…

Dalam kedua tampilan tersebut, nama variabel diikuti oleh singkatan yang menunjukkan tipe setiap variabel:

  • <int> berarti integer (bilangan bulat),
  • <dbl> berarti double (alias bilangan real),
  • <chr> berarti character (alias string atau teks),
  • <dttm> berarti date-time (tanggal dan waktu).

Informasi ini penting karena operasi yang dapat dilakukan pada sebuah kolom sangat bergantung pada tipe datanya.

dplyr basics

Kamu akan mempelajari verbs utama dalam dplyr (fungsi-fungsi), yang dapat membantu menyelesaikan sebagian besar tantangan manipulasi data. Namun, sebelum membahas perbedaan masing-masing fungsi, ada baiknya memahami kesamaan mereka:

  1. Argumen pertama selalu berupa sebuah data frame.
  2. Argumen selanjutnya biasanya mendeskripsikan kolom yang akan dioperasikan, menggunakan nama variabel (tanpa tanda kutip).
  3. Hasil keluaran selalu berupa data frame baru.

Karena setiap verb hanya melakukan satu tugas dengan baik, menyelesaikan masalah kompleks biasanya memerlukan kombinasi beberapa verb. Kombinasi ini dilakukan dengan menggunakan pipe (|>).

Kita akan membahas pipe lebih lanjut di Bagian Asinkronus, tetapi secara singkat, pipe mengambil nilai di sebelah kirinya dan meneruskannya ke fungsi di sebelah kanannya. Contohnya:

  • x |> f(y) setara dengan f(x, y).
  • x |> f(y) |> g(z) setara dengan g(f(x, y), z). Cara termudah untuk membaca pipe adalah dengan mengartikannya sebagai “then” Ini memungkinkanmu memahami maksud kode berikut meskipun belum mempelajari detailnya.
flights |>
  filter(dest == "IAH") |> 
  group_by(year, month, day) |> 
  summarize(
    arr_delay = mean(arr_delay, na.rm = TRUE)
  )
`summarise()` has grouped output by 'year', 'month'. You can override using the
`.groups` argument.
# A tibble: 365 × 4
# Groups:   year, month [12]
    year month   day arr_delay
   <int> <int> <int>     <dbl>
 1  2013     1     1     17.8 
 2  2013     1     2      7   
 3  2013     1     3     18.3 
 4  2013     1     4     -3.2 
 5  2013     1     5     20.2 
 6  2013     1     6      9.28
 7  2013     1     7     -7.74
 8  2013     1     8      7.79
 9  2013     1     9     18.1 
10  2013     1    10      6.68
# ℹ 355 more rows

Verbs dalam dplyr dikelompokkan menjadi empat kategori berdasarkan apa yang mereka operasikan: baris, kolom, grup, atau tabel. Pada bagian berikut, kamu akan mempelajari verbs paling penting untuk mengoperasikan baris, kolom, dan grup. Kemudian, kita akan kembali membahas join verbs yang bekerja pada tabel di Bagian Asinkronus.

Mari kita mulai! 🚀

Rows - Baris

Verbs paling penting yang bekerja pada baris dalam sebuah dataset adalah:

  1. filter() – Memilih baris yang akan ditampilkan tanpa mengubah urutannya.
  2. arrange() – Mengubah urutan baris tanpa memengaruhi baris yang ditampilkan. Kedua fungsi ini hanya memengaruhi baris, sementara kolom tetap tidak berubah.

Selain itu, ada juga:

  1. distinct(), yang digunakan untuk mencari baris dengan nilai yang unik.

Berbeda dengan arrange() dan filter(), fungsi ini juga dapat, jika diperlukan, mengubah kolom.

filter()

Fungsi filter() memungkinkan kamu memilih baris berdasarkan nilai kolom tertentu.

  • Argumen pertama adalah data frame.
  • Argumen kedua dan seterusnya adalah kondisi yang harus terpenuhi agar baris tersebut dipilih. Sebagai contoh, untuk menemukan semua penerbangan yang berangkat lebih dari 120 menit (dua jam) terlambat, kamu bisa menggunakan:
flights |> 
  filter(dep_delay > 120)
# A tibble: 9,723 × 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      848           1835       853     1001           1950
 2  2013     1     1      957            733       144     1056            853
 3  2013     1     1     1114            900       134     1447           1222
 4  2013     1     1     1540           1338       122     2020           1825
 5  2013     1     1     1815           1325       290     2120           1542
 6  2013     1     1     1842           1422       260     1958           1535
 7  2013     1     1     1856           1645       131     2212           2005
 8  2013     1     1     1934           1725       129     2126           1855
 9  2013     1     1     1938           1703       155     2109           1823
10  2013     1     1     1942           1705       157     2124           1830
# ℹ 9,713 more rows
# ℹ 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>

Selain operator > (lebih besar dari), kamu juga bisa menggunakan operator lain seperti:

  • >= (lebih besar atau sama dengan),
  • < (lebih kecil dari),
  • <= (lebih kecil atau sama dengan),
  • == (sama dengan),
  • != (tidak sama dengan). Kamu juga bisa menggabungkan beberapa kondisi:

Gunakan & atau tanda koma (,) untuk menunjukkan and (kedua kondisi harus terpenuhi). Gunakan | untuk menunjukkan or (salah satu kondisi cukup terpenuhi).

# Flights that departed on January 1
flights |> 
  filter(month == 1 & day == 1)
# A tibble: 842 × 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
# ℹ 832 more rows
# ℹ 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 that departed in January or February
flights |> 
  filter(month == 1 | month == 2)
# A tibble: 51,955 × 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
# ℹ 51,945 more rows
# ℹ 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>

Ada sebuah shortcut yang berguna saat kamu menggabungkan | dengan ==, yaitu operator %in%. Operator ini akan memilih baris di mana sebuah variabel sama dengan salah satu nilai yang ada di sebelah kanan.

# A shorter way to select flights that departed in January or February
flights |> 
  filter(month %in% c(1, 2))
# A tibble: 51,955 × 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
# ℹ 51,945 more rows
# ℹ 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>

Saat kamu menjalankan filter(), dplyr melakukan operasi pemfilteran, membuat data frame baru, lalu mencetak hasilnya. Namun, fungsi dplyr tidak pernah mengubah dataset yang ada, termasuk dataset flights.

Jika kamu ingin menyimpan hasilnya, kamu harus menggunakan operator penugasan <-.

jan1 <- flights |> 
  filter(month == 1 & day == 1)

common mistakes

Ketika baru mulai belajar R, salah satu kesalahan paling umum adalah menggunakan = alih-alih == untuk menguji kesetaraan.

  • = digunakan untuk penugasan, bukan untuk membandingkan nilai.
  • == digunakan untuk memeriksa apakah dua nilai sama. Jika kamu secara tidak sengaja menggunakan = di dalam filter(), R akan memberikan pesan kesalahan yang membantu kamu mengenali kesalahan ini.
flights |> 
  filter(month == 1)
# A tibble: 27,004 × 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
# ℹ 26,994 more rows
# ℹ 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>

Kesalahan umum lainnya adalah menulis pernyataan “or” seperti dalam bahasa Inggris, alih-alih mengikuti sintaks R.

flights |> 
  filter(month == 1 | 2)
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 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>

Kode tersebut tidak akan menghasilkan kesalahan tetapi juga tidak akan melakukan apa yang kamu inginkan. Masalahnya adalah operator | pertama-tama akan memeriksa kondisi month == 1 dan kemudian memeriksa nilai 2 sebagai kondisi, yang sebenarnya tidak masuk akal untuk diperiksa.

Kenapa tidak masuk akal? Karena R mencoba memeriksa apakah nilai 2 itu benar atau salah (logical value), dan ini tidak relevan dengan kolom month.

Secara intuisi kita ingin mengambil bulan Januari atau (|) bulan Februari (Keduanya boleh). Tetapi, Perhatikan kalau konjungsi dan disjungsi dalam bahasa R ini proposisi atomik-nya harus berupa syntax callable.

Perhatikan perbedaan kedua hal ini.

  • filter(month == 1 | 2)
  • filter(month == 1 | day == 2)

Nanti, ketika syntax di atas dicompile, maka ia akan mengecek conditional_value dari kedua proposisi atomik di atas.

  • Yang pertama ia akan mengecek apakah row ke-i memiliki nilai month adalah 1 atau tidak. Jika month == 1 maka proposisi atomik ruas kiri akan bernilai TRUE. Lalu, ia akan cek proposisi kanan operator or yakni 2. Ia akan menentukan apakan 2 ini TRUE atau FALSE. Akan tetapi, karena ia tidak merupakan coditional, ia tidak dapat ditentukan apakah 2 ini TRUE atau FALSE.
  • Yang kedua sama, kecuali pada proposisi atomik yang sebelah kanan, dapat ditentukan conditional_value miliknya.

Perhatikan hal ini juga berlaku (bahkan lebih worst logika-nya [tidak masuk akal]) pada kasus konjungsi.

  • filter(month == 1 & 2)

arrange()

Fungsi arrange() digunakan untuk mengubah urutan baris dalam dataset berdasarkan nilai-nilai pada kolom-kolom yang diberikan. Fungsi ini menerima sebuah data frame dan satu set nama kolom (atau ekspresi yang lebih rumit) yang akan digunakan untuk menentukan urutan.

Jika kamu memberikan lebih dari satu nama kolom, kolom tambahan akan digunakan untuk memecahkan tie (nilai yang sama) pada kolom sebelumnya. Dengan kata lain, jika dua baris memiliki nilai yang sama di kolom pertama, arrange() akan memeriksa kolom kedua untuk menentukan urutan.

flights |> 
  arrange(year, month, day, dep_time)
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 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>

Apa yang terjadi di sini?

  • Penerbangan akan diurutkan pertama berdasarkan tahun.
  • Jika ada penerbangan di tahun yang sama, maka urutan dilanjutkan berdasarkan bulan.
  • Kemudian berdasarkan hari dalam bulan tersebut.
  • Terakhir, penerbangan yang terjadi pada hari yang sama akan diurutkan berdasarkan waktu keberangkatan (dep_time). Dengan cara ini, kita mendapatkan urutan penerbangan dari yang paling awal hingga yang paling terlambat, dimulai dari tahun yang paling awal.

Untuk mengurutkan data berdasarkan kolom dalam urutan menurun (dari yang besar ke kecil), kamu dapat menggunakan fungsi desc() di dalam arrange(). Fungsi desc() mengubah urutan kolom yang kamu tentukan sehingga data akan diurutkan dari nilai terbesar ke terkecil.

flights |> 
  arrange(desc(dep_delay))
# A tibble: 336,776 × 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     9      641            900      1301     1242           1530
 2  2013     6    15     1432           1935      1137     1607           2120
 3  2013     1    10     1121           1635      1126     1239           1810
 4  2013     9    20     1139           1845      1014     1457           2210
 5  2013     7    22      845           1600      1005     1044           1815
 6  2013     4    10     1100           1900       960     1342           2211
 7  2013     3    17     2321            810       911      135           1020
 8  2013     6    27      959           1900       899     1236           2226
 9  2013     7    22     2257            759       898      121           1026
10  2013    12     5      756           1700       896     1058           2020
# ℹ 336,766 more rows
# ℹ 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>

Perhatikan bahwa jumlah baris tidak berubah – kami hanya mengatur data, kami tidak memfilternya.

distinct()

Fungsi distinct() di dplyr digunakan untuk mencari dan mengembalikan baris-baris unik dalam sebuah dataset. Secara teknis, fungsi ini bekerja pada baris (rows) karena akan menghapus baris yang duplikat. Namun, lebih sering daripada itu, kamu mungkin ingin mencari kombinasi unik dari beberapa kolom tertentu dalam dataset, bukan seluruh baris.

Kamu bisa memberikan satu atau lebih nama kolom ke dalam distinct() untuk mendapatkan kombinasi unik dari kolom-kolom tersebut. Berikut adalah contoh penggunaannya:

# Remove duplicate rows, if any
flights |> 
  distinct()
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 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>
# Find all unique origin and destination pairs
flights |> 
  distinct(origin, dest)
# A tibble: 224 × 2
   origin dest 
   <chr>  <chr>
 1 EWR    IAH  
 2 LGA    IAH  
 3 JFK    MIA  
 4 JFK    BQN  
 5 LGA    ATL  
 6 EWR    ORD  
 7 EWR    FLL  
 8 LGA    IAD  
 9 JFK    MCO  
10 LGA    ORD  
# ℹ 214 more rows

Jika kamu ingin menjaga kolom-kolom lain saat mencari baris unik, kamu dapat menggunakan opsi .keep_all = TRUE dalam fungsi distinct(). Opsi ini memungkinkan kamu untuk mengembalikan seluruh kolom dalam dataset, bukan hanya kolom yang digunakan untuk menentukan keunikan.

flights |> 
  distinct(origin, dest, .keep_all = TRUE)
# A tibble: 224 × 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
# ℹ 214 more rows
# ℹ 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>

Penjelasan:

  • origin dan dest adalah kolom yang digunakan untuk menentukan keunikan.
  • Dengan menambahkan .keep_all = TRUE, fungsi distinct() akan mengembalikan seluruh baris yang unik berdasarkan kombinasi origin dan dest, tetapi tetap menyertakan semua kolom lainnya dalam dataset (seperti dep_delay, arr_delay, dll.).

Bukan kebetulan bahwa semua penerbangan berbeda ini terjadi pada 1 Januari: distinct() akan menemukan kemunculan pertama dari baris unik dalam kumpulan data dan membuang sisanya.

Jika Anda ingin menemukan jumlah kemunculan, Anda lebih baik menukar distinct() dengan count(). Dengan argumen sort = TRUE, Anda dapat mengaturnya dalam urutan menurun dari jumlah kemunculan.

flights |>
  count(origin, dest, sort = TRUE)
# A tibble: 224 × 3
   origin dest      n
   <chr>  <chr> <int>
 1 JFK    LAX   11262
 2 LGA    ATL   10263
 3 LGA    ORD    8857
 4 JFK    SFO    8204
 5 LGA    CLT    6168
 6 EWR    ORD    6100
 7 JFK    BOS    5898
 8 LGA    MIA    5781
 9 JFK    MCO    5464
10 EWR    BOS    5327
# ℹ 214 more rows

Latihan 1

  1. Dalam satu alur(in a single pipeline) untuk setiap kondisi, temukan semua penerbangan yang memenuhi kondisi tersebut:
  • Memiliki penundaan kedatangan dua jam atau lebih
  • Terbang ke Houston (IAH atau HOU)
  • Dioperasikan oleh United, American, atau Delta
  • Berangkat pada musim panas (Juli, Agustus, dan September)
  • Tiba lebih dari dua jam terlambat tetapi tidak pulang terlambat
  • Ditunda setidaknya satu jam, tetapi dibuat lebih dari 30 menit dalam penerbangan
  1. Urutkan penerbangan untuk menemukan penerbangan dengan penundaan keberangkatan terlama. Temukan penerbangan yang berangkat paling awal di pagi hari.

  2. Urutkan penerbangan untuk menemukan penerbangan tercepat. (Petunjuk: Coba sertakan perhitungan matematika di dalam fungsi Anda.)

  3. Apakah ada penerbangan setiap hari di tahun 2013?

  4. Penerbangan mana yang menempuh jarak terjauh? Mana yang menempuh jarak paling sedikit?

  5. Apakah penting urutan apa yang Anda gunakan filter() dan arrange() jika Anda menggunakan keduanya? Mengapa tidak? Pikirkan tentang hasil dan berapa banyak pekerjaan yang harus dilakukan oleh fungsi tersebut.

Pay Attention

Coba kerjakan dahulu sendiri. Jawaban tersedia disini

Columns - Kolom

Ada empat kata kerja penting yang memengaruhi kolom tanpa mengubah baris: mutate() membuat kolom baru yang diturunkan dari kolom yang ada, select() mengubah kolom mana yang ada, rename() mengubah nama kolom, dan relocate() mengubah posisi kolom.

mutate()

Tugas mutate() adalah menambahkan kolom baru yang dihitung dari kolom yang ada. Dalam bab transform, Anda akan mempelajari sekumpulan besar fungsi yang dapat Anda gunakan untuk memanipulasi berbagai jenis variabel. Untuk saat ini, kita akan tetap menggunakan aljabar dasar, yang memungkinkan kita menghitung perolehan, berapa lama waktu penerbangan yang tertunda di udara, dan kecepatan dalam mil per jam:

flights |> 
  mutate(
    gain = dep_delay - arr_delay,
    speed = distance / air_time * 60
  )
# A tibble: 336,776 × 21
    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
# ℹ 336,766 more rows
# ℹ 13 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>, gain <dbl>, speed <dbl>

Secara default, mutate() menambahkan kolom baru di sisi kanan kumpulan data Anda, yang menyulitkan untuk melihat apa yang terjadi di sini. Kita bisa menggunakan . sebelum argumen untuk menambahkan variabel ke sisi kiri 2:

flights |> 
  mutate(
    gain = dep_delay - arr_delay,
    speed = distance / air_time * 60,
    .before = 1
  )
# A tibble: 336,776 × 21
    gain speed  year month   day dep_time sched_dep_time dep_delay arr_time
   <dbl> <dbl> <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1    -9  370.  2013     1     1      517            515         2      830
 2   -16  374.  2013     1     1      533            529         4      850
 3   -31  408.  2013     1     1      542            540         2      923
 4    17  517.  2013     1     1      544            545        -1     1004
 5    19  394.  2013     1     1      554            600        -6      812
 6   -16  288.  2013     1     1      554            558        -4      740
 7   -24  404.  2013     1     1      555            600        -5      913
 8    11  259.  2013     1     1      557            600        -3      709
 9     5  405.  2013     1     1      557            600        -3      838
10   -10  319.  2013     1     1      558            600        -2      753
# ℹ 336,766 more rows
# ℹ 12 more variables: sched_arr_time <int>, 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>

. menunjukkan bahwa .before adalah argumen untuk fungsi tersebut, bukan nama variabel baru ketiga yang sedang kita buat. Anda juga dapat menggunakan .after menambahkan setelah variabel, dan di keduanya .before dan .after Anda dapat menggunakan nama variabel alih-alih posisi. Misalnya, kita dapat menambahkan variabel baru setelah day:

flights |> 
  mutate(
    gain = dep_delay - arr_delay,
    speed = distance / air_time * 60,
    .after = day
  )
# A tibble: 336,776 × 21
    year month   day  gain speed dep_time sched_dep_time dep_delay arr_time
   <int> <int> <int> <dbl> <dbl>    <int>          <int>     <dbl>    <int>
 1  2013     1     1    -9  370.      517            515         2      830
 2  2013     1     1   -16  374.      533            529         4      850
 3  2013     1     1   -31  408.      542            540         2      923
 4  2013     1     1    17  517.      544            545        -1     1004
 5  2013     1     1    19  394.      554            600        -6      812
 6  2013     1     1   -16  288.      554            558        -4      740
 7  2013     1     1   -24  404.      555            600        -5      913
 8  2013     1     1    11  259.      557            600        -3      709
 9  2013     1     1     5  405.      557            600        -3      838
10  2013     1     1   -10  319.      558            600        -2      753
# ℹ 336,766 more rows
# ℹ 12 more variables: sched_arr_time <int>, 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>

Sebagai alternatif, kamu bisa mengontrol variabel mana saja yang ingin disimpan menggunakan argumen .keep. Salah satu nilai yang berguna untuk .keep adalah "used", yang artinya kita hanya menyimpan kolom-kolom yang terlibat atau dibuat dalam langkah mutate(). Misalnya, pada kode berikut, hasilnya hanya akan berisi variabel-variabel: dep_delay, arr_delay, air_time, gain, hours, dan gain_per_hour:

flights |> 
  mutate(
    gain = dep_delay - arr_delay,
    hours = air_time / 60,
    gain_per_hour = gain / hours,
    .keep = "used"
  )
# A tibble: 336,776 × 6
   dep_delay arr_delay air_time  gain hours gain_per_hour
       <dbl>     <dbl>    <dbl> <dbl> <dbl>         <dbl>
 1         2        11      227    -9 3.78          -2.38
 2         4        20      227   -16 3.78          -4.23
 3         2        33      160   -31 2.67         -11.6 
 4        -1       -18      183    17 3.05           5.57
 5        -6       -25      116    19 1.93           9.83
 6        -4        12      150   -16 2.5           -6.4 
 7        -5        19      158   -24 2.63          -9.11
 8        -3       -14       53    11 0.883         12.5 
 9        -3        -8      140     5 2.33           2.14
10        -2         8      138   -10 2.3           -4.35
# ℹ 336,766 more rows
Pay Attention

kita belum menetapkan hasil perhitungan di atas kembali ke flights, variabel baru gain, hours, dan gain_per_hour hanya akan dicetak tetapi tidak akan disimpan dalam data frame.

Dan jika kita ingin hasilnya tersedia dalam data frame untuk penggunaan di masa mendatang, kita harus memikirkan dengan cermat apakah kita ingin hasilnya ditetapkan kembali ke flights, menimpa data frame asli dengan lebih banyak variabel, atau ke objek baru.

Seringkali, jawaban yang benar adalah objek baru yang diberi nama secara informatif untuk menunjukkan isinya, mis., delay_gain, tetapi Anda mungkin juga memiliki alasan bagus untuk menimpa flights.

select()

Tidak jarang mendapatkan kumpulan data dengan ratusan atau bahkan ribuan variabel. Dalam situasi ini, tantangan pertama seringkali hanya berfokus pada variabel yang Anda minati. select() memungkinkan Anda memperbesar subset yang berguna dengan cepat menggunakan operasi berdasarkan nama variabel:

  • Select columns by name:
flights |> 
  select(year, month, day)
# A tibble: 336,776 × 3
    year month   day
   <int> <int> <int>
 1  2013     1     1
 2  2013     1     1
 3  2013     1     1
 4  2013     1     1
 5  2013     1     1
 6  2013     1     1
 7  2013     1     1
 8  2013     1     1
 9  2013     1     1
10  2013     1     1
# ℹ 336,766 more rows
  • Select all columns between year and day (inclusive):
flights |> 
  select(year:day)
# A tibble: 336,776 × 3
    year month   day
   <int> <int> <int>
 1  2013     1     1
 2  2013     1     1
 3  2013     1     1
 4  2013     1     1
 5  2013     1     1
 6  2013     1     1
 7  2013     1     1
 8  2013     1     1
 9  2013     1     1
10  2013     1     1
# ℹ 336,766 more rows
  • Select all columns except those from year to day (inclusive):
flights |> 
  select(!year:day)
# A tibble: 336,776 × 16
   dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
 1      517            515         2      830            819        11 UA     
 2      533            529         4      850            830        20 UA     
 3      542            540         2      923            850        33 AA     
 4      544            545        -1     1004           1022       -18 B6     
 5      554            600        -6      812            837       -25 DL     
 6      554            558        -4      740            728        12 UA     
 7      555            600        -5      913            854        19 B6     
 8      557            600        -3      709            723       -14 EV     
 9      557            600        -3      838            846        -8 B6     
10      558            600        -2      753            745         8 AA     
# ℹ 336,766 more rows
# ℹ 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

Secara historis, operasi ini dilakukan dengan - alih-alih !, jadi kemungkinan besar Anda akan melihatnya di luar sana (wild). Kedua operator ini memiliki tujuan yang sama tetapi dengan perbedaan perilaku yang tidak kentara.

Rekomendasi

Kami merekomendasikan penggunaan ! karena terbaca sebagai “no” dan berpadu dengan baik dengan & dan |.

  • Select all columns that are characters:
flights |> 
  select(where(is.character))
# A tibble: 336,776 × 4
   carrier tailnum origin dest 
   <chr>   <chr>   <chr>  <chr>
 1 UA      N14228  EWR    IAH  
 2 UA      N24211  LGA    IAH  
 3 AA      N619AA  JFK    MIA  
 4 B6      N804JB  JFK    BQN  
 5 DL      N668DN  LGA    ATL  
 6 UA      N39463  EWR    ORD  
 7 B6      N516JB  EWR    FLL  
 8 EV      N829AS  LGA    IAD  
 9 B6      N593JB  JFK    MCO  
10 AA      N3ALAA  LGA    ORD  
# ℹ 336,766 more rows

Ada beberapa fungsi bantu (helper functions) yang dapat kamu gunakan di dalam select() untuk memilih kolom berdasarkan pola nama tertentu:

  • starts_with(“abc”): Memilih nama kolom yang diawali dengan “abc”. Contoh: Kolom bernama abc_data atau abc_result.

  • ends_with(“xyz”): Memilih nama kolom yang diakhiri dengan “xyz”. Contoh: Kolom bernama value_xyz atau output_xyz.

  • contains(“ijk”): Memilih nama kolom yang mengandung “ijk”. Contoh: Kolom bernama data_ijk atau ijk_value.

  • num_range(“x”, 1:3): Memilih nama kolom dengan pola x1, x2, dan x3. Cocok untuk kolom yang diberi nama dengan format angka berurutan.

Lihat dokumentasi ?select untuk informasi lebih lanjut. Setelah kamu memahami ekspresi reguler (yang akan dibahas di Bagian asinkronus), kamu juga bisa menggunakan fungsi matches() untuk memilih variabel yang sesuai dengan pola tertentu.

Anda dapat mengganti nama variabel saat Anda select() dengan menggunakan =. Nama baru muncul di sisi kiri =, dan variabel lama muncul di sisi kanan:

flights |> 
  select(tail_num = tailnum)
# A tibble: 336,776 × 1
   tail_num
   <chr>   
 1 N14228  
 2 N24211  
 3 N619AA  
 4 N804JB  
 5 N668DN  
 6 N39463  
 7 N516JB  
 8 N829AS  
 9 N593JB  
10 N3ALAA  
# ℹ 336,766 more rows

rename()

Jika Anda ingin menyimpan semua variabel yang ada dan hanya ingin mengganti nama beberapa variabel, Anda dapat menggunakan rename() alih-alih select():

flights |> 
  rename(tail_num = tailnum)
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
#   tail_num <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
#   hour <dbl>, minute <dbl>, time_hour <dttm>

Jika kamu memiliki banyak kolom dengan nama yang tidak konsisten dan memperbaikinya satu per satu akan memakan waktu, coba gunakan janitor::clean_names(), yang dapat membersihkan nama-nama kolom secara otomatis dengan cara yang berguna.

relocate()

Gunakan relocate() untuk memindahkan variabel di dalam dataset. Kamu mungkin ingin mengumpulkan variabel-variabel yang berhubungan bersama atau memindahkan variabel penting ke depan. Secara default, relocate() akan memindahkan variabel ke bagian depan dataset.

flights |> 
  relocate(time_hour, air_time)
# A tibble: 336,776 × 19
   time_hour           air_time  year month   day dep_time sched_dep_time
   <dttm>                 <dbl> <int> <int> <int>    <int>          <int>
 1 2013-01-01 05:00:00      227  2013     1     1      517            515
 2 2013-01-01 05:00:00      227  2013     1     1      533            529
 3 2013-01-01 05:00:00      160  2013     1     1      542            540
 4 2013-01-01 05:00:00      183  2013     1     1      544            545
 5 2013-01-01 06:00:00      116  2013     1     1      554            600
 6 2013-01-01 05:00:00      150  2013     1     1      554            558
 7 2013-01-01 06:00:00      158  2013     1     1      555            600
 8 2013-01-01 06:00:00       53  2013     1     1      557            600
 9 2013-01-01 06:00:00      140  2013     1     1      557            600
10 2013-01-01 06:00:00      138  2013     1     1      558            600
# ℹ 336,766 more rows
# ℹ 12 more variables: dep_delay <dbl>, arr_time <int>, sched_arr_time <int>,
#   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
#   dest <chr>, distance <dbl>, hour <dbl>, minute <dbl>

Anda juga dapat menentukan di mana harus meletakkannya menggunakan .before dan .after argumen, seperti di mutate():

flights |> 
  relocate(year:dep_time, .after = time_hour)
# A tibble: 336,776 × 19
   sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
            <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1            515         2      830            819        11 UA        1545
 2            529         4      850            830        20 UA        1714
 3            540         2      923            850        33 AA        1141
 4            545        -1     1004           1022       -18 B6         725
 5            600        -6      812            837       -25 DL         461
 6            558        -4      740            728        12 UA        1696
 7            600        -5      913            854        19 B6         507
 8            600        -3      709            723       -14 EV        5708
 9            600        -3      838            846        -8 B6          79
10            600        -2      753            745         8 AA         301
# ℹ 336,766 more rows
# ℹ 12 more variables: tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>, year <int>,
#   month <int>, day <int>, dep_time <int>
flights |> 
  relocate(starts_with("arr"), .before = dep_time)
# A tibble: 336,776 × 19
    year month   day arr_time arr_delay dep_time sched_dep_time dep_delay
   <int> <int> <int>    <int>     <dbl>    <int>          <int>     <dbl>
 1  2013     1     1      830        11      517            515         2
 2  2013     1     1      850        20      533            529         4
 3  2013     1     1      923        33      542            540         2
 4  2013     1     1     1004       -18      544            545        -1
 5  2013     1     1      812       -25      554            600        -6
 6  2013     1     1      740        12      554            558        -4
 7  2013     1     1      913        19      555            600        -5
 8  2013     1     1      709       -14      557            600        -3
 9  2013     1     1      838        -8      557            600        -3
10  2013     1     1      753         8      558            600        -2
# ℹ 336,766 more rows
# ℹ 11 more variables: sched_arr_time <int>, carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
#   hour <dbl>, minute <dbl>, time_hour <dttm>

##Latihan 2 1. Bandingkan dep_time, sched_dep_time, dan dep_delay. Bagaimana Anda mengharapkan ketiga angka itu terkait?

  1. Lakukan brainstorming sebanyak mungkin cara untuk memilih dep_time, dep_delay, arr_time, dan arr_delay dari flights.

  2. Apa yang terjadi jika Anda menentukan nama variabel yang sama beberapa kali dalam panggilan select()?

  3. Apa yang dilakukan fungsi any_of()? Mengapa ini bisa membantu dalam hubungannya dengan vektor ini?

variables <- c("year", "month", "day", "dep_delay", "arr_delay")
  1. Apakah hasil menjalankan kode berikut mengejutkan Anda? Bagaimana pembantu select menangani huruf besar dan kecil secara default? Bagaimana Anda bisa mengubah default itu?
flights |> select(contains("TIME"))
# A tibble: 336,776 × 6
   dep_time sched_dep_time arr_time sched_arr_time air_time time_hour          
      <int>          <int>    <int>          <int>    <dbl> <dttm>             
 1      517            515      830            819      227 2013-01-01 05:00:00
 2      533            529      850            830      227 2013-01-01 05:00:00
 3      542            540      923            850      160 2013-01-01 05:00:00
 4      544            545     1004           1022      183 2013-01-01 05:00:00
 5      554            600      812            837      116 2013-01-01 06:00:00
 6      554            558      740            728      150 2013-01-01 05:00:00
 7      555            600      913            854      158 2013-01-01 06:00:00
 8      557            600      709            723       53 2013-01-01 06:00:00
 9      557            600      838            846      140 2013-01-01 06:00:00
10      558            600      753            745      138 2013-01-01 06:00:00
# ℹ 336,766 more rows
  1. Ganti nama air_time menjadi air_time_min untuk menunjukkan satuan pengukuran dan memindahkannya ke awal bingkai data.

Mengapa hal berikut tidak berhasil, dan apa arti kesalahannya?

flights |> 
  select(tailnum) |> 
  arrange(arr_delay)
Error in `arrange()`:
ℹ In argument: `..1 = arr_delay`.
Caused by error:
! object 'arr_delay' not found
Pay Attention

Coba kerjakan dahulu sendiri. Jawaban tersedia disini

The pipe

Kami telah menunjukkan contoh sederhana dari penggunaan pipe di atas, namun kekuatan sebenarnya dari pipe muncul saat kamu mulai menggabungkan beberapa fungsi (verbs). Misalnya, bayangkan kamu ingin mencari penerbangan tercepat ke bandara IAH di Houston. Untuk melakukan ini, kamu perlu menggabungkan fungsi filter(), mutate(), select(), dan arrange().

flights |> 
  filter(dest == "IAH") |> 
  mutate(speed = distance / air_time * 60) |> 
  select(year:day, dep_time, carrier, flight, speed) |> 
  arrange(desc(speed))
# A tibble: 7,198 × 7
    year month   day dep_time carrier flight speed
   <int> <int> <int>    <int> <chr>    <int> <dbl>
 1  2013     7     9      707 UA         226  522.
 2  2013     8    27     1850 UA        1128  521.
 3  2013     8    28      902 UA        1711  519.
 4  2013     8    28     2122 UA        1022  519.
 5  2013     6    11     1628 UA        1178  515.
 6  2013     8    27     1017 UA         333  515.
 7  2013     8    27     1205 UA        1421  515.
 8  2013     8    27     1758 UA         302  515.
 9  2013     9    27      521 UA         252  515.
10  2013     8    28      625 UA         559  515.
# ℹ 7,188 more rows

Meskipun alur ini memiliki empat langkah, mudah untuk membaca sekilas karena kata kerja muncul di awal setiap baris: mulai dengan data flights, lalu filter, lalu mutate, lalu select, lalu arrange.

Apa yang akan terjadi jika kita tidak memiliki pipe? Kita dapat menyarangkan setiap pemanggilan fungsi di dalam pemanggilan sebelumnya:

arrange(
  select(
    mutate(
      filter(
        flights, 
        dest == "IAH"
      ),
      speed = distance / air_time * 60
    ),
    year:day, dep_time, carrier, flight, speed
  ),
  desc(speed)
)
# A tibble: 7,198 × 7
    year month   day dep_time carrier flight speed
   <int> <int> <int>    <int> <chr>    <int> <dbl>
 1  2013     7     9      707 UA         226  522.
 2  2013     8    27     1850 UA        1128  521.
 3  2013     8    28      902 UA        1711  519.
 4  2013     8    28     2122 UA        1022  519.
 5  2013     6    11     1628 UA        1178  515.
 6  2013     8    27     1017 UA         333  515.
 7  2013     8    27     1205 UA        1421  515.
 8  2013     8    27     1758 UA         302  515.
 9  2013     9    27      521 UA         252  515.
10  2013     8    28      625 UA         559  515.
# ℹ 7,188 more rows

Atau kita bisa menggunakan banyak objek perantara:

flights1 <- filter(flights, dest == "IAH")
flights2 <- mutate(flights1, speed = distance / air_time * 60)
flights3 <- select(flights2, year:day, dep_time, carrier, flight, speed)
arrange(flights3, desc(speed))
# A tibble: 7,198 × 7
    year month   day dep_time carrier flight speed
   <int> <int> <int>    <int> <chr>    <int> <dbl>
 1  2013     7     9      707 UA         226  522.
 2  2013     8    27     1850 UA        1128  521.
 3  2013     8    28      902 UA        1711  519.
 4  2013     8    28     2122 UA        1022  519.
 5  2013     6    11     1628 UA        1178  515.
 6  2013     8    27     1017 UA         333  515.
 7  2013     8    27     1205 UA        1421  515.
 8  2013     8    27     1758 UA         302  515.
 9  2013     9    27      521 UA         252  515.
10  2013     8    28      625 UA         559  515.
# ℹ 7,188 more rows

Meskipun kedua bentuk (menggunakan pipe atau tanpa pipe) memiliki kelebihan dan kekurangannya masing-masing, penggunaan pipe umumnya menghasilkan kode analisis data yang lebih mudah ditulis dan dibaca.

Kenapa Pipe Lebih Baik?

  • Kemudahan Membaca: Kode yang menggunakan pip lebih mudah dibaca karena setiap langkah dalam proses analisis data dipecah menjadi bagian yang terpisah, dan urutannya jelas. Ini membuat alur logika lebih transparan.
  • Kemudahan Menulis: Dengan pipe, kita tidak perlu menulis fungsi-fungsi bersarang yang dapat membingungkan. Kode lebih ringkas dan mudah dimodifikasi.

Menambahkan Pipe ke Kode:

Di RStudio, kamu bisa menambahkan pipe dengan menggunakan shortcut keyboard bawaan Ctrl/Cmd + Shift + M. Ini akan menyisipkan simbol pipe (|>) secara otomatis ke dalam kode kamu.

Gambar 1. Untuk memasukkan |>, pastikan “Use native pipe operator” option is checked.
  • %>%: Ini adalah operator pipe yang umum digunakan di dplyr dan berbagai paket tidyverse lainnya. Ini juga berfungsi dalam banyak situasi di luar tidyverse.
#|eval: FALSE
library(tidyverse)

mtcars %>% 
  group_by(cyl) %>%
  summarize(n = n())
# A tibble: 3 × 2
    cyl     n
  <dbl> <int>
1     4    11
2     6     7
3     8    14
  • |>: Operator pipe ini adalah bagian dari bahasa R itu sendiri, mulai diperkenalkan di R versi 4.1.0. Fungsinya mirip dengan %>%, tetapi memiliki beberapa perbedaan kecil dalam cara menangani argumen dan kedalaman fungsi.

Groups

Sejauh ini Anda telah mempelajari tentang fungsi yang berfungsi dengan baris dan kolom. dplyr menjadi lebih kuat saat Anda menambahkan kemampuan untuk bekerja dengan grup. Di bagian ini, kita akan fokus pada fungsi yang paling penting: group_by(), summarize() dan keluarga fungsi slice.

group_by()

Gunakan group_by() untuk membagi kumpulan data Anda menjadi beberapa grup yang bermakna untuk analisis Anda:

flights |> 
  group_by(month)
# A tibble: 336,776 × 19
# Groups:   month [12]
    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
# ℹ 336,766 more rows
# ℹ 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>

group_by() tidak mengubah data tetapi, jika Anda melihat lebih dekat pada outputnya, Anda akan melihat bahwa outputnya menunjukkan bahwa itu “dikelompokkan berdasarkan” bulan (Groups: month [12]). Ini berarti operasi selanjutnya sekarang akan berfungsi “berdasarkan bulan”. group_by() menambahkan fitur yang dikelompokkan ini (disebut sebagai kelas class) ke data frame, yang mengubah perilaku kata kerja berikutnya yang diterapkan ke data.

summarize()

Operasi pengelompokan yang paling penting adalah ringkasan, yang mana jika digunakan untuk menghitung statistik ringkasan tunggal, mengurangi data frame menjadi satu baris untuk setiap grup. Di dplyr, operasi ini dilakukan dengan summarize(), seperti yang ditunjukkan oleh contoh berikut, yang menghitung penundaan keberangkatan rata-rata menurut bulan:

flights |> 
  group_by(month) |> 
  summarize(
    avg_delay = mean(dep_delay)
  )
# A tibble: 12 × 2
   month avg_delay
   <int>     <dbl>
 1     1        NA
 2     2        NA
 3     3        NA
 4     4        NA
 5     5        NA
 6     6        NA
 7     7        NA
 8     8        NA
 9     9        NA
10    10        NA
11    11        NA
12    12        NA

Uh-oh! Ada yang tidak beres, dan semua hasil kami adalah NAs (diucapkan “NA”), simbol R untuk nilai yang hilang. Ini terjadi karena beberapa penerbangan yang diamati memiliki data yang hilang di kolom penundaan, jadi ketika kami menghitung rata-rata termasuk nilai tersebut, kami mendapatkan hasil NA. Kita akan kembali membahas nilai yang hilang secara detail di Bagian Asinkronus, tetapi untuk saat ini, kita akan memberi tahu fungsi mean() untuk mengabaikan semua nilai yang hilang dengan menyetel argumen na.rm menjadi TRUE:

flights |> 
  group_by(month) |> 
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE)
  )
# A tibble: 12 × 2
   month avg_delay
   <int>     <dbl>
 1     1     10.0 
 2     2     10.8 
 3     3     13.2 
 4     4     13.9 
 5     5     13.0 
 6     6     20.8 
 7     7     21.7 
 8     8     12.6 
 9     9      6.72
10    10      6.24
11    11      5.44
12    12     16.6 

Anda dapat membuat sejumlah ringkasan dalam satu panggilan ke summarize(). Anda akan mempelajari berbagai ringkasan berguna di bab-bab mendatang, tetapi satu ringkasan yang sangat berguna adalah n(), yang mengembalikan jumlah baris di setiap grup:

flights |> 
  group_by(month) |> 
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE), 
    n = n()
  )
# A tibble: 12 × 3
   month avg_delay     n
   <int>     <dbl> <int>
 1     1     10.0  27004
 2     2     10.8  24951
 3     3     13.2  28834
 4     4     13.9  28330
 5     5     13.0  28796
 6     6     20.8  28243
 7     7     21.7  29425
 8     8     12.6  29327
 9     9      6.72 27574
10    10      6.24 28889
11    11      5.44 27268
12    12     16.6  28135

Means dan counts bisa ditemukan lebih lanjut dalam ilmu data!

The sclice function

Berikut adalah lima fungsi berguna dalam dplyr yang memungkinkan kamu untuk mengekstrak baris tertentu dalam setiap grup:

  • slice_head(n = 1): Mengambil baris pertama dari setiap grup.
  • slice_tail(n = 1): Mengambil baris terakhir dari setiap grup.
  • slice_min(x, n = 1): Mengambil baris dengan nilai terkecil di kolom x.
  • slice_max(x, n = 1): Mengambil baris dengan nilai terbesar di kolom x.
  • slice_sample(n = 1): Mengambil satu baris secara acak.

Kamu dapat menyesuaikan n untuk memilih lebih dari satu baris, atau kamu bisa menggunakan argumen prop untuk memilih proporsi tertentu dari baris. Misalnya, prop = 0.1 akan memilih 10% dari baris di setiap grup.

flights |> 
  group_by(dest) |> 
  slice_max(arr_delay, n = 1) |>
  relocate(dest)
# A tibble: 108 × 19
# Groups:   dest [105]
   dest   year month   day dep_time sched_dep_time dep_delay arr_time
   <chr> <int> <int> <int>    <int>          <int>     <dbl>    <int>
 1 ABQ    2013     7    22     2145           2007        98      132
 2 ACK    2013     7    23     1139            800       219     1250
 3 ALB    2013     1    25      123           2000       323      229
 4 ANC    2013     8    17     1740           1625        75     2042
 5 ATL    2013     7    22     2257            759       898      121
 6 AUS    2013     7    10     2056           1505       351     2347
 7 AVL    2013     8    13     1156            832       204     1417
 8 BDL    2013     2    21     1728           1316       252     1839
 9 BGR    2013    12     1     1504           1056       248     1628
10 BHM    2013     4    10       25           1900       325      136
# ℹ 98 more rows
# ℹ 11 more variables: sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#   flight <int>, tailnum <chr>, origin <chr>, air_time <dbl>, distance <dbl>,
#   hour <dbl>, minute <dbl>, time_hour <dttm>

Perhatikan bahwa meskipun ada 105 tujuan, kita mendapatkan 108 baris di sini. Mengapa bisa begitu?

Fungsi slice_min() dan slice_max() akan mempertahankan nilai yang terikat (tie), jadi meskipun kita menetapkan n = 1, jika ada beberapa baris dengan nilai yang sama (misalnya, keterlambatan yang sama), maka seluruh baris tersebut akan dimasukkan. Jika kamu hanya ingin satu baris per grup meskipun ada nilai yang terikat, kamu bisa menggunakan argumen with_ties = FALSE.

Dengan menambahkan with_ties = FALSE, fungsi ini hanya akan mengambil satu baris per grup, bahkan jika ada beberapa baris yang memiliki nilai keterlambatan yang sama.

Ini mirip dengan perhitungan nilai maksimum menggunakan summarize(), tetapi dengan slice_max() atau slice_min(), kamu mendapatkan seluruh baris yang sesuai dengan nilai tersebut (atau beberapa baris jika ada tie), bukan hanya statistik ringkasan tunggal.

Grouping by multiple variables

Anda dapat membuat grup menggunakan lebih dari satu variabel. Misalnya, kita dapat membuat grup untuk setiap tanggal.

daily <- flights |>  
  group_by(year, month, day)
daily
# A tibble: 336,776 × 19
# Groups:   year, month, day [365]
    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
# ℹ 336,766 more rows
# ℹ 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>

Ketika kamu melakukan summary pada sebuah tibble yang dikelompokkan berdasarkan lebih dari satu variabel, setiap summary akan memisahkan grup terakhir. Meskipun ini bukan cara terbaik untuk membuat fungsi ini bekerja, perubahan pada perilaku ini sulit dilakukan tanpa merusak kode yang sudah ada.

Untuk membuat hal ini lebih jelas, dplyr menampilkan pesan yang memberi tahu kamu bagaimana cara mengubah perilaku ini. Pesan tersebut biasanya berbunyi seperti ini:

“This is the default behavior of summarize() when grouping by multiple variables. To change this behavior, you can use group_by() followed by ungroup() or adjust the grouping inside summarize().”

daily_flights <- daily |> 
  summarize(n = n())
`summarise()` has grouped output by 'year', 'month'. You can override using the
`.groups` argument.

Jika Anda happy dengan perilaku ini, Anda dapat memintanya secara eksplisit untuk menyembunyikan pesan tersebut:

daily_flights <- daily |> 
  summarize(
    n = n(), 
    .groups = "drop_last"
  )

Atau, ubah perilaku default dengan menetapkan nilai yang berbeda, mis., “drop” untuk menghapus semua pengelompokan atau “keep” untuk mempertahankan grup yang sama.

Ungrouping

Anda mungkin juga ingin menghapus pengelompokan dari dataframe tanpa menggunakan summarize(). Anda dapat melakukannya dengan ungroup().

daily |> 
  ungroup()
# A tibble: 336,776 × 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
# ℹ 336,766 more rows
# ℹ 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>

Sekarang mari kita lihat apa yang terjadi saat Anda summarize data frame yang tidak dikelompokkan.

daily |> 
  ungroup() |>
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE), 
    flights = n()
  )
# A tibble: 1 × 2
  avg_delay flights
      <dbl>   <int>
1      12.6  336776

Anda mendapatkan satu baris kembali karena dplyr memperlakukan semua baris dalam data frame yang tidak dikelompokkan sebagai milik satu grup.

.by

dplyr 1.1.0 menyertakan sintaks baru, eksperimental, untuk pengelompokan per operasi, argumen .by, group_by(), dan ungroup() tidak akan hilang, tetapi sekarang Anda juga dapat menggunakan argumen .by untuk mengelompokkan dalam satu operasi:

flights |> 
  summarize(
    delay = mean(dep_delay, na.rm = TRUE), 
    n = n(),
    .by = month
  )
# A tibble: 12 × 3
   month delay     n
   <int> <dbl> <int>
 1     1 10.0  27004
 2    10  6.24 28889
 3    11  5.44 27268
 4    12 16.6  28135
 5     2 10.8  24951
 6     3 13.2  28834
 7     4 13.9  28330
 8     5 13.0  28796
 9     6 20.8  28243
10     7 21.7  29425
11     8 12.6  29327
12     9  6.72 27574

Atau jika Anda ingin mengelompokkan berdasarkan beberapa variabel:

flights |> 
  summarize(
    delay = mean(dep_delay, na.rm = TRUE), 
    n = n(),
    .by = c(origin, dest)
  )
# A tibble: 224 × 4
   origin dest  delay     n
   <chr>  <chr> <dbl> <int>
 1 EWR    IAH   11.8   3973
 2 LGA    IAH    9.06  2951
 3 JFK    MIA    9.34  3314
 4 JFK    BQN    6.67   599
 5 LGA    ATL   11.4  10263
 6 EWR    ORD   14.6   6100
 7 EWR    FLL   13.5   3793
 8 LGA    IAD   16.7   1803
 9 JFK    MCO   10.6   5464
10 LGA    ORD   10.7   8857
# ℹ 214 more rows

.by bekerja dengan semua kata kerja dan memiliki keuntungan bahwa Anda tidak perlu menggunakan argumen .group untuk menekan pesan pengelompokan atau ungroup() setelah selesai.

Latihan 3

  1. Operator mana yang memiliki penundaan rata-rata terburuk? Tantangan: dapatkah Anda menguraikan efek dari bad airport v.s. bad carriers? Mengapa iya / mengapa tidak? (Petunjuk: pikirkan tentang flights|> group_by(carrier, dest)|> summarize(n()))

  2. Temukan penerbangan yang paling tertunda saat keberangkatan dari setiap tujuan.

  3. Bagaimana penundaan bervariasi sepanjang hari? Ilustrasikan jawaban Anda dengan sebuah plot.

  4. Apa yang terjadi jika Anda memberikan n negatif ke slice_min() dan teman-temannya?

  5. Jelaskan apa yang dilakukan count() dalam kaitannya dengan kata kerja dplyr yang baru saja Anda pelajari. Apa yang dilakukan argumen sort kepada count()?

  6. Misalkan kita memiliki bingkai data kecil berikut:

df <- tibble(
  x = 1:5,
  y = c("a", "b", "a", "a", "b"),
  z = c("K", "K", "L", "L", "K")
)
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan group_by().
df |>
  group_by(y)
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan arrange(). Juga, beri komentar tentang perbedaannya dari group_by() di bagian (a).
df |>
  arrange(y)
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan pipeline.
df |>
  group_by(y) |>
  summarize(mean_x = mean(x))
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan pipeline. Kemudian, komentari apa yang dikatakan pesan tersebut.
df |>
  group_by(y, z) |>
  summarize(mean_x = mean(x))
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan pipeline. Bagaimana outputnya berbeda dari yang ada di bagian (d)?
df |>
  group_by(y, z) |>
  summarize(mean_x = mean(x), .groups = "drop")
  1. Tuliskan seperti apa tampilan outputnya menurut Anda, lalu periksa apakah Anda benar, dan jelaskan apa yang dilakukan setiap pipeline. Bagaimana output dari kedua pipeline berbeda?
df |>
  group_by(y, z) |>
  summarize(mean_x = mean(x))
`summarise()` has grouped output by 'y'. You can override using the `.groups`
argument.
# A tibble: 3 × 3
# Groups:   y [2]
  y     z     mean_x
  <chr> <chr>  <dbl>
1 a     K        1  
2 a     L        3.5
3 b     K        3.5
df |>
  group_by(y, z) |>
  mutate(mean_x = mean(x))
# A tibble: 5 × 4
# Groups:   y, z [3]
      x y     z     mean_x
  <int> <chr> <chr>  <dbl>
1     1 a     K        1  
2     2 b     K        3.5
3     3 a     L        3.5
4     4 a     L        3.5
5     5 b     K        3.5
Pay Attention

Coba kerjakan dahulu sendiri. Jawaban tersedia disini

Studi kasus - Dataset Information

Kita akan memberikan salah satu contoh pemula pre-processing dari data yang dibawah ini.

Pendahuluan

Dalam dunia transportasi online, layanan seperti greb telah mengubah cara kita memesan dan menggunakan transportasi. Seiring dengan pertumbuhan pesat teknologi, data yang dihasilkan oleh platform transportasi online semakin berharga. Untuk memanfaatkan potensi data ini, kami mengadakan kompetisi prediksi harga pesanan mobil. Tujuan dari kompetisi ini adalah untuk mengembangkan model prediksi yang akurat dan canggih untuk harga pesanan mobil berdasarkan fitur-fitur yang diberikan.

Evaluation

Dalam kasus kali ini, kami akan menggunakan Root Mean Square Error (RMSE) sebagai metrik evaluasi utama untuk mengukur kinerja model prediksi harga pesanan mobil. RMSE mengukur sejauh mana prediksi harga yang dihasilkan oleh model mendekati harga aktual.

RMSE didefinisikan sebagai berikut:

\[\sqrt{\frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y}_i)^2}\] Hasil RMSE yang lebih rendah menunjukkan kinerja model yang lebih baik dalam memprediksi harga pesanan mobil. Peserta yang berhasil menghasilkan model dengan RMSE terendah akan diberi apresiasi.

Scoring System

Dalam kasus kali ini, penilaian akan dinilai 100% dari metrik, dimana penilaian kalian akan bergantung pada evaluasi metrik. Semakin rendah hasil RMSE kalian, semakin tinggi poin yang akan kalian peroleh.

Penjelasan Dataset

Column Name Description
timestamp Memberikan informasi berupa waktu atau penanda.
api_calls Mencerminkan jumlah panggilan atau permintaan ke API.
clouds Memberikan informasi tentang kondisi awan.
distance_max Menggambarkan jarak terkait pesanan (jarak maksimum).
distance_mean Menggambarkan jarak terkait pesanan (jarak rata-rata).
distance_min Menggambarkan jarak terkait pesanan (jarak minimum).
humidity Menunjukkan tingkat kelembapan.
rain Data terkait hujan atau curah hujan.
surge_max Informasi lonjakan harga (lonjakan maksimum).
surge_mean Informasi lonjakan harga (lonjakan rata-rata).
surge_min Informasi lonjakan harga (lonjakan minimum).
temp Data terkait suhu.
price_mean Harga pesanan mobil

Main Notebook

Import Data

train <- read.csv('https://raw.githubusercontent.com/zzeiidann/Ristek-UI-Competition/refs/heads/main/Ristek-UI-Data-Competition-2023/Data/train.csv')
test <- read.csv('https://raw.githubusercontent.com/zzeiidann/Ristek-UI-Competition/refs/heads/main/Ristek-UI-Data-Competition-2023/Data/test.csv')
  • train : digunakan untuk melatih model , sekaligus mengevaluasi model.
  • test : digunakan untuk membuat prediksi menggunakan model setelah selesai dibuat.
head(train)
            timestamp api_calls    clouds distance_max distance_mean
1 2018-11-26 06:00:00         9 0.9906667         3.03      1.726667
2 2018-11-26 07:00:00        10 0.9700000         2.67      1.690000
3 2018-11-26 08:00:00         1 0.9800000         1.38      1.380000
4 2018-11-26 09:00:00        11 1.0000000         3.08      1.920909
5 2018-11-26 10:00:00        12 0.9950000         3.01      2.122500
6 2018-11-26 11:00:00         6 0.9550000         2.97      1.721667
  distance_min  humidity price_mean rain surge_max surge_mean surge_min
1         1.04 0.9133333   16.55556    0      1.50   1.055556         1
2         1.09 0.9200000   17.30000    0      2.00   1.100000         1
3         1.38 0.9233333   13.50000    0      1.00   1.000000         1
4         1.39 0.9275000   17.95455    0      1.75   1.113636         1
5         1.07 0.9400000   18.62500    0      1.50   1.083333         1
6         1.03 0.9400000   15.08333    0      1.00   1.000000         1
      temp     wind type
1 40.62733 1.350667    0
2 41.13750 1.735000    0
3 40.92000 1.330000    0
4 40.93750 1.365000    0
5 40.69500 1.895000    0
6 40.18500 2.260000    0
head(test)
  index           timestamp api_calls clouds distance_max distance_mean
1     0 2018-12-14 00:00:00        13   0.69         3.02      1.980000
2     1 2018-12-14 01:00:00        14   0.77         2.34      1.541429
3     2 2018-12-14 02:00:00        13   0.59         3.00      2.010769
4     3 2018-12-14 03:00:00        12   0.68         3.14      1.860833
5     4 2018-12-14 04:00:00         7   0.72         2.41      1.634286
6     5 2018-12-14 05:00:00         9   0.60         2.63      1.623333
  distance_min humidity rain surge_max surge_mean surge_min  temp wind type
1         1.06     0.68    0      2.00   1.115385         1 29.93 1.99    0
2         1.04     0.68    0      1.00   1.000000         1 30.19 2.35    0
3         1.08     0.69    0      1.50   1.096154         1 30.02 1.98    0
4         1.06     0.70    0      1.25   1.020833         1 29.89 1.92    0
5         1.06     0.71    0      1.25   1.035714         1 29.92 1.58    0
6         1.06     0.73    0      1.25   1.027778         1 29.28 1.35    0

Collecting Data Information

cat('Informasi Data Train')
Informasi Data Train
str(train)
'data.frame':   20355 obs. of  15 variables:
 $ timestamp    : chr  "2018-11-26 06:00:00" "2018-11-26 07:00:00" "2018-11-26 08:00:00" "2018-11-26 09:00:00" ...
 $ api_calls    : num  9 10 1 11 12 6 12 9 9 10 ...
 $ clouds       : num  0.991 0.97 0.98 1 0.995 ...
 $ distance_max : num  3.03 2.67 1.38 3.08 3.01 2.97 3.01 3.01 3.02 3.03 ...
 $ distance_mean: num  1.73 1.69 1.38 1.92 2.12 ...
 $ distance_min : num  1.04 1.09 1.38 1.39 1.07 1.03 1.07 1.06 1.04 1.07 ...
 $ humidity     : num  0.913 0.92 0.923 0.927 0.94 ...
 $ price_mean   : num  16.6 17.3 13.5 18 18.6 ...
 $ rain         : num  0 0 0 0 0 0 0 0.0031 0.0044 0 ...
 $ surge_max    : num  1.5 2 1 1.75 1.5 1 1.25 2 1 1 ...
 $ surge_mean   : num  1.06 1.1 1 1.11 1.08 ...
 $ surge_min    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ temp         : num  40.6 41.1 40.9 40.9 40.7 ...
 $ wind         : num  1.35 1.74 1.33 1.36 1.9 ...
 $ type         : int  0 0 0 0 0 0 0 0 0 0 ...
cat('Informasi Data Test')
Informasi Data Test
str(test)
'data.frame':   11040 obs. of  15 variables:
 $ index        : int  0 1 2 3 4 5 6 7 8 9 ...
 $ timestamp    : chr  "2018-12-14 00:00:00" "2018-12-14 01:00:00" "2018-12-14 02:00:00" "2018-12-14 03:00:00" ...
 $ api_calls    : num  13 14 13 12 7 9 17 9 11 15 ...
 $ clouds       : num  0.69 0.77 0.59 0.68 0.72 0.6 0.6 0.34 0.53 0.44 ...
 $ distance_max : num  3.02 2.34 3 3.14 2.41 2.63 2.32 3.16 3.05 3.01 ...
 $ distance_mean: num  1.98 1.54 2.01 1.86 1.63 ...
 $ distance_min : num  1.06 1.04 1.08 1.06 1.06 1.06 1.01 1.06 1.06 1.06 ...
 $ humidity     : num  0.68 0.68 0.69 0.7 0.71 0.73 0.73 0.77 0.77 0.81 ...
 $ rain         : num  0 0 0 0 0 0 0 0 0 0 ...
 $ surge_max    : num  2 1 1.5 1.25 1.25 1.25 1 1 2 1.5 ...
 $ surge_mean   : num  1.12 1 1.1 1.02 1.04 ...
 $ surge_min    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ temp         : num  29.9 30.2 30 29.9 29.9 ...
 $ wind         : num  1.99 2.35 1.98 1.92 1.58 1.35 0.83 2.48 3.12 2.39 ...
 $ type         : int  0 0 0 0 0 0 0 0 0 0 ...

Dapat dilihat bahwa timestamp masih memiliki data type yang salah. Sehingga kita harus memastikan semua variabel yang kita miliki sesuai data type yang seharusnya. Oleh karena itu , pada bagian ini kita akan memperbaiki data type timestamp tersebut.

train$timestamp <- as.Date(train$timestamp, format = "%Y-%m-%d")
str(train$timestamp)
 Date[1:20355], format: "2018-11-26" "2018-11-26" "2018-11-26" "2018-11-26" "2018-11-26" ...
test$timestamp <- as.Date(test$timestamp, format = "%Y-%m-%d")
str(test$timestamp)
 Date[1:11040], format: "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" ...

Missing Value Checking and Handling

colSums(is.na(train))
    timestamp     api_calls        clouds  distance_max distance_mean 
            0             0           192             0             0 
 distance_min      humidity    price_mean          rain     surge_max 
            0           192             0           192             0 
   surge_mean     surge_min          temp          wind          type 
            0             0           192           192             0 
cat('Jumlah total Missing Value :' , sum(is.na(train)))
Jumlah total Missing Value : 960
colSums(is.na(test))
        index     timestamp     api_calls        clouds  distance_max 
            0             0             0             0             0 
distance_mean  distance_min      humidity          rain     surge_max 
            0             0             0             0             0 
   surge_mean     surge_min          temp          wind          type 
            0             0             0             0             0 
cat('Jumlah total Missing Value :' , sum(is.na(test)))
Jumlah total Missing Value : 0

Dapat dilihat dari hasil sebelumnya bahwa terdapat missing value pada beberapa kolom. Sehingga kita perlu menentukan apakah kita akan handling missing value ini dengan imputasi atau menghapus observasi / row dari missing value tersebut. Pada kesempatan kali ini kita akan mengimputasi missing value tersebut.

Tipe Tipe Imputasi :

Skala Data Metode Imputasi Contoh
Categorical Buat NA Menjadi class baru. Umur (Balita = 1 , Dewasa = 2, Lansia = 3)
Numerical (continous) Mean, Median, Mode. Umur (14,16,17,19,20,24,50,60)
install.packages("tidyverse")
install.packages("dplyr")
library(dplyr)
library(tidyverse)
library(conflicted)
Warning: package 'conflicted' was built under R version 4.4.2
train <- train %>%
  mutate(clouds = replace_na(clouds, mean(clouds, na.rm = TRUE)))

sum(is.na(train$clouds))
[1] 0
train <- train %>%
 mutate(humidity = replace_na(humidity, mean(humidity, na.rm = TRUE)))
  
train <- train %>%
  mutate(rain = replace_na(rain, mean(rain, na.rm = TRUE)))
  
train <- train %>%
  mutate(temp = replace_na(temp, mean(temp, na.rm = TRUE)))
  
 train <- train %>%
  mutate(wind = replace_na(wind, mean(wind, na.rm = TRUE)))  

Setelah semua missing value diisi jangan lupa untuk recheck kembali data yang sudah diimputasi (Tujuannya adalah untuk memastikan kolom yang missing sudah ter isi)

colSums(is.na(train))
    timestamp     api_calls        clouds  distance_max distance_mean 
            0             0             0             0             0 
 distance_min      humidity    price_mean          rain     surge_max 
            0             0             0             0             0 
   surge_mean     surge_min          temp          wind          type 
            0             0             0             0             0 
cat('Jumlah total Missing Value :' , sum(is.na(train)))
Jumlah total Missing Value : 0

Duplicated Data Detection

cat('Jumlah Observasi yang duplikat pada data train:', sum(duplicated(train)))
Jumlah Observasi yang duplikat pada data train: 0
cat('Jumlah Observasi yang duplikat pada data test:', sum(duplicated(test)))
Jumlah Observasi yang duplikat pada data test: 0

Berdasarkan hasil yang diperoleh tidak terdapat data yang duplikat pada data train dan test.