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.

Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider

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.

Konsep TidyData

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 rapi 0.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.

Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider

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.

Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider

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:

#> # A tibble: 18 x 11
#>    religion `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k`
#>    <chr>      <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
#>  1 Agnostic      27        34        60        81        76       137
#>  2 Atheist       12        27        37        52        35        70
#>  3 Buddhist      27        21        30        34        33        58
#>  4 Catholic     418       617       732       670       638      1116
#>  5 Don’t k…      15        14        15        11        10        35
#>  6 Evangel…     575       869      1064       982       881      1486
#>  7 Hindu          1         9         7         9        11        34
#>  8 Histori…     228       244       236       238       197       223
#>  9 Jehovah…      20        27        24        24        21        30
#> 10 Jewish        19        19        25        25        30        95
#> # … with 8 more rows, and 4 more variables: `$75-100k` <dbl>,
#> #   `$100-150k` <dbl>, `>150k` <dbl>, `Don't know/refused` <dbl>

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():

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")
#> # A tibble: 180 x 3
#>    religion income             count
#>    <chr>    <chr>              <dbl>
#>  1 Agnostic <$10k                 27
#>  2 Agnostic $10-20k               34
#>  3 Agnostic $20-30k               60
#>  4 Agnostic $30-40k               81
#>  5 Agnostic $40-50k               76
#>  6 Agnostic $50-75k              137
#>  7 Agnostic $75-100k             122
#>  8 Agnostic $100-150k            109
#>  9 Agnostic >150k                 84
#> 10 Agnostic Don't know/refused    96
#> # … with 170 more rows

Argumen Fungsi 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")

#> # A tibble: 56 x 3
#>    .name        .value name        
#>    <chr>        <chr>  <chr>       
#>  1 new_sp_m014  count  new_sp_m014 
#>  2 new_sp_m1524 count  new_sp_m1524
#>  3 new_sp_m2534 count  new_sp_m2534
#>  4 new_sp_m3544 count  new_sp_m3544
#>  5 new_sp_m4554 count  new_sp_m4554
#>  6 new_sp_m5564 count  new_sp_m5564
#>  7 new_sp_m65   count  new_sp_m65  
#>  8 new_sp_f014  count  new_sp_f014 
#>  9 new_sp_f1524 count  new_sp_f1524
#> 10 new_sp_f2534 count  new_sp_f2534
#> # … with 46 more rows

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.

spec <- spec %>%
        extract(name, c("diagnosis", "gender", "age"), "new_?(.*)_(.)(.*)")

#> # 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:

spec <-  spec %>%
            mutate(
              gender = factor(gender, levels = c("f", "m")),
              age = factor(age, levels = unique(age), ordered = TRUE)
            ) 

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:

Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider

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.

Mari buat kerangka data pelatihan.

family <- tibble::tribble(
  ~family,  ~dob_child1,  ~dob_child2, ~gender_child1, ~gender_child2,
       1L, "1998-11-26", "2000-01-29",             1L,             2L,
       2L, "1996-06-22",           NA,             2L,             NA,
       3L, "2002-07-11", "2004-04-05",             2L,             2L,
       4L, "2004-10-10", "2009-08-27",             1L,             1L,
       5L, "2000-12-05", "2005-02-28",             2L,             1L,
)
family <- family %>% mutate_at(vars(starts_with("dob")), parse_date)

#> # A tibble: 5 x 5
#>   family dob_child1 dob_child2 gender_child1 gender_child2
#>    <int> <date>     <date>             <int>         <int>
#> 1      1 1998-11-26 2000-01-29             1             2
#> 2      2 1996-06-22 NA                     2            NA
#> 3      3 2002-07-11 2004-04-05             2             2
#> 4      4 2004-10-10 2009-08-27             1             1
#> 5      5 2000-12-05 2005-02-28             2             1

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.

family %>% 
    pivot_longer(spec = spec, na.rm = T)

#> # A tibble: 9 x 4
#>   family child dob        gender
#>    <int> <dbl> <date>      <int>
#> 1      1     1 1998-11-26      1
#> 2      1     2 2000-01-29      2
#> 3      2     1 1996-06-22      2
#> 4      3     1 2002-07-11      2
#> 5      3     2 2004-04-05      2
#> 6      4     1 2004-10-10      1
#> 7      4     2 2009-08-27      1
#> 8      5     1 2000-12-05      2
#> 9      5     2 2005-02-28      1

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.

