filter

Mengambil subset baris dengan kondisi logika.

Daftar isi

Topik ini membahas verba filter() dari dplyr, yaitu verba yang mengambil sebagian baris tabel berdasarkan kondisi logika. Pembahasan mencakup operator perbandingan dan keanggotaan, penggabungan beberapa kondisi, perilaku nilai NA yang khusus perlu dipahami, fungsi between() untuk kondisi rentang, serta kesalahan yang lazim terjadi. Dataset contoh didefinisikan ulang di awal topik agar seluruh contoh tetap dapat dijalankan ulang secara mandiri.

r
library(tidyverse)
nilai <- tibble::tibble(
  nama = c("Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar", "Gita", "Hana"),
  kelas = c("7A", "7B", "7A", "7B", "7A", "7B", "7A", "7B"),
  nilai = c(88, 74, 92, 65, 81, 79, 95, 70),
  kehadiran = c(0.95, 0.88, 1.00, 0.75, 0.92, 0.85, 0.98, 0.80)
)
text Keluaran
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.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

Mengambil baris dengan kondisi#

Argumen pertama filter() adalah tabelnya, dan argumen-argumen berikutnya berupa kondisi logika yang dievaluasi pada setiap baris. Kondisi ditulis dengan nama kolom tanpa tanda kutip, dan hasilnya hanya baris-baris yang kondisinya bernilai TRUE. Contoh berikut mengambil seluruh baris siswa kelas 7A.

r
nilai |> filter(kelas == "7A")
text Keluaran
# A tibble: 4 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Ali   7A       88      0.95
2 Citra 7A       92      1   
3 Eka   7A       81      0.92
4 Gita  7A       95      0.98

Tanda == membandingkan kesamaan, sedangkan tanda = tunggal adalah penugasan argumen dan tidak boleh dipakai sebagai pembanding. Kondisi dievaluasi pada seluruh baris sekaligus sebagaimana operasi vektor pada umumnya di R, sehingga satu pemanggilan menguji delapan baris tanpa perulangan eksplisit. Hasilnya selalu berupa tabel baru, sehingga tabel asalnya tetap utuh dan dapat difilter ulang dengan kondisi lain. Operator perbandingan lain bekerja dengan pola yang sama, seperti != untuk ketaksamaan, <, <=, >, dan >= untuk perbandingan besaran.

r
nilai |> filter(nilai >= 80)
text Keluaran
# A tibble: 4 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Ali   7A       88      0.95
2 Citra 7A       92      1   
3 Eka   7A       81      0.92
4 Gita  7A       95      0.98

Apabila yang diuji adalah keanggotaan pada sekumpulan nilai, operator %in% lebih ringkas daripada gabungan pembanding kesamaan. Operator ini menghasilkan TRUE untuk setiap baris yang nilainya terdapat pada vektor di sisi kanannya, dan bernilai FALSE tanpa error apabila nilainya tidak ditemukan.

r
nilai |> filter(nama %in% c("Ali", "Gita", "Zaki"))
text Keluaran
# A tibble: 2 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Ali   7A       88      0.95
2 Gita  7A       95      0.98

Nama Zaki tidak ada pada tabel, tetapi pemfilteran tetap berjalan dan menghasilkan dua baris yang cocok. Perilaku toleran inilah yang membuat %in% cocok untuk daftar yang isinya mungkin tidak semuanya terdapat pada data.

Menggabungkan beberapa kondisi#

Beberapa kondisi digabungkan dengan operator & untuk dan, | untuk atau, serta ! untuk pembalikan. Pemanggilan filter() dengan beberapa kondisi yang dipisahkan koma mempunyai makna yang sama dengan penggabungan menggunakan &, yaitu seluruh kondisinya harus terpenuhi.

r
nilai |> filter(kelas == "7A" & nilai >= 90)
text Keluaran
# A tibble: 2 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Citra 7A       92      1   
2 Gita  7A       95      0.98
r
nilai |> filter(kelas == "7A", nilai >= 90)
text Keluaran
# A tibble: 2 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Citra 7A       92      1   
2 Gita  7A       95      0.98

Kedua pemanggilan di atas menghasilkan tabel yang sama persis. Operator | mengambil baris yang memenuhi salah satu kondisinya, sehingga jumlah baris hasilnya biasanya lebih banyak daripada penggabungan dengan &. Apabila kondisi & dan | bercampur dalam satu ekspresi, operator & dievaluasi lebih dahulu menurut presedensinya, sehingga tanda kurung perlu dipakai secara eksplisit apabila maksud pengelompokannya berbeda.

r
nilai |> filter(nilai >= 90 | kehadiran < 0.8)
text Keluaran
# A tibble: 3 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Citra 7A       92      1   
2 Dewi  7B       65      0.75
3 Gita  7A       95      0.98

Pembalikan dengan ! membalik nilai kondisi, sehingga !(kelas == "7A") mengambil seluruh baris yang bukan kelas 7A. Hasil yang sama diperoleh dengan kelas != "7A", dan pilihan di antara keduanya diserahkan pada keterbacaan.

