pivot_longer dan pivot_wider

Mengubah bentuk data antara format lebar dan format panjang.

Daftar isi

Fungsi pivot menata ulang letak nilai antarkolom tanpa mengubah isinya. Topik ini membahas pivot_longer() untuk mengubah tabel lebar menjadi tabel panjang, pivot_wider() untuk mengubahnya kembali, peredaran bolak-balik (roundtrip) yang memastikan keduanya saling melengkapi, serta argumen values_fill untuk menangani kekosongan data. Contohnya memakai rekap nilai ujian per kelas per semester yang sama dari awal sampai akhir.

Mengubah tabel lebar menjadi panjang dengan pivot_longer#

Tabel lebar menyimpan setiap semester di kolom tersendiri, seperti rekap rata-rata nilai ujian berikut. Setiap kelas menempati satu baris, sedangkan tiga semester menempati tiga kolom nilai. Perhatikan bahwa nama tiga kolom terakhir adalah nilai, bukan nama variabel.

r Contoh: rekap nilai dalam bentuk lebar
library(tidyverse)
rekap <- tribble(
  ~kelas, ~`Ganjil 2024`, ~`Genap 2024`, ~`Ganjil 2025`,
  "7A",   78,             82,            80,
  "7B",   74,             79,            77
)
rekap
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
# A tibble: 2 × 4
  kelas `Ganjil 2024` `Genap 2024` `Ganjil 2025`
  <chr>         <dbl>        <dbl>         <dbl>
1 7A               78           82            80
2 7B               74           79            77

Nama kolom Ganjil 2024, Genap 2024, dan Ganjil 2025 sebenarnya adalah nilai dari variabel semester, sedangkan isinya adalah nilai dari variabel rata_rata. Fungsi pivot_longer() memindahkan nama-nama kolom tersebut beserta isinya sekaligus. Argumen cols menentukan kolom yang dipindahkan, argumen names_to menamai kolom baru penampung nama kolom lama, dan argumen values_to menamai kolom penampung isinya.

r Contoh: memindahkan kolom semester menjadi baris
panjang <- pivot_longer(rekap, cols = -kelas, names_to = "semester", values_to = "rata_rata")
panjang
text Keluaran
# A tibble: 6 × 3
  kelas semester    rata_rata
  <chr> <chr>           <dbl>
1 7A    Ganjil 2024        78
2 7A    Genap 2024         82
3 7A    Ganjil 2025        80
4 7B    Ganjil 2024        74
5 7B    Genap 2024         79
6 7B    Ganjil 2025        77

Selektor pada cols mengikuti aturan dplyr. Tanda minus pada cols = -kelas berarti seluruh kolom kecuali kelas dipindahkan, sedangkan selektor lain seperti starts_with() juga dapat dipakai apabila kolom nilai berbagi awalan nama. Hasilnya berupa enam baris, yaitu dua kelas dikali tiga semester, dengan satu nilai rata_rata per baris.

Data dalam bentuk lebar sering dihasilkan lembar kerja yang disusun untuk dibaca manusia, sehingga keadaan ini ditemui hampir setiap kali data diimpor. Pivot pertama yang dilakukan pada data baru dengan demikian biasanya berarah dari lebar ke panjang, sebelum penghitungan lain dimulai.

Nama yang tersisa pada kolom semester juga dapat dirapikan dengan argumen names_prefix. Apabila kolom semula bernama ganjil_2024 dan ganjil_2025, argumen names_prefix = "ganjil_" membuang awalan itu dari setiap nama, sehingga isi kolom baru tidak membawa ulang teks yang sudah tersirat pada namanya.

Mengubah tabel panjang menjadi lebar dengan pivot_wider#

Perubahan sebaliknya dilakukan oleh pivot_wider(). Argumen names_from menyebut kolom yang isinya menjadi nama kolom baru. Argumen values_from menyebut kolom yang isinya mengisi sel-sel kolom baru tersebut. Penerapan keduanya pada tabel panjang mengembalikan bentuk semula.