Paket R rapir dan fungsi barunya pivot_longer dan pivot_wider

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)

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:

fish_encounters %>% pivot_wider(
  names_from = station, 
  values_from = seen,
  values_fill = list(seen = 0)
)

#> # 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     0     0     0     0     0
#>  5 4847        1     1      1     0       0     0     0     0     0     0
#>  6 4848        1     1      1     1       0     0     0     0     0     0
#>  7 4849        1     1      0     0       0     0     0     0     0     0
#>  8 4850        1     1      0     1       1     1     1     0     0     0
#>  9 4851        1     1      0     0       0     0     0     0     0     0
#> 10 4854        1     1      0     0       0     0     0     0     0     0
#> # … with 9 more rows, and 1 more variable: MAW <int>

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.

df %>% pivot_wider(names_from = c(product, country),
                 values_from = "value")

#> # A tibble: 15 x 4
#>     year     A_AI    B_AI    B_EI
#>    <int>    <dbl>   <dbl>   <dbl>
#>  1  2000 -2.05     0.607   1.20  
#>  2  2001 -0.676    1.65   -0.114 
#>  3  2002  1.60    -0.0245  0.501 
#>  4  2003 -0.353    1.30   -0.459 
#>  5  2004 -0.00530  0.921  -0.0589
#>  6  2005  0.442   -1.55    0.594 
#>  7  2006 -0.610    0.380  -1.28  
#>  8  2007 -2.77     0.830   0.637 
#>  9  2008  0.899    0.0175 -1.30  
#> 10  2009 -0.106   -0.195   1.03  
#> # … with 5 more rows

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:

spec <- df %>% 
  expand(product, country, .value = "value") %>% 
  unite(".name", product, country, remove = FALSE)

#> # 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.

  spec <- us_rent_income %>% 
    expand(variable, .value = c("estimate", "moe")) %>% 
    mutate(
      .name = paste0(variable, ifelse(.value == "moe", "_moe", ""))
    )

#> # A tibble: 4 x 3
#>   variable .value   .name     
#>   <chr>    <chr>    <chr>     
#> 1 income   estimate income    
#> 2 income   moe      income_moe
#> 3 rent     estimate rent      
#> 4 rent     moe      rent_moe

Memberikan spesifikasi ini pivot_wider() memberi kita hasil yang kita cari:

us_rent_income %>% pivot_wider(spec = spec)

#> # A tibble: 52 x 6
#>    GEOID NAME                 income income_moe  rent rent_moe
#>    <chr> <chr>                 <dbl>      <dbl> <dbl>    <dbl>
#>  1 01    Alabama               24476        136   747        3
#>  2 02    Alaska                32940        508  1200       13
#>  3 04    Arizona               27517        148   972        4
#>  4 05    Arkansas              23789        165   709        5
#>  5 06    California            29454        109  1358        3
#>  6 08    Colorado              32401        109  1125        5
#>  7 09    Connecticut           35326        195  1123        5
#>  8 10    Delaware              31560        247  1076       10
#>  9 11    District of Columbia  43198        681  1424       17
#> 10 12    Florida               25952         70  1077        3
#> # … with 42 more rows

Bank Dunia

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.

#> # A tibble: 1,056 x 20
#>    country indicator `2000` `2001` `2002` `2003`  `2004`  `2005`   `2006`
#>    <chr>   <chr>      <dbl>  <dbl>  <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
#>  1 ABW     SP.URB.T… 4.24e4 4.30e4 4.37e4 4.42e4 4.47e+4 4.49e+4  4.49e+4
#>  2 ABW     SP.URB.G… 1.18e0 1.41e0 1.43e0 1.31e0 9.51e-1 4.91e-1 -1.78e-2
#>  3 ABW     SP.POP.T… 9.09e4 9.29e4 9.50e4 9.70e4 9.87e+4 1.00e+5  1.01e+5
#>  4 ABW     SP.POP.G… 2.06e0 2.23e0 2.23e0 2.11e0 1.76e+0 1.30e+0  7.98e-1
#>  5 AFG     SP.URB.T… 4.44e6 4.65e6 4.89e6 5.16e6 5.43e+6 5.69e+6  5.93e+6
#>  6 AFG     SP.URB.G… 3.91e0 4.66e0 5.13e0 5.23e0 5.12e+0 4.77e+0  4.12e+0
#>  7 AFG     SP.POP.T… 2.01e7 2.10e7 2.20e7 2.31e7 2.41e+7 2.51e+7  2.59e+7
#>  8 AFG     SP.POP.G… 3.49e0 4.25e0 4.72e0 4.82e0 4.47e+0 3.87e+0  3.23e+0
#>  9 AGO     SP.URB.T… 8.23e6 8.71e6 9.22e6 9.77e6 1.03e+7 1.09e+7  1.15e+7
#> 10 AGO     SP.URB.G… 5.44e0 5.59e0 5.70e0 5.76e0 5.75e+0 5.69e+0  4.92e+0
#> # … with 1,046 more rows, and 11 more variables: `2007` <dbl>,
#> #   `2008` <dbl>, `2009` <dbl>, `2010` <dbl>, `2011` <dbl>, `2012` <dbl>,
#> #   `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>, `2017` <dbl>

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().