r
nilai |> filter(!(kelas == "7A"))
text Keluaran
# A tibble: 4 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Budi  7B       74      0.88
2 Dewi  7B       65      0.75
3 Fajar 7B       79      0.85
4 Hana  7B       70      0.8 

Perilaku NA dalam filter#

Kondisi yang melibatkan nilai NA tidak menghasilkan TRUE maupun FALSE, melainkan NA, karena perbandingan dengan nilai yang tidak diketahui tidak dapat dipastikan. Verba filter() hanya menyimpan baris yang kondisinya TRUE, sehingga baris yang kondisinya NA ikut terbuang tanpa pesan apa pun. Perilaku ini berakar pada logika tiga nilai R, yaitu TRUE, FALSE, dan NA sebagai perwakilan nilai yang tidak diketahui. Perbandingan apa pun yang melibatkan NA tidak dapat dipastikan jawabannya, sehingga hasilnya kembali NA dan bukan FALSE. Perilaku ini perlu dikenali karena hasil filter bisa kehilangan baris secara diam-diam. Tabel kecil berikut dipakai untuk memperlihatkannya, dengan satu skor yang belum tersedia.

r
ulangan <- tibble::tibble(
  nama = c("Ali", "Budi", "Citra"),
  skor = c(88, NA, 75)
)
ulangan |> filter(skor >= 80)
text Keluaran
# A tibble: 1 × 2
  nama   skor
  <chr> <dbl>
1 Ali      88

Hasilnya hanya memuat Ali. Baris Citra terbuang karena skornya 75 tidak memenuhi kondisi, sedangkan baris Budi yang skornya NA ikut terbuang tanpa pesan. Apabila baris bernilai NA memang ingin ditemukan, fungsi is.na() menguji keberadaan nilai NA dan menghasilkan TRUE untuk baris yang menyimpannya.

r
ulangan |> filter(is.na(skor))
text Keluaran
# A tibble: 1 × 2
  nama   skor
  <chr> <dbl>
1 Budi     NA

Cara menyertakan kembali baris bernilai NA adalah menambahkannya sebagai kondisi tersendiri pada penggabungan.

r
ulangan |> filter(skor >= 80 | is.na(skor))
text Keluaran
# A tibble: 2 × 2
  nama   skor
  <chr> <dbl>
1 Ali      88
2 Budi     NA

Rentang nilai dengan between()#

Kondisi rentang semacam nilai >= 74 & nilai <= 88 dapat ditulis lebih ringkas dengan fungsi between(). Fungsi ini menerima tiga argumen, yaitu kolom yang diuji, batas bawah, dan batas atas, dan kedua batasnya bersifat inklusif.

r
nilai |> filter(between(nilai, 74, 88))
text Keluaran
# A tibble: 4 × 4
  nama  kelas nilai kehadiran
  <chr> <chr> <dbl>     <dbl>
1 Ali   7A       88      0.95
2 Budi  7B       74      0.88
3 Eka   7A       81      0.92
4 Fajar 7B       79      0.85

Hasilnya memuat nilai 74 dan 88 yang menempel pada kedua batas, beserta 79 dan 81 yang berada di antaranya. between() tidak menambah kemampuan baru karena hasilnya identik dengan penggabungan dua perbandingan, tetapi menyatakan maksud rentang secara eksplisit sehingga kondisi lebih mudah dibaca.

Kesalahan umum#

Kesalahan yang paling sering adalah memakai tanda = sebagai pembanding, padahal tanda yang benar adalah ==.

r
nilai |> filter(kelas = "7A")
text Keluaran
Error in filter(nilai, kelas = "7A") : We detected a named input.
ℹ This usually means that you've used `=` instead of `==`.
ℹ Did you mean `kelas == "7A"`?

Pesan We detected a named input menandakan R menafsirkan kelas = "7A" sebagai pemberian argumen bernama, bukan perbandingan, dan pesannya bahkan menyertakan saran perbaikan yang berbunyi Did you mean .... Kesalahan kedua yang lazim adalah lupa bahwa NA tidak pernah lolos perbandingan, sebagaimana dijelaskan pada bagian sebelumnya, sehingga baris hilang tanpa pesan dan hasil analisis ternyata lebih sedikit daripada yang diperkirakan.

Ringkasan#

  • filter() menyimpan baris yang kondisinya TRUE, dengan kondisi yang ditulis memakai nama kolom tanpa tanda kutip.
  • Perbandingan memakai ==, !=, <, <=, >, >=, keanggotaan memakai %in%, dan penggabungan kondisi memakai &, |, serta !.
  • Kondisi yang dipisahkan koma berarti penggabungan dengan &.
  • Perbandingan dengan NA menghasilkan NA, sehingga baris tersebut terbuang tanpa pesan, dan is.na() dipakai untuk mendeteksi atau menyertakannya.
  • between(kolom, bawah, atas) menuliskan kondisi rentang inklusif secara ringkas, sedangkan tanda = sebagai pembanding menghasilkan error.

Referensi#