r Contoh: menyebarkan kolom semester menjadi kolom
pivot_wider(panjang, names_from = semester, values_from = rata_rata)
text Keluaran
# A tibble: 2 × 4
  kelas `Ganjil 2024` `Genap 2024` `Ganjil 2025`
  <chr>         <dbl>        <dbl>         <dbl>
1 7A               78           82            80
2 7B               74           79            77

Kolom semester musnah karena isinya telah menyebar menjadi tiga kolom, dan tabel hasil hanya memuat dua baris, satu per kelas. Urutan kolom hasil mengikuti urutan kemunculan nilainya pada data, sehingga Ganjil 2024, Genap 2024, dan Ganjil 2025 tampil berurutan. Fungsi ini lazim dipakai menjelang penyajian, misalnya sebelum tabel dipindahkan ke laporan atau lembar kerja yang dibaca manusia.

Memeriksa peredaran bolak-balik#

Apabila pivot_wider() dan pivot_longer() dipasangkan dengan argumen yang saling mencerminkan, hasil akhirnya identik dengan data awal. Sifat ini disebut peredaran bolak-balik dan menjadi pemeriksaan cepat apabila keraguan muncul tentang kebenaran hasil pivot. Kedua fungsi memang saling berkebalikan, sehingga kesalahan pada satu sisi langsung terlihat pada perbandingannya.

r Contoh: peredaran bolak-balik lebar ke panjang
identical(
  pivot_longer(pivot_wider(panjang, names_from = semester, values_from = rata_rata),
               cols = -kelas, names_to = "semester", values_to = "rata_rata"),
  panjang
)
text Keluaran
[1] TRUE

Nilai TRUE pada keluaran berarti tabel hasil peredaran identik dengan tabel panjang awal, termasuk urutan kolom dan tipe datanya. Pemeriksaan seperti ini murah dilakukan, tetapi cukup untuk menangkap kesalahan argumen yang sering terjadi, misalnya names_to dan values_to yang tertukar. Apabila hasilnya FALSE, bandingkan nama dan urutan kolom kedua tabel dengan names() sebelum mencari kesalahan argumennya.

Mengisi kekosongan data dengan values_fill#

Tabel panjang yang nyata sering tidak lengkap. Kekosongan seperti ini wajar terjadi, misalnya karena ujian satu kelas belum dilaksanakan atau datanya gagal terekam. Apabila satu kombinasi kelas dan semester tidak memiliki baris, pivot_wider() menyisakan sel kosong berupa NA.

r Contoh: tabel panjang dengan satu kombinasi hilang
panjang_kurang <- tribble(
  ~kelas, ~semester, ~rata_rata,
  "7A",   "Ganjil",  78,
  "7A",   "Genap",   82,
  "7B",   "Ganjil",  74
)
pivot_wider(panjang_kurang, names_from = semester, values_from = rata_rata)
text Keluaran
# A tibble: 2 × 3
  kelas Ganjil Genap
  <chr>  <dbl> <dbl>
1 7A        78    82
2 7B        74    NA

Nilai NA pada kolom Genap menandakan kelas 7B belum memiliki nilai rata_rata untuk semester tersebut, dan posisi selnya tetap dipertahankan agar tabel tetap sejajar. Apabila kekosongan dibiarkan, penghitungan lanjutan yang menyentuh kolom itu ikut menghasilkan NA. Argumen values_fill mengganti kekosongan semacam ini dengan nilai tertentu.

r Contoh: values_fill mengisi sel kosong
pivot_wider(panjang_kurang, names_from = semester, values_from = rata_rata, values_fill = 0)
text Keluaran
# A tibble: 2 × 3
  kelas Ganjil Genap
  <chr>  <dbl> <dbl>
1 7A        78    82
2 7B        74     0