pop2 <- world_bank_pop %>% 
  pivot_longer(`2000`:`2017`, names_to = "year")

#> # A tibble: 19,008 x 4
#>    country indicator   year  value
#>    <chr>   <chr>       <chr> <dbl>
#>  1 ABW     SP.URB.TOTL 2000  42444
#>  2 ABW     SP.URB.TOTL 2001  43048
#>  3 ABW     SP.URB.TOTL 2002  43670
#>  4 ABW     SP.URB.TOTL 2003  44246
#>  5 ABW     SP.URB.TOTL 2004  44669
#>  6 ABW     SP.URB.TOTL 2005  44889
#>  7 ABW     SP.URB.TOTL 2006  44881
#>  8 ABW     SP.URB.TOTL 2007  44686
#>  9 ABW     SP.URB.TOTL 2008  44375
#> 10 ABW     SP.URB.TOTL 2009  44052
#> # … with 18,998 more rows

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):

pop3 <- pop2 %>% 
  separate(indicator, c(NA, "area", "variable"))

#> # A tibble: 19,008 x 5
#>    country area  variable year  value
#>    <chr>   <chr> <chr>    <chr> <dbl>
#>  1 ABW     URB   TOTL     2000  42444
#>  2 ABW     URB   TOTL     2001  43048
#>  3 ABW     URB   TOTL     2002  43670
#>  4 ABW     URB   TOTL     2003  44246
#>  5 ABW     URB   TOTL     2004  44669
#>  6 ABW     URB   TOTL     2005  44889
#>  7 ABW     URB   TOTL     2006  44881
#>  8 ABW     URB   TOTL     2007  44686
#>  9 ABW     URB   TOTL     2008  44375
#> 10 ABW     URB   TOTL     2009  44052
#> # … with 18,998 more rows

Sekarang yang harus kita lakukan adalah membagi variabel menjadi dua kolom:

pop3 %>% 
  pivot_wider(names_from = variable, values_from = value)

#> # A tibble: 9,504 x 5
#>    country area  year   TOTL    GROW
#>    <chr>   <chr> <chr> <dbl>   <dbl>
#>  1 ABW     URB   2000  42444  1.18  
#>  2 ABW     URB   2001  43048  1.41  
#>  3 ABW     URB   2002  43670  1.43  
#>  4 ABW     URB   2003  44246  1.31  
#>  5 ABW     URB   2004  44669  0.951 
#>  6 ABW     URB   2005  44889  0.491 
#>  7 ABW     URB   2006  44881 -0.0178
#>  8 ABW     URB   2007  44686 -0.435 
#>  9 ABW     URB   2008  44375 -0.698 
#> 10 ABW     URB   2009  44052 -0.731 
#> # … with 9,494 more rows

Daftar kontak

Contoh terakhir, bayangkan Anda memiliki daftar kontak yang Anda salin dan tempel dari sebuah situs web:

contacts <- tribble(
  ~field, ~value,
  "name", "Jiena McLellan",
  "company", "Toyota", 
  "name", "John Smith", 
  "company", "google", 
  "email", "[email protected]",
  "name", "Huxley Ratcliffe"
)

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":

contacts <- contacts %>% 
  mutate(
    person_id = cumsum(field == "name")
  )
contacts

#> # 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:

contacts %>% 
  pivot_wider(names_from = field, values_from = value)

#> # 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().

Sumber: www.habr.com

Tambah komentar