Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider
Paket lebih rapi termasuk dalam inti salah satu perpustakaan paling populer dalam bahasa R - rapi.
Tujuan utama dari paket ini adalah untuk membawa data ke dalam bentuk yang akurat.
Sudah tersedia di Habré publikasi didedikasikan untuk paket ini, tetapi sudah ada sejak tahun 2015. Dan saya ingin memberi tahu Anda tentang perubahan terkini, yang diumumkan beberapa hari lalu oleh penulisnya, Hedley Wickham.
SJK: Akankah Gather() dan Spread() tidak digunakan lagi?
Hadley Wickham: Sampai batas tertentu. Kami tidak akan lagi merekomendasikan penggunaan fungsi-fungsi ini dan memperbaiki bug di dalamnya, tetapi fungsi-fungsi tersebut akan terus ada dalam paket dalam kondisi saat ini.
kadar
Jika Anda tertarik dengan analisis data, Anda mungkin tertarik dengan saya Telegram и Youtube saluran. Sebagian besar konten didedikasikan untuk bahasa R.
target lebih rapi — membantu Anda membawa data ke bentuk yang disebut rapi. Data rapi adalah data yang:
Setiap variabel ada dalam kolom.
Setiap pengamatan adalah sebuah string.
Setiap nilai adalah sel.
Jauh lebih mudah dan nyaman untuk bekerja dengan data yang disajikan dalam data yang rapi saat melakukan analisis.
Fungsi utama termasuk dalam paket rapir
Tidir berisi serangkaian fungsi yang dirancang untuk mengubah tabel:
fill() — mengisi nilai yang hilang pada kolom dengan nilai sebelumnya;
separate() — membagi satu bidang menjadi beberapa menggunakan pemisah;
unite() — melakukan operasi menggabungkan beberapa bidang menjadi satu, tindakan kebalikan dari fungsi tersebut separate();
pivot_longer() — fungsi yang mengubah data dari format lebar ke format panjang;
pivot_wider() - fungsi yang mengubah data dari format panjang ke format lebar. Operasi kebalikan dari fungsi yang dilakukan pivot_longer().
gather()usang — fungsi yang mengubah data dari format lebar ke format panjang;
spread()usang - fungsi yang mengubah data dari format panjang ke format lebar. Operasi kebalikan dari fungsi yang dilakukan gather().
Konsep baru untuk mengkonversi data dari format lebar ke panjang dan sebaliknya
Sebelumnya, fungsi digunakan untuk transformasi semacam ini gather() и spread(). Selama bertahun-tahun keberadaan fungsi-fungsi ini, menjadi jelas bahwa bagi sebagian besar pengguna, termasuk pembuat paket, nama fungsi-fungsi ini dan argumennya tidak terlalu jelas, dan menyebabkan kesulitan dalam menemukannya dan memahami fungsi mana yang dikonversi. bingkai tanggal dari format lebar ke panjang, dan sebaliknya.
Dalam hal ini, di lebih rapi Dua fungsi baru dan penting telah ditambahkan yang dirancang untuk mengubah kerangka tanggal.
Fitur baru pivot_longer() и pivot_wider() terinspirasi oleh beberapa fitur dalam paket cdata, dibuat oleh John Mount dan Nina Zumel.
Menginstal rapir versi terbaru 0.8.3.9000
Untuk menginstal paket versi terbaru dan terkini lebih rapi0.8.3.9000, jika fitur baru tersedia, gunakan kode berikut.
devtools::install_github("tidyverse/tidyr")
Pada saat penulisan, fungsi-fungsi ini hanya tersedia dalam versi dev paket di GitHub.
Transisi ke fitur baru
Sebenarnya, tidak sulit untuk mentransfer skrip lama untuk bekerja dengan fungsi baru, untuk pemahaman yang lebih baik, saya akan mengambil contoh dari dokumentasi fungsi lama dan menunjukkan bagaimana operasi yang sama dilakukan menggunakan fungsi baru. pivot_*() fungsi.
Konversi format lebar ke format panjang.
Contoh kode dari dokumentasi fungsi pengumpulan
# example
library(dplyr)
stocks <- data.frame(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
# old
stocks_gather <- stocks %>% gather(key = stock,
value = price,
-time)
# new
stocks_long <- stocks %>% pivot_longer(cols = -time,
names_to = "stock",
values_to = "price")
Mengubah format panjang ke format lebar.
Contoh kode dari dokumentasi fungsi penyebaran
# old
stocks_spread <- stocks_gather %>% spread(key = stock,
value = price)
# new
stock_wide <- stocks_long %>% pivot_wider(names_from = "stock",
values_from = "price")
Karena dalam contoh bekerja dengan di atas pivot_longer() и pivot_wider(), di tabel asli saham tidak ada kolom yang tercantum dalam argumen nama_ke и nilai_ke nama mereka harus dalam tanda petik.
Tabel yang akan membantu Anda dengan mudah mengetahui cara beralih bekerja dengan konsep baru lebih rapi.
Catatan dari penulis
Semua teks di bawah ini adaptif, bahkan menurut saya terjemahan gratis sketsa dari situs resmi perpustakaan rapiverse.
Contoh sederhana mengubah data dari format lebar ke format panjang
pivot_longer () — membuat kumpulan data lebih panjang dengan mengurangi jumlah kolom dan menambah jumlah baris.
Untuk menjalankan contoh yang disajikan dalam artikel, Anda harus menghubungkan paket yang diperlukan terlebih dahulu:
library(tidyr)
library(dplyr)
library(readr)
Katakanlah kita mempunyai tabel berisi hasil survei yang (antara lain) menanyakan orang-orang tentang agama dan pendapatan tahunan mereka:
Tabel ini memuat data agama responden dalam baris-baris, dan tingkat pendapatan tersebar pada nama-nama kolom. Jumlah responden dari masing-masing kategori disimpan dalam nilai sel pada titik persimpangan agama dan tingkat pendapatan. Untuk menjadikan tabel menjadi format yang rapi dan benar, cukup menggunakan pivot_longer():
Argumen pertama kerah, menjelaskan kolom mana yang perlu digabungkan. Dalam hal ini, semua kolom kecuali waktu.
Argumen nama_ke memberikan nama variabel yang akan dibuat dari nama kolom yang kita gabungkan.
nilai_ke memberi nama variabel yang akan dibuat dari data yang disimpan dalam nilai sel kolom yang digabungkan.
Spesifikasi
Ini adalah fungsi baru dari paket tersebut lebih rapi, yang sebelumnya tidak tersedia saat bekerja dengan fungsi lama.
Spesifikasi adalah bingkai data, setiap barisnya berhubungan dengan satu kolom dalam bingkai tanggal keluaran baru, dan dua kolom khusus yang dimulai dengan:
. Nama berisi nama kolom asli.
.nilai berisi nama kolom yang akan berisi nilai sel.
Kolom spesifikasi lainnya mencerminkan bagaimana kolom baru akan menampilkan nama kolom terkompresi . Nama.
Spesifikasi menjelaskan metadata yang disimpan dalam nama kolom, dengan satu baris untuk setiap kolom dan satu kolom untuk setiap variabel, dikombinasikan dengan nama kolom, definisi ini mungkin tampak membingungkan saat ini, tetapi setelah melihat beberapa contoh akan menjadi lebih banyak lebih jelas.
Inti dari spesifikasinya adalah Anda dapat mengambil, memodifikasi, dan menentukan metadata baru untuk kerangka data yang sedang dikonversi.
Untuk bekerja dengan spesifikasi saat mengonversi tabel dari format lebar ke format panjang, gunakan fungsi tersebut pivot_longer_spec().
Cara kerja fungsi ini adalah ia mengambil kerangka tanggal apa pun dan menghasilkan metadatanya dengan cara yang dijelaskan di atas.
Sebagai contoh, mari kita ambil himpunan data who yang disediakan bersama paket lebih rapi. Dataset ini berisi informasi yang diberikan oleh organisasi kesehatan internasional mengenai kejadian tuberkulosis.
who
#> # A tibble: 7,240 x 60
#> country iso2 iso3 year new_sp_m014 new_sp_m1524 new_sp_m2534
#> <chr> <chr> <chr> <int> <int> <int> <int>
#> 1 Afghan… AF AFG 1980 NA NA NA
#> 2 Afghan… AF AFG 1981 NA NA NA
#> 3 Afghan… AF AFG 1982 NA NA NA
#> 4 Afghan… AF AFG 1983 NA NA NA
#> 5 Afghan… AF AFG 1984 NA NA NA
#> 6 Afghan… AF AFG 1985 NA NA NA
#> 7 Afghan… AF AFG 1986 NA NA NA
#> 8 Afghan… AF AFG 1987 NA NA NA
#> 9 Afghan… AF AFG 1988 NA NA NA
#> 10 Afghan… AF AFG 1989 NA NA NA
#> # … with 7,230 more rows, and 53 more variables
Mari kita buat spesifikasinya.
spec <- who %>%
pivot_longer_spec(new_sp_m014:newrel_f65, values_to = "count")
Lapangan negara, iso2, iso3 sudah menjadi variabel. Tugas kita adalah membalik kolom dengan baru_sp_m014 pada newrel_f65.
Nama kolom ini menyimpan informasi berikut:
Awalan new_ menunjukkan bahwa kolom tersebut berisi data kasus baru tuberkulosis, kerangka tanggal saat ini hanya berisi informasi tentang penyakit baru, sehingga awalan ini dalam konteks saat ini tidak memiliki arti apa pun.
sp/rel/sp/ep menjelaskan metode untuk mendiagnosis suatu penyakit.
m/f jenis kelamin pasien.
014/1524/2535/3544/4554/65 rentang usia pasien.
Kita dapat membagi kolom ini menggunakan fungsi tersebut extract()menggunakan ekspresi reguler.
#> # A tibble: 56 x 5
#> .name .value diagnosis gender age
#> <chr> <chr> <chr> <chr> <chr>
#> 1 new_sp_m014 count sp m 014
#> 2 new_sp_m1524 count sp m 1524
#> 3 new_sp_m2534 count sp m 2534
#> 4 new_sp_m3544 count sp m 3544
#> 5 new_sp_m4554 count sp m 4554
#> 6 new_sp_m5564 count sp m 5564
#> 7 new_sp_m65 count sp m 65
#> 8 new_sp_f014 count sp f 014
#> 9 new_sp_f1524 count sp f 1524
#> 10 new_sp_f2534 count sp f 2534
#> # … with 46 more rows
Harap perhatikan kolomnya . Nama harus tetap tidak berubah karena ini adalah indeks kami ke dalam nama kolom kumpulan data asli.
Jenis kelamin dan usia (kolom jenis kelamin и usia) memiliki nilai yang tetap dan diketahui, jadi disarankan untuk mengonversi kolom berikut menjadi faktor:
Terakhir, untuk menerapkan spesifikasi yang kami buat pada kerangka tanggal asli yang kita perlu menggunakan argumen spek dalam fungsi pivot_longer().
who %>% pivot_longer(spec = spec)
#> # A tibble: 405,440 x 8
#> country iso2 iso3 year diagnosis gender age count
#> <chr> <chr> <chr> <int> <chr> <fct> <ord> <int>
#> 1 Afghanistan AF AFG 1980 sp m 014 NA
#> 2 Afghanistan AF AFG 1980 sp m 1524 NA
#> 3 Afghanistan AF AFG 1980 sp m 2534 NA
#> 4 Afghanistan AF AFG 1980 sp m 3544 NA
#> 5 Afghanistan AF AFG 1980 sp m 4554 NA
#> 6 Afghanistan AF AFG 1980 sp m 5564 NA
#> 7 Afghanistan AF AFG 1980 sp m 65 NA
#> 8 Afghanistan AF AFG 1980 sp f 014 NA
#> 9 Afghanistan AF AFG 1980 sp f 1524 NA
#> 10 Afghanistan AF AFG 1980 sp f 2534 NA
#> # … with 405,430 more rows
Segala sesuatu yang baru saja kami lakukan dapat digambarkan secara skematis sebagai berikut:
Spesifikasi menggunakan beberapa nilai (.value)
Pada contoh di atas, kolom spesifikasi .nilai hanya berisi satu nilai, dalam banyak kasus hal ini terjadi.
Namun terkadang situasi mungkin muncul ketika Anda perlu mengumpulkan data dari kolom dengan tipe data nilai yang berbeda. Menggunakan fungsi warisan spread() ini akan cukup sulit untuk dilakukan.
Contoh di bawah ini diambil dari sketsa ke paket tabel data.
Bingkai tanggal yang dibuat berisi data anak dari satu keluarga di setiap baris. Keluarga mungkin memiliki satu atau dua anak. Untuk setiap anak, data disediakan berdasarkan tanggal lahir dan jenis kelamin, dan data untuk setiap anak ditempatkan di kolom terpisah, tugas kita adalah membawa data ini ke format yang benar untuk dianalisis.
Harap dicatat bahwa kami memiliki dua variabel dengan informasi tentang setiap anak: jenis kelamin dan tanggal lahir mereka (kolom dengan awalan baptisan berisi tanggal lahir, kolom dengan awalan jenis kelamin memuat jenis kelamin anak). Hasil yang diharapkan adalah mereka muncul di kolom terpisah. Kita dapat melakukan ini dengan membuat spesifikasi di kolom mana .value akan memiliki dua arti yang berbeda.
spec <- family %>%
pivot_longer_spec(-family) %>%
separate(col = name, into = c(".value", "child"))%>%
mutate(child = parse_number(child))
#> # A tibble: 4 x 3
#> .name .value child
#> <chr> <chr> <dbl>
#> 1 dob_child1 dob 1
#> 2 dob_child2 dob 2
#> 3 gender_child1 gender 1
#> 4 gender_child2 gender 2
Jadi, mari kita lihat langkah demi langkah tindakan yang dilakukan oleh kode di atas.
pivot_longer_spec(-family) — membuat spesifikasi yang mengkompres semua kolom yang ada kecuali kolom keluarga.
separate(col = name, into = c(".value", "child")) - membagi kolom . Nama, yang berisi nama bidang sumber, menggunakan garis bawah dan memasukkan nilai yang dihasilkan ke dalam kolom .nilai и anak.
mutate(child = parse_number(child)) — mengubah nilai bidang anak dari tipe data teks ke numerik.
Sekarang kita dapat menerapkan spesifikasi yang dihasilkan ke kerangka data asli dan membawa tabel ke bentuk yang diinginkan.
Kami menggunakan argumen na.rm = TRUE, karena bentuk data saat ini memaksa pembuatan baris tambahan untuk observasi yang tidak ada. Karena keluarga 2 hanya memiliki satu anak, na.rm = TRUE menjamin bahwa keluarga 2 akan memiliki satu baris dalam output.
Mengonversi bingkai tanggal dari format panjang ke lebar
pivot_wider() - adalah transformasi terbalik, dan sebaliknya menambah jumlah kolom bingkai tanggal dengan mengurangi jumlah baris.
Transformasi semacam ini sangat jarang digunakan untuk membawa data ke dalam bentuk yang akurat, namun teknik ini dapat berguna untuk membuat tabel pivot yang digunakan dalam presentasi, atau untuk integrasi dengan beberapa alat lainnya.
Sebenarnya fungsinya pivot_longer() и pivot_wider() simetris, dan menghasilkan aksi yang saling bertolak belakang, yaitu: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) akan mengembalikan df asli.
Contoh paling sederhana untuk mengonversi tabel ke format lebar
Untuk mendemonstrasikan cara kerja fungsi pivot_wider() kami akan menggunakan kumpulan data pertemuan_ikan, yang menyimpan informasi tentang bagaimana berbagai stasiun mencatat pergerakan ikan di sepanjang sungai.
#> # A tibble: 114 x 3
#> fish station seen
#> <fct> <fct> <int>
#> 1 4842 Release 1
#> 2 4842 I80_1 1
#> 3 4842 Lisbon 1
#> 4 4842 Rstr 1
#> 5 4842 Base_TD 1
#> 6 4842 BCE 1
#> 7 4842 BCW 1
#> 8 4842 BCE2 1
#> 9 4842 BCW2 1
#> 10 4842 MAE 1
#> # … with 104 more rows
Umumnya, tabel ini akan lebih informatif dan mudah digunakan jika Anda menyajikan informasi untuk setiap stasiun dalam kolom terpisah.
fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
#> # A tibble: 19 x 12
#> fish Release I80_1 Lisbon Rstr Base_TD BCE BCW BCE2 BCW2 MAE
#> <fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
#> 1 4842 1 1 1 1 1 1 1 1 1 1
#> 2 4843 1 1 1 1 1 1 1 1 1 1
#> 3 4844 1 1 1 1 1 1 1 1 1 1
#> 4 4845 1 1 1 1 1 NA NA NA NA NA
#> 5 4847 1 1 1 NA NA NA NA NA NA NA
#> 6 4848 1 1 1 1 NA NA NA NA NA NA
#> 7 4849 1 1 NA NA NA NA NA NA NA NA
#> 8 4850 1 1 NA 1 1 1 1 NA NA NA
#> 9 4851 1 1 NA NA NA NA NA NA NA NA
#> 10 4854 1 1 NA NA NA NA NA NA NA NA
#> # … with 9 more rows, and 1 more variable: MAW <int>
Kumpulan data ini hanya mencatat informasi ketika ikan telah terdeteksi oleh stasiun, yaitu ketika ikan terdeteksi oleh stasiun. jika ada ikan yang tidak dicatat oleh beberapa stasiun, maka data ini tidak akan ada di tabel. Artinya outputnya akan diisi dengan NA.
Namun dalam hal ini kita mengetahui bahwa tidak adanya catatan berarti ikan tersebut tidak terlihat, sehingga kita dapat menggunakan argumen tersebut nilai_isi dalam fungsi pivot_wider() dan isi nilai yang hilang ini dengan nol:
Menghasilkan nama kolom dari beberapa variabel sumber
Bayangkan kita memiliki tabel yang berisi kombinasi produk, negara, dan tahun. Untuk menghasilkan kerangka tanggal pengujian, Anda dapat menjalankan kode berikut:
df <- expand_grid(
product = c("A", "B"),
country = c("AI", "EI"),
year = 2000:2014
) %>%
filter((product == "A" & country == "AI") | product == "B") %>%
mutate(value = rnorm(nrow(.)))
#> # A tibble: 45 x 4
#> product country year value
#> <chr> <chr> <int> <dbl>
#> 1 A AI 2000 -2.05
#> 2 A AI 2001 -0.676
#> 3 A AI 2002 1.60
#> 4 A AI 2003 -0.353
#> 5 A AI 2004 -0.00530
#> 6 A AI 2005 0.442
#> 7 A AI 2006 -0.610
#> 8 A AI 2007 -2.77
#> 9 A AI 2008 0.899
#> 10 A AI 2009 -0.106
#> # … with 35 more rows
Tugas kita adalah memperluas kerangka data sehingga satu kolom berisi data untuk setiap kombinasi produk dan negara. Untuk melakukan ini, cukup sampaikan argumennya nama_dari vektor yang berisi nama bidang yang akan digabungkan.
Anda juga dapat menerapkan spesifikasi pada suatu fungsi pivot_wider(). Namun ketika diserahkan ke pivot_wider() spesifikasi melakukan konversi sebaliknya pivot_longer(): Kolom yang ditentukan dalam . Nama, menggunakan nilai dari .nilai dan kolom lainnya.
Untuk kumpulan data ini, Anda dapat membuat spesifikasi khusus jika Anda ingin setiap kemungkinan kombinasi negara dan produk memiliki kolomnya sendiri, bukan hanya kolom yang ada dalam data:
#> # A tibble: 4 x 4
#> .name product country .value
#> <chr> <chr> <chr> <chr>
#> 1 A_AI A AI value
#> 2 A_EI A EI value
#> 3 B_AI B AI value
#> 4 B_EI B EI value
df %>% pivot_wider(spec = spec) %>% head()
#> # A tibble: 6 x 5
#> year A_AI A_EI B_AI B_EI
#> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 2000 -2.05 NA 0.607 1.20
#> 2 2001 -0.676 NA 1.65 -0.114
#> 3 2002 1.60 NA -0.0245 0.501
#> 4 2003 -0.353 NA 1.30 -0.459
#> 5 2004 -0.00530 NA 0.921 -0.0589
#> 6 2005 0.442 NA -1.55 0.594
Beberapa contoh lanjutan dalam bekerja dengan konsep rapi baru
Membersihkan data menggunakan kumpulan data Pendapatan dan Sewa Sensus AS sebagai contoh.
Himpunan data pendapatan_sewa_kami berisi informasi pendapatan rata-rata dan sewa untuk setiap negara bagian di AS pada tahun 2017 (kumpulan data tersedia dalam paket sensus rapi).
us_rent_income
#> # A tibble: 104 x 5
#> GEOID NAME variable estimate moe
#> <chr> <chr> <chr> <dbl> <dbl>
#> 1 01 Alabama income 24476 136
#> 2 01 Alabama rent 747 3
#> 3 02 Alaska income 32940 508
#> 4 02 Alaska rent 1200 13
#> 5 04 Arizona income 27517 148
#> 6 04 Arizona rent 972 4
#> 7 05 Arkansas income 23789 165
#> 8 05 Arkansas rent 709 5
#> 9 06 California income 29454 109
#> 10 06 California rent 1358 3
#> # … with 94 more rows
Dalam bentuk dimana data disimpan dalam dataset pendapatan_sewa_kami bekerja dengan mereka sangat merepotkan, jadi kami ingin membuat kumpulan data dengan kolom: menyewa, sewa_moe, bagaimana, pendapatan_moe. Ada banyak cara untuk membuat spesifikasi ini, tetapi yang terpenting adalah kita perlu menghasilkan setiap kombinasi nilai variabel dan perkiraan/moedan kemudian menghasilkan nama kolom.
Terkadang membawa kumpulan data ke bentuk yang diinginkan memerlukan beberapa langkah.
Himpunan data dunia_bank_pop berisi data Bank Dunia tentang populasi setiap negara antara tahun 2000 dan 2018.
Tujuan kami adalah membuat kumpulan data yang rapi dengan setiap variabel di kolomnya sendiri. Tidak jelas langkah apa yang diperlukan, tapi kita akan mulai dengan masalah yang paling jelas: tahun tersebar di beberapa kolom.
Untuk memperbaikinya, Anda perlu menggunakan fungsi tersebut pivot_longer().
Langkah selanjutnya adalah melihat variabel indikator. pop2 %>% count(indicator)
#> # A tibble: 4 x 2
#> indicator n
#> <chr> <int>
#> 1 SP.POP.GROW 4752
#> 2 SP.POP.TOTL 4752
#> 3 SP.URB.GROW 4752
#> 4 SP.URB.TOTL 4752
Dimana SP.POP.GROW adalah pertumbuhan penduduk, SP.POP.TOTL adalah jumlah penduduk, dan SP.URB. *sama saja, namun hanya untuk perkotaan. Mari kita bagi nilai-nilai ini menjadi dua variabel: luas - luas (total atau perkotaan) dan variabel yang berisi data aktual (penduduk atau pertumbuhan):
Membuat tabulasi daftar ini cukup sulit karena tidak ada variabel yang mengidentifikasi data mana yang termasuk dalam kontak mana. Kita dapat memperbaikinya dengan mencatat bahwa data untuk setiap kontak baru dimulai dengan "nama", sehingga kita dapat membuat pengidentifikasi unik dan menambahkannya satu setiap kali kolom bidang berisi nilai "nama":
#> # A tibble: 6 x 3
#> field value person_id
#> <chr> <chr> <int>
#> 1 name Jiena McLellan 1
#> 2 company Toyota 1
#> 3 name John Smith 2
#> 4 company google 2
#> 5 email [email protected] 2
#> 6 name Huxley Ratcliffe 3
Sekarang kita memiliki ID unik untuk setiap kontak, kita dapat mengubah bidang dan nilai menjadi kolom:
#> # A tibble: 3 x 4
#> person_id name company email
#> <int> <chr> <chr> <chr>
#> 1 1 Jiena McLellan Toyota <NA>
#> 2 2 John Smith google [email protected]
#> 3 3 Huxley Ratcliffe <NA> <NA>
Kesimpulan
Pendapat pribadi saya adalah konsep baru lebih rapi benar-benar lebih intuitif, dan fungsionalitasnya jauh lebih unggul dibandingkan fungsi lama spread() и gather(). Saya harap artikel ini membantu Anda mengatasinya pivot_longer() и pivot_wider().