Argumen values_fill menerima satu nilai untuk seluruh kolom nilai, atau vektor bernama (named vector) untuk mengatur isian per kolom. Isian yang umum adalah 0 untuk pencacahan kejadian dan teks kosong untuk kolom karakter. Sebelum memilih isian, tentukan dahulu apakah kekosongan berarti data belum ada atau data memang bernilai nol, karena kedua makna itu menuntut perlakuan berbeda pada analisis.

Kesalahan umum#

Kesalahan pertama adalah memindahkan kolom identitas bersama kolom nilainya. Apabila cols menyertakan kolom kelas, isi kelas ikut dipindahkan ke kolom nilai, dan karena kelas bertipe character sedangkan rata_rata bertipe double, penggabungan kedua tipe itu langsung gagal. Selektor yang terlalu luas, misalnya everything(), adalah penyebab yang paling sering.

r Contoh: kolom identitas ikut dipindahkan
pivot_longer(rekap, cols = everything(), names_to = "semester", values_to = "rata_rata")
text Keluaran
Error in pivot_longer(rekap, cols = everything(), names_to = "semester",      values_to = "rata_rata") : Can't combine `kelas` <character> and `Ganjil 2024` <double>.

Pesan Can't combine berarti kolom-kolom yang dipindahkan bertipe berbeda sehingga tidak dapat ditempatkan pada satu kolom nilai. Perbaikannya adalah menyisihkan kolom identitas dengan cols = -kelas, sehingga hanya kolom nilai yang dipindahkan. Apabila memang kolom campuran perlu dipertahankan, samakan tipe kolom-kolomnya terlebih dahulu lewat konversi.

Kesalahan kedua adalah memanggil pivot_wider() pada tabel panjang yang memuat kunci ganda, yaitu kombinasi kelas dan semester yang muncul lebih dari satu kali. Kunci ganda lazim muncul ketika pengukuran diulang atau data digabung dari lebih dari satu sumber. tidyr tidak menebak cara merapatkan nilainya, sehingga kolom hasil berubah menjadi list dan sebuah peringatan dikeluarkan.

r Contoh: kunci ganda pada pivot_wider
ganda <- tribble(
  ~kelas, ~semester, ~rata_rata,
  "7A",   "Ganjil",  78,
  "7A",   "Ganjil",  80
)
pivot_wider(ganda, names_from = semester, values_from = rata_rata)
text Keluaran
Warning: Values from `rata_rata` are not uniquely identified; output will contain
list-cols.
• Use `values_fn = list` to suppress this warning.
• Use `values_fn = {summary_fun}` to summarise duplicates.
• Use the following dplyr code to identify duplicates.
  {data} |>
  dplyr::summarise(n = dplyr::n(), .by = c(kelas, semester)) |>
  dplyr::filter(n > 1L)
# A tibble: 1 × 2
  kelas Ganjil   
  <chr> <list>   
1 7A    <dbl [2]>

Peringatan Values from rata_rata are not uniquely identified berarti satu sel akan menampung dua nilai sekaligus. Perbaikan yang benar dilakukan di hulu, yaitu merapatkan nilai ganda terlebih dahulu dengan group_by() dan summarize(), misalnya mengambil rata-ratanya, sehingga setiap kombinasi kelas dan semester hanya muncul satu kali. Argumen values_fn memang dapat menengahi duplikat saat pivot, tetapi keputusan merapatkan data sebaiknya disadari, bukan tersembunyi di dalam pembentukan bentuk.

Ringkasan#

  • pivot_longer() memindahkan kolom terpilih menjadi dua kolom baru, yaitu nama (names_to) dan nilai (values_to).
  • pivot_wider() menyebar satu kolom menjadi banyak kolom berdasarkan names_from dan values_from.
  • Pasangan keduanya yang argumennya saling mencerminkan mengembalikan data awal, dan fungsi identical() memeriksanya.
  • Kombinasi tanpa baris menjadi NA, dan values_fill menggantinya dengan nilai tertentu.
  • Kunci ganda pada pivot_wider() menghasilkan peringatan dan kolom list, sehingga duplikatnya dirapatkan terlebih dahulu.

Referensi#