Wrangle adalah proses yg melibat penginputan dan perapihan data, bisa dibilang satu proses sebelum eksplorasi data. Pada bagian ini, kita akan belajar soal ‘tibble’ (versi baru dari dataframe yg dibuat khusus untuk bisa bekerja dengan tidyverse), cara impor data, dan teknik serta prinsip perapihan data.
Pada dasarnya, saat kita menginstal library ‘tidyverse’ paket ‘tibble’ sudah di load secara otomatis.
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5 v purrr 0.3.4
## v tibble 3.1.4 v dplyr 1.0.7
## v tidyr 1.1.4 v stringr 1.4.0
## v readr 2.0.2 v forcats 0.5.1
## Warning: package 'tidyr' was built under R version 4.1.2
## Warning: package 'dplyr' was built under R version 4.1.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
Apa sebenarnya yang membedakan? Singkatnya tibble lebih canggih untuk membuat data yang terinput lebih rapih untuk analisa.
a <- 1:5
b <- c("a","b","c","d","e")
c <- data.frame(a,b)
c
## a b
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
Seperti yg bisa dilihat, dalam dataframe kita harus membuat dan memastikan seluruh data yg diinput. Misal, jika pada salah satu variabel saja ada yg kurang atau tidak sama dengan variabel lainnya, dataframe akan mengeluarkan pesan error.
Nah, sekarang kita bandingkan dengan tibble.
#variabel
x = 1:5
y = 1
z = x^2 + y
# buat tibble
tb <- tibble(x,y,z)
tb
## # A tibble: 5 x 3
## x y z
## <int> <dbl> <dbl>
## 1 1 1 2
## 2 2 1 5
## 3 3 1 10
## 4 4 1 17
## 5 5 1 26
Lihat bagaimana mudahnya pembuatan tibble. nilai 1 pada var y secara otomatis akan mengulangi dirinya sendiri sesuai jumlah observasi variabel lainnya. Tibble tidak akan mengubah tipe data inputan, membuat variabel baru, atau merubah nama variabel inputan. Di tibble bahkan kita memberi nama aneh yg non-sytemic. Ada versi lain dari tibble yg memungkinkan untuk pembuatan data mini
tb2 <- tribble(
~k, ~l, ~m,
#--------
"a",2,3.4,
"b",1,8.4
)
tb2
## # A tibble: 2 x 3
## k l m
## <chr> <dbl> <dbl>
## 1 a 2 3.4
## 2 b 1 8.4
data(mpg)
mpg %>% print(n = 12, width = 2)
## # A
## # tibble:
## # 234
## # x
## # 11
Kita juga bisa menggunakan built in function seperti view() untuk melihat keseluruhan data set seperti tampilan excel atau spreadsheet
mpg %>% view()
Secara general, tibble lebih strict dan ketat dalam perihal subseting, tibble tidak akan mengeluarkan output untuk variabel yg tidak eksis
note : selama ini ada salah tangkap perihal subseting, di mana aku selalu menggunakan [] untuk memanggil variabel dalam memanggil subset dataframe atatu tibble. yg benar harusnya [[]] untuk numeric, dan [[""]] untuk string. Jika sudah menggunakan pipe (%>%) cukup gunakan “.” untuk memanggil variabel.
df <- data.frame(abc = 1, xyz = "a")
df$x # Kenapa hanya dengan mengetikan x, bisa menghasilkan "a" ?
## [1] "a"
df[,"xyz"]
## [1] "a"
df[,c("abc", "xyz")]
## abc xyz
## 1 1 a
# Pakai variabel bernama 1
`1` <- c(1:20)
`2` <- rnorm(20)
data <- tibble(`1`,`2`)
data$`1`
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
data$`2`
## [1] -0.72859600 -0.92316593 1.42554554 1.45985997 -1.08737851 1.55720610
## [7] 0.59498219 0.19473978 0.34696041 -0.58309657 0.14246500 -1.82804271
## [13] 1.18084549 -0.73290540 -0.68021843 1.10242180 -0.56011058 -0.05358341
## [19] -0.41260443 0.63113949
plot(data$`1`,data$`2`)
data$`3` <- data$`2`/data$`1`
data
## # A tibble: 20 x 3
## `1` `2` `3`
## <int> <dbl> <dbl>
## 1 1 -0.729 -0.729
## 2 2 -0.923 -0.462
## 3 3 1.43 0.475
## 4 4 1.46 0.365
## 5 5 -1.09 -0.217
## 6 6 1.56 0.260
## 7 7 0.595 0.0850
## 8 8 0.195 0.0243
## 9 9 0.347 0.0386
## 10 10 -0.583 -0.0583
## 11 11 0.142 0.0130
## 12 12 -1.83 -0.152
## 13 13 1.18 0.0908
## 14 14 -0.733 -0.0524
## 15 15 -0.680 -0.0453
## 16 16 1.10 0.0689
## 17 17 -0.560 -0.0329
## 18 18 -0.0536 -0.00298
## 19 19 -0.413 -0.0217
## 20 20 0.631 0.0316
data <- rename(data, one = `1`, two = `2`, three = `3`)
data
## # A tibble: 20 x 3
## one two three
## <int> <dbl> <dbl>
## 1 1 -0.729 -0.729
## 2 2 -0.923 -0.462
## 3 3 1.43 0.475
## 4 4 1.46 0.365
## 5 5 -1.09 -0.217
## 6 6 1.56 0.260
## 7 7 0.595 0.0850
## 8 8 0.195 0.0243
## 9 9 0.347 0.0386
## 10 10 -0.583 -0.0583
## 11 11 0.142 0.0130
## 12 12 -1.83 -0.152
## 13 13 1.18 0.0908
## 14 14 -0.733 -0.0524
## 15 15 -0.680 -0.0453
## 16 16 1.10 0.0689
## 17 17 -0.560 -0.0329
## 18 18 -0.0536 -0.00298
## 19 19 -0.413 -0.0217
## 20 20 0.631 0.0316
Pada awal bagian ini, kita akan mulai dengan membahas soal bagaimana kita mengimpor data dari plain-rectangular data, tapi kemudian akan mencoba untuk menerapkannya pada tipe-tipe data lain.
Seperti biasa, awalnya kita load terlebih dahulu library(tidyverse)
library(tidyverse)
Tools yg barguna untuk keperluan ini adalah ‘readr’. Beberapa fungsi yg penting adalah : * read_csv(), fungsi yg berguna untuk membaca file format csv. kita bisa memberi spesifikasi delimiter apa yg berada dalam file. Bentuk lainnya dari read_csv adalah read_csv2() yg membaca file dengan delimiter “;” semicolon, ada read_tsv() yg membaca file berdelimiter ‘tab’, dan juga read_delim() yg membaca file dengan delimiter apapun.
Contoh :
bacacsv <- read_csv("100 Sales Records.csv")
## Rows: 100 Columns: 14
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr (7): Region, Country, Item Type, Sales Channel, Order Priority, Order Da...
## dbl (7): Order ID, Units Sold, Unit Price, Unit Cost, Total Revenue, Total C...
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
bacacsv
## # A tibble: 100 x 14
## Region Country `Item Type` `Sales Channel` `Order Priority` `Order Date`
## <chr> <chr> <chr> <chr> <chr> <chr>
## 1 Australi~ Tuvalu Baby Food Offline H 5/28/2010
## 2 Central ~ Grenada Cereal Online C 8/22/2012
## 3 Europe Russia Office Sup~ Offline L 5/2/2014
## 4 Sub-Saha~ Sao Tome~ Fruits Online C 6/20/2014
## 5 Sub-Saha~ Rwanda Office Sup~ Offline L 2/1/2013
## 6 Australi~ Solomon ~ Baby Food Online C 2/4/2015
## 7 Sub-Saha~ Angola Household Offline M 4/23/2011
## 8 Sub-Saha~ Burkina ~ Vegetables Online H 7/17/2012
## 9 Sub-Saha~ Republic~ Personal C~ Offline M 7/14/2015
## 10 Sub-Saha~ Senegal Cereal Online H 4/18/2014
## # ... with 90 more rows, and 8 more variables: Order ID <dbl>, Ship Date <chr>,
## # Units Sold <dbl>, Unit Price <dbl>, Unit Cost <dbl>, Total Revenue <dbl>,
## # Total Cost <dbl>, Total Profit <dbl>
bacatsv <- read_tsv("Phantomscan_InventoryEvents_2013-01-12.tsv")
## Rows: 183 Columns: 5
## -- Column specification --------------------------------------------------------
## Delimiter: "\t"
## chr (2): EventType, SkuId
## dbl (2): Quantity, ItemId
## dttm (1): EventDate
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
bacatsv
## # A tibble: 183 x 5
## EventDate EventType Quantity ItemId SkuId
## <dttm> <chr> <dbl> <dbl> <chr>
## 1 2013-01-01 10:10:35 out 3 3596710216072 <NA>
## 2 2013-01-01 10:10:36 out 1 3596710216074 <NA>
## 3 2013-01-01 10:10:46 out 1 3596710216069 <NA>
## 4 2013-01-01 10:10:54 out 3 3596710216070 <NA>
## 5 2013-01-01 10:10:55 out 1 3596710216073 <NA>
## 6 2013-01-01 10:40:23 out 1 3596710216072 <NA>
## 7 2013-01-01 11:45:54 out 1 3596710216074 <NA>
## 8 2013-01-01 12:01:18 out 2 3596710216073 <NA>
## 9 2013-01-01 12:18:56 out 2 3596710216074 <NA>
## 10 2013-01-01 13:30:56 out 3 3596710216070 <NA>
## # ... with 173 more rows
Untuk saat ini, kita kan berfokus pada file csv karena format ini paling umum digunakan, dan paling mudah untuk dipahami.
Kita juga bisa membaca data csv secara manual dalam R.
read_csv("a, b, c
1,2,3
4,5,6")
## Rows: 2 Columns: 3
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## dbl (3): a, b, c
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 2 x 3
## a b c
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 6
seperti yg bisa dilihat di atas, kita menemukan beberapa hal menarik. Data baris pertama akan selau diperlakukan sebagai header dari data atau nama variabel. Apa dalam read_csv kita tidak perlu menggunakan " " untuk data string? kita coba.
read_csv("a,b,c
d,e,f
g,h,2")
## Rows: 2 Columns: 3
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr (3): a, b, c
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 2 x 3
## a b c
## <chr> <chr> <chr>
## 1 d e f
## 2 g h 2
Yep, ternyata benar. Ketika membaca read_csv seperti ini, kita tidak perlu menuliskan string dalam "". Berkaitan dengan setting csv untuk membuat setiap baris pertama dalam data menjadi header data, kita bisa mengaturnya dengan penggantian opsi. Kenapa kita butuh ini? karena dalam beberapa data, baris pertama atay beberapa baris awasl digunakan sebagai meta data yg menjelaskan secara deskirptif, dan tidak diperlukan dalam analisa data. Untuk tidak melibatkan baris-baris data awal, kita bisa menambahkan opsi ‘skip=n’, untuk memerintahkan R melewatkan n baris pertama. Pilihan lain adalah menggunakan pilihan comment = ‘#’;untuk memerintahkan R melewati setiap baris yg diawali #. (Bisa diatur dalam simbol lainnya)
contoh :
read_csv("ini baris pertama
ini baris kedua
x,y,z
a,2,1", skip = 2, show_col_type = FALSE)
## # A tibble: 1 x 3
## x y z
## <chr> <dbl> <dbl>
## 1 a 2 1
read_csv("# comment yg diawali tanda
z,y,x
1,2,3", comment = "#", show_col_type = FALSE)
## # A tibble: 1 x 3
## z y x
## <dbl> <dbl> <dbl>
## 1 1 2 3
Bagaimana kita tidak ingin melewati baris pertama, tapi juga tidak ingin menggunakannya sebagai header melainkan sebagai konten data? maka yg perlu ditambahkan adalah argumen ‘col_names = FALSE’. R akan menjadikan baris pertama sebagai bagian dari value data, dan secara bersamaan, menambahkan secara sekuensial nama variabel dari X1 hingga Xn.
read_csv("1,2,3\n4,5,6", col_names = FALSE, show_col_type = FALSE)
## # A tibble: 2 x 3
## X1 X2 X3
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 6
note : “” adalah cara efisien untuk menulis baris.
Selain baris pertama seperti di atas, hal lain yang memerlukan penyesuaian di sini adalah ‘missing data’. Kita bisa menentukan seperti apa data yg hilang akan direpresentasikan.
read_csv("1,2,3\n4,5,.", col_names = c("x", "y", "z"), show_col_types = FALSE,
na = ".")
## # A tibble: 2 x 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 NA
Karena jika “na =” tidak di atur, read_csv akan menampilkan data apa adanya. (ingat, tibble tidak akan mengubah apapun value dan format data)
Kenapa tidak pakai read.csv()? * Lebih cepat * read_csv() memproduksi tibble. Artinya kita tidak perlu khawatir R mengubah format data begitu saja. * Dapat direproduksi. read.csv() akan mewarisi beberapa properti dari sistem operasi dan variabel environment. Jadi kemungkinan besar, kode kita tidak akan bisa digunakan di kode lain.
case penasaran
read_csv("x,y\n1,'a,b'", quote = '' ,show_col_types = FALSE)
## Warning: One or more parsing issues, see `problems()` for details
## # A tibble: 1 x 2
## x y
## <dbl> <chr>
## 1 1 'a,b'
read_csv("a,b\n1,2,3\n4,5,6")
## Rows: 2 Columns: 2
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## dbl (1): a
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Warning: One or more parsing issues, see `problems()` for details
## # A tibble: 2 x 2
## a b
## <dbl> <dbl>
## 1 1 23
## 2 4 56
Jika jumlah kolom (baris pertama) < baris berikutnya, read_csv akan memaksa seluruh baris berikutnya menyesuaikan dengan jumlah kolom yg ada.
read_csv("a,b,c\n1,2\n1,2,3,4", show_col_types = FALSE)
## Warning: One or more parsing issues, see `problems()` for details
## # A tibble: 2 x 3
## a b c
## <dbl> <dbl> <dbl>
## 1 1 2 NA
## 2 1 2 34
Sementara jika jumlah kolom > baris berikutnya, maka read_csv akan membuat baris yg kekurangan nilai tersebut sebagai missing value NA.
read_csv("a,b\n\"1", show_col_types = FALSE)
## # A tibble: 0 x 2
## # ... with 2 variables: a <chr>, b <chr>
Kode di atas tidak menunjukkan hasil apapun.
read_csv("a,b\n1,2\na,b")
## Rows: 2 Columns: 2
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr (2): a, b
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 2 x 2
## a b
## <chr> <chr>
## 1 1 2
## 2 a b
Meski diprediksi akan menimbulkan masalah dengan keambiguan “” dan “”, nyatanya kode tersebut masih bisa menghasilkan output yg sesuai.
read_csv("a;b\n1;3")
## Rows: 1 Columns: 1
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr (1): a;b
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 1 x 1
## `a;b`
## <chr>
## 1 1;3
Pada kode diatas karena kita tidak memberikan kode dengan spesifikasi yg lebih baik, dalam arti tidak menggunakan argumen delim = “;”, output yg dihasilkan akan jadi seperti di atas.
Parsing atau parse adalah fungsi R untuk mengonversi objek karakter (char) menjadi objek dengan tertentu. Misal dari char menjadi int, char menjadi dbl, dsg.
contoh :
parse_logical(c("TRUE","FALSE","TRUE"))
## [1] TRUE FALSE TRUE
parse_integer(c("1","2","3"))
## [1] 1 2 3
parse_date(c("2010-01-01","1979-10-14"))
## [1] "2010-01-01" "1979-10-14"
Jika ada nilai yg gagal di parse, R akan mengeluarkan output berupa missing value untuk nilai yg gagal.
ada beberapa jenis parse_* yg kerap muncul dan penting : * parse_logical() dan parse_integer() * parse_double(); contoh seperti 12.34 atau 32,24. Rumit karena masing-masing data bisa menggunakan aturan desimal yg berbeda. * parse_character() penting untuk character encoding * parse_factor() * parse_datetime(), parse_date, dan parse_time()
Seperti yang sudah disebutkan di atas, parse_double() sedikit rumit karena kondisi dan perbedaan yg ada dalam penginputan nilai data itu sendiri. Ada yg manggunakan “.” dan “,” untuk bagian integral dan desimal; ada yg didahului karakter tertentu seperi “Rp.1000,-” dsg.
Untuk mengatasi isu-isu tersebut, berikut adalah caranya :
parse_double("1,23", locale = locale(decimal_mark = ","))
## [1] 1.23
parse_number("Rp1000")
## [1] 1000
as.integer(parse_number("Rp.1000.000", locale = locale(grouping_mark =
c("."))))
## [1] 1000000
Kenapa perlu ada parso_character()? bukankah fungsi parse sendiri adalah untuk mengovert data character menjadi tipe yg diinginkan? Kegunaannya adalah saat kita menemukan file yg berasal dari intetias miterius (hehe), atau dokumentasi lama yg mungkin belum mengenal standart encoding modern.
Perlu kita pahami bahwa komputer memiliki banyak cara untuk merepresentasikan data string.
charToRaw("Galih")
## [1] 47 61 6c 69 68
Yup seperti yg bisa kita, lihat. Nama “Galih” pada dasarnya berasal dari representasi setiap bit informasi yg tersusun dalam angka hexadecimal. Dan setiap sistem informasi memiliki standart yg berbeda soal ini. inilah kegunaan parse_character.
contoh :
x1 <- "El Ni\xf1o was particularly bad this year"
x2 <- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"
x1
## [1] "El Niño was particularly bad this year"
x2
## [1] "‚±‚ñ‚É‚¿‚Í"
pada x1, character “Ni1o” rupanya merupakan kodefikasi dari tanda umum dalam pelafalan latin. Kita bisa mengencode nya langsung karena tanda itu masih dalam UTF-8. Akan tetapi akan lebih baik untuk kita tetap melaukan parse secara layak. Untuk x2, karakter menjadi simbol-simbol tidak terdefinisi, karena memang tidak ada mengikuti standar encoding UTF-8.
Apa yg perlu kita lakukan? bagaimana kita bisa menebak standar encoding apa yang tepat untuk karakter di atas? Jika beruntung, kita bisa menemukan encoding yg sesuai pada dokumentasi data. Akan tetapi, keberuntungan itu sering kali tidak muncul, dan kita harus menebak sendiri standart encoding yg tepat. caranya adalah menggunakan guess_encoding(). Fungsi ini akan menghasilkan beberapa probabilitas standar yg bisa kita uji dan cobakan.
guess_encoding(charToRaw(x2))
## # A tibble: 1 x 2
## encoding confidence
## <chr> <dbl>
## 1 KOI8-R 0.42
Oke, jadi kita punya satu kandidat yaitu KOI8-R sebagai standar encoding untuk memparse kan karakter x2. Lalu apa?
Sekarang, kita lakukan parse_character x1 dan x2 secara benar
parse_character(x1, locale = locale(encoding = "Latin1"))
## [1] "El Niño was particularly bad this year"
parse_character(x2, locale = locale(encoding = "SHIFT-JIS"))
## [1] "<U+3053><U+3093><U+306B><U+3061><U+306F>"
Dan… seperti yg kita lihat lagi, ternyata rekomendasi dari guess_encoding juga salah dan membuatku harus mencari-cari encoding lain yg tepat.
parse_factor() digunakan untuk convert dari character menjadi data factor dengan levelnya.
fruit <- c("apple","banana")
parse_factor(c("apple"), levels = fruit)
## [1] apple
## Levels: apple banana
yg ini mungkin belum terlihat banyak kegunaannya karena kita bisa saja langsung menggunakan as.factor()
Cara tercepat untuk memahami parse datetime, date, dan time adalah dengan membuat contoh langsung.
parse_date("01/02/15", "%m/%d/%y")
## [1] "2015-01-02"
parse_date("01/02/15", "%d/%m/%y")
## [1] "2015-02-01"
parse_date("01/02/15", "%y/%m/%d")
## [1] "2001-02-15"
parse_date("22-01-1993", "%d-%m-%Y")
## [1] "1993-01-22"
parse_date("14 September 1995", "%d %B %Y")
## [1] "1995-09-14"
parse_datetime("150195,2010", "%d%m%y%.%H%M")
## [1] "1995-01-15 20:10:00 UTC"
parse_datetime("01/12/00,0120PM", "%d/%m/%y%.%I%M%p")
## [1] "2000-12-01 13:20:00 UTC"
Kegunaannya di sini adalah membuat vector character menjadi format tanggal dan waktu sesuai format standar R dengan mengidentifikasikan tidap bagiannya.
Selain tanggal dan tanggal-waktu, kita bisa juga hanya memodifikasi bagian waktunya saja dengan parse_time. Tapi karena R base kurang baik dalam menangani hal ini, kita perlu load library(hms)
library(hms)
parse_time("0101", "%H%M")
## 01:01:00
parse_time("192414UTC7","%H%M%S%Z")
## 19:24:14
Pada catatan-catatan sebelumnya, kita melakukan parsing pada vector. Sekarang kita berlanjut ke parsing sebuah file.
Contoh : 1. Kita gunakan file sample dengan readr_example(). readr_example adalah sebuah fungsi yang memiliki beberapa sample data.
ex_data <- read_csv(readr_example("challenge.csv"))
## Rows: 2000 Columns: 2
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## dbl (1): x
## date (1): y
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
spec(ex_data)
## cols(
## x = col_double(),
## y = col_date(format = "")
## )
Cara terbaik untuk menangani parsing file adalah dengan mengerjakannya secara kolom per kolom.
ex_data
## # A tibble: 2,000 x 2
## x y
## <dbl> <date>
## 1 404 NA
## 2 4172 NA
## 3 3004 NA
## 4 787 NA
## 5 37 NA
## 6 2332 NA
## 7 2489 NA
## 8 1449 NA
## 9 3665 NA
## 10 3863 NA
## # ... with 1,990 more rows
Perbaikan kolom ‘y’
ex_data <- read_csv(readr_example("challenge.csv"),
col_types = cols(
x = col_double(),
y = col_date()
))
tail(ex_data)
## # A tibble: 6 x 2
## x y
## <dbl> <date>
## 1 0.805 2019-11-21
## 2 0.164 2018-03-29
## 3 0.472 2014-08-04
## 4 0.718 2015-08-16
## 5 0.270 2020-02-04
## 6 0.608 2019-01-06
Kenapa kita menggunakan col_abc() bukan parse_abc() ?
Itu karena parse_abs digunakan untuk mengonversi vector, sementara col_abc() digunakan untuk memberi tahu R bagaimana cara me-load data. Cara ini sangat direkomendasikan karena akan membantu kita untuk menghasilkan script yg konsisten dan reproducible. Untuk menambah ketat script, kita gunakan fungsi ‘stop_for_problems()’ yg akan menghentikan berjalannya script saat ada masalah pada parsing.
Note : SELALU BIASAKAN UNTUK MENAMBAH ‘col_types()’ pada script
Analisa data yg baik dan akurat berasal dari struktur data yg rapi. Dalam kasus R yg berdasarkan pada analisa vector, struktur data yg rapi adalah data yg terdiri dari : * Variabel pada kolom * Observasi pada bari * satu nilai pada satu cell. Kenapa data bisa tidak rapi? * Tidak banyak orang paham prinsip struktur data * Banyak struktur data awalnya bukan ditujukan untuk analisa, melainkan untuk mempermudah entry input.
Bagaimana prinsip penataan data ? * Pahami mana yg menjadi variabel, dan mana yg menjadi observasi. * Selesaikan masalah di mana adanya kemungkinan satu variabel yg tersebar di banyak kolom, atau satu observasi yg tersebar di banyak baris.
Apa tools yg paling sering bermanfaat untuk penataan data? Dalam package tidyverse, kita akan banyak menggunakan pivot_longer() dan pivot_wider().
Fungsi ini bertujuan untuk : mengurangi jumlah kolom, dan menambah jumlah baris. Ia digunakan saat kita menemui sebuah dataset yg menempatkan value variabel dalam bentuk kolom.
Contoh :
stocks <- tibble(
year = c(2015, 2015, 2016,2016),
half = c(1, 2, 1, 2),
return = c(1.88, 0.59, 0.92, 0.17)
)
stock_wider <- stocks %>%
pivot_wider(names_from = year, values_from = return)
stock_wider
## # A tibble: 2 x 3
## half `2015` `2016`
## <dbl> <dbl> <dbl>
## 1 1 1.88 0.92
## 2 2 0.59 0.17
stock_longer <- stock_wider %>% pivot_longer(c(`2015`,`2016`), names_to = "year", values_to = "return") %>% select(year,half,return)
stock_longer
## # A tibble: 4 x 3
## year half return
## <chr> <dbl> <dbl>
## 1 2015 1 1.88
## 2 2016 1 0.92
## 3 2015 2 0.59
## 4 2016 2 0.17
contoh 2 :
people <- tribble (
~name, ~names, ~values,
#-----|-------|-------
"Philips Woods", "age", 45,
"Philips Woods", "height", 186,
"Philips Woods", "age", 50,
"Jessica Cordero", "age", 37,
"Jessica Cordero", "height", 156
)
people
## # A tibble: 5 x 3
## name names values
## <chr> <chr> <dbl>
## 1 Philips Woods age 45
## 2 Philips Woods height 186
## 3 Philips Woods age 50
## 4 Jessica Cordero age 37
## 5 Jessica Cordero height 156
coba lebarkan people.
people %>% pivot_wider(names_from = names, values_from = values)
## Warning: Values are not uniquely identified; output will contain list-cols.
## * Use `values_fn = list` to suppress this warning.
## * Use `values_fn = length` to identify where the duplicates arise
## * Use `values_fn = {summary_fun}` to summarise duplicates
## # A tibble: 2 x 3
## name age height
## <chr> <list> <list>
## 1 Philips Woods <dbl [2]> <dbl [1]>
## 2 Jessica Cordero <dbl [1]> <dbl [1]>
TIDAK BISA. Karena pada kolom ‘names’ values age ada 2…
contoh3 :
preg <- tribble(
~pregnant, ~male, ~female,
"yes", NA, 10,
"no", 20, 12
)
preg
## # A tibble: 2 x 3
## pregnant male female
## <chr> <dbl> <dbl>
## 1 yes NA 10
## 2 no 20 12
preg2 <- preg %>% pivot_longer(c(male, female), names_to = "gender",
values_to = "count") %>%
select(gender, pregnant, count) %>% arrange(gender)
preg2
## # A tibble: 4 x 3
## gender pregnant count
## <chr> <chr> <dbl>
## 1 female yes 10
## 2 female no 12
## 3 male yes NA
## 4 male no 20
Coba anda lihat data set di bawah ini :
table3
## # A tibble: 6 x 3
## country year rate
## * <chr> <int> <chr>
## 1 Afghanistan 1999 745/19987071
## 2 Afghanistan 2000 2666/20595360
## 3 Brazil 1999 37737/172006362
## 4 Brazil 2000 80488/174504898
## 5 China 1999 212258/1272915272
## 6 China 2000 213766/1280428583
Seperti yg kita lihat pada tabel di atas, kolom rate merupakan gabungan dari nilai case dan population, yg artinya ada dua nilai tergabung dalam satu cell. Untuk mengatasi ini, kita perlu menggunakan fungsi separate().
table3 %>% separate(rate, into = c("case","population"))
## # A tibble: 6 x 4
## country year case population
## <chr> <int> <chr> <chr>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
Keren, kan? Secara dafault, separate() akan memisahkan data saat menemui non-alphanumeric character (karakter yg bukan angka maupun abjad). Jika kita ingin mengatur pada titik apa variabel perlu dipecah, kita bisa merincinya dengan menambahkan argumen ‘sep=“tanda”’. Sep ini di sini biasanya akan menggunakan Regular Expression sebagai praktik umum.
Perlu dipahami bahwa hasil separation akan selalu menghasilkan output character. Oleh karena itu, jika apa yang kita inginkan adalah non-character, maka kita perlu segera mengonvertnya setelah dipisah.
Kita juga bisa menggunakan vector integral sebagai pemisah dalam separate(). Ini akan membuat string terpisah berdasarkan posisiny atau indeksnya. Angka 1 adalah ujung paling kiri karakter, sedangkan -1 adalah ujung paling kanan karakter.
table5 <- table3 %>% separate(year, into = c("century", "year"), sep = 2)
table5
## # A tibble: 6 x 4
## country century year rate
## <chr> <chr> <chr> <chr>
## 1 Afghanistan 19 99 745/19987071
## 2 Afghanistan 20 00 2666/20595360
## 3 Brazil 19 99 37737/172006362
## 4 Brazil 20 00 80488/174504898
## 5 China 19 99 212258/1272915272
## 6 China 20 00 213766/1280428583
Ini adalah kebalikan dari separate(). Simpelnya, kita menggabungkan beberapa variabel value menjadi satu. Ambil contoh pada data pemisahan ‘century’ dan ‘year’ di atas.
table5 %>% unite("new","century", "year")
## # A tibble: 6 x 3
## country new rate
## <chr> <chr> <chr>
## 1 Afghanistan 19_99 745/19987071
## 2 Afghanistan 20_00 2666/20595360
## 3 Brazil 19_99 37737/172006362
## 4 Brazil 20_00 80488/174504898
## 5 China 19_99 212258/1272915272
## 6 China 20_00 213766/1280428583
Dan seperti yg terlihat pada output unitContoh, value ‘century’ dan ‘new’ tergabung menjadi satu dalam variabel baru bernama ‘new’, namun dengan bentuk yg terhubung dengan underscore (_). Ini adalah bentuk separation default hasil unite(). Untuk mengubahnya, cukup atur argument ‘sep =’ dalam fungsi unite().
table6 <- table5 %>% unite("new", "century", "year", sep = "")
table6
## # A tibble: 6 x 3
## country new rate
## <chr> <chr> <chr>
## 1 Afghanistan 1999 745/19987071
## 2 Afghanistan 2000 2666/20595360
## 3 Brazil 1999 37737/172006362
## 4 Brazil 2000 80488/174504898
## 5 China 1999 212258/1272915272
## 6 China 2000 213766/1280428583
Exercise
tibble(x = c("a,b,c", "d, e, f", "h,i,j"))%>%
separate(x, c("one","two","three"))
## # A tibble: 3 x 3
## one two three
## <chr> <chr> <chr>
## 1 a b c
## 2 d e f
## 3 h i j
Nilai yang hilang bisa masuk dalam dua kategori kemungkinan : * Explisit, ditandai dengan NA * Implisit, tidak muncul dalam data
Secara singkatnya, Missing explisit adalah variabel ada tapi nilai nya NA. Sedangkan implisit adalah saat variabel dan nilainya tidak hadir dalam data set.
Satu hal yg penting untuk menangani missing value adalah memmastikan keberadaan missing implisit, dan mengubahnya menjadi missing explisit. Setelah menemukan nilai yg hilang, kita menghapus seluruh observasi denga nilai yg hilang, atau memberi treatment khusus, di mana, dalam beberapa kasus, nilai yg hilang berarti perlu memajukan variabel2 sebelumnya.
who
## # A tibble: 7,240 x 60
## country iso2 iso3 year new_sp_m014 new_sp_m1524 new_sp_m2534 new_sp_m3544
## <chr> <chr> <chr> <int> <int> <int> <int> <int>
## 1 Afghanistan AF AFG 1980 NA NA NA NA
## 2 Afghanistan AF AFG 1981 NA NA NA NA
## 3 Afghanistan AF AFG 1982 NA NA NA NA
## 4 Afghanistan AF AFG 1983 NA NA NA NA
## 5 Afghanistan AF AFG 1984 NA NA NA NA
## 6 Afghanistan AF AFG 1985 NA NA NA NA
## 7 Afghanistan AF AFG 1986 NA NA NA NA
## 8 Afghanistan AF AFG 1987 NA NA NA NA
## 9 Afghanistan AF AFG 1988 NA NA NA NA
## 10 Afghanistan AF AFG 1989 NA NA NA NA
## # ... with 7,230 more rows, and 52 more variables: new_sp_m4554 <int>,
## # new_sp_m5564 <int>, new_sp_m65 <int>, new_sp_f014 <int>,
## # new_sp_f1524 <int>, new_sp_f2534 <int>, new_sp_f3544 <int>,
## # new_sp_f4554 <int>, new_sp_f5564 <int>, new_sp_f65 <int>,
## # new_sn_m014 <int>, new_sn_m1524 <int>, new_sn_m2534 <int>,
## # new_sn_m3544 <int>, new_sn_m4554 <int>, new_sn_m5564 <int>,
## # new_sn_m65 <int>, new_sn_f014 <int>, new_sn_f1524 <int>, ...
data di atas adalah data set kasus tubercolosis (TBC) yg dipecah dalam beberapa variabel seperti year, negara, gender, dan metode diagnosis. Namun seperti yg bisa terlihat, data di atas terlihat acak-acakan dak sulit untuk di analisa.
Coba terapkan semua yg telah kita pelajari dalam bab wrangle ini.
view(who)
dataDict <- read_csv("TB_data_dictionary_2021-12-23.csv")
## Rows: 576 Columns: 4
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr (4): variable_name, dataset, code_list, definition
##
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
dataDict
## # A tibble: 576 x 4
## variable_name dataset code_list definition
## <chr> <chr> <chr> <chr>
## 1 budget_cpp_dstb Budget <NA> Average cost of drugs budgeted per patient~
## 2 budget_cpp_mdr Budget <NA> Average cost of drugs budgeted per patient~
## 3 budget_cpp_tpt Budget <NA> Average cost of drugs budgeted per patient~
## 4 budget_cpp_xdr Budget <NA> Average cost of drugs budgeted per patient~
## 5 budget_fld Budget <NA> Budget required for drugs to treat drug-su~
## 6 budget_lab Budget <NA> Budget required for laboratory infrastruct~
## 7 budget_mdrmgt Budget <NA> Budget required for programme costs to tre~
## 8 budget_orsrvy Budget <NA> Budget required for operational research a~
## 9 budget_oth Budget <NA> Budget required for all other budget line ~
## 10 budget_patsup Budget <NA> Budget required for patient support (US Do~
## # ... with 566 more rows
Melihat struktur data yg ada, maka solusi yg bisa dikerjakan adalah dengan menjadikannya pivot_longer()
who2 <- who %>% pivot_longer(c(new_sp_m014:newrel_f65), names_to = "newVar",
values_to = "countNew", values_drop_na = TRUE)
who2
## # A tibble: 76,046 x 6
## country iso2 iso3 year newVar countNew
## <chr> <chr> <chr> <int> <chr> <int>
## 1 Afghanistan AF AFG 1997 new_sp_m014 0
## 2 Afghanistan AF AFG 1997 new_sp_m1524 10
## 3 Afghanistan AF AFG 1997 new_sp_m2534 6
## 4 Afghanistan AF AFG 1997 new_sp_m3544 3
## 5 Afghanistan AF AFG 1997 new_sp_m4554 5
## 6 Afghanistan AF AFG 1997 new_sp_m5564 2
## 7 Afghanistan AF AFG 1997 new_sp_m65 0
## 8 Afghanistan AF AFG 1997 new_sp_f014 5
## 9 Afghanistan AF AFG 1997 new_sp_f1524 38
## 10 Afghanistan AF AFG 1997 new_sp_f2534 36
## # ... with 76,036 more rows
Setelah mentransformasikannya menjadi pivot long, langkah selanjutnya adalah memisahkan nilai method, gender, dan usia menjadi tiga variabel sendiri. Namun sebelum itu, kita bisa perhatikan bahwa sedikti ketidakkonsistenan pada penamaan value newVar. Nilai pada newVar terdiri dari metode, gender dan usia. Tiga huruf pertama, adalah tanda untuk kasus barus (new case) sementara dua huruf berikutnya adalah nama metode diagnosisnya. Untuk lima terakhir, sudah cukup jelas.
Pertama kita pisahkan dulu yg dipisahkan oleh ’_’
who3 <- who2 %>% separate(newVar, c("new","type","sexage"), sep = "_")
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 2580 rows [243,
## 244, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 903,
## 904, 905, 906, ...].
who3
## # A tibble: 76,046 x 8
## country iso2 iso3 year new type sexage countNew
## <chr> <chr> <chr> <int> <chr> <chr> <chr> <int>
## 1 Afghanistan AF AFG 1997 new sp m014 0
## 2 Afghanistan AF AFG 1997 new sp m1524 10
## 3 Afghanistan AF AFG 1997 new sp m2534 6
## 4 Afghanistan AF AFG 1997 new sp m3544 3
## 5 Afghanistan AF AFG 1997 new sp m4554 5
## 6 Afghanistan AF AFG 1997 new sp m5564 2
## 7 Afghanistan AF AFG 1997 new sp m65 0
## 8 Afghanistan AF AFG 1997 new sp f014 5
## 9 Afghanistan AF AFG 1997 new sp f1524 38
## 10 Afghanistan AF AFG 1997 new sp f2534 36
## # ... with 76,036 more rows
Sip. Sekarang, lanjutkan dengan pemisahan variabel ‘sexage’ menajadi sex dan age saja. Oya, karena variabel ‘new’, ‘iso’, dan ‘iso2’ isinya tidak penting ( Karena redundan), lebih baik buang saja.
who4 <- who3 %>% select(-iso2, -iso3, -new)
who5 <- who4 %>% separate(sexage, c("sex","age"), sep = 1)
who5
## # A tibble: 76,046 x 6
## country year type sex age countNew
## <chr> <int> <chr> <chr> <chr> <int>
## 1 Afghanistan 1997 sp m 014 0
## 2 Afghanistan 1997 sp m 1524 10
## 3 Afghanistan 1997 sp m 2534 6
## 4 Afghanistan 1997 sp m 3544 3
## 5 Afghanistan 1997 sp m 4554 5
## 6 Afghanistan 1997 sp m 5564 2
## 7 Afghanistan 1997 sp m 65 0
## 8 Afghanistan 1997 sp f 014 5
## 9 Afghanistan 1997 sp f 1524 38
## 10 Afghanistan 1997 sp f 2534 36
## # ... with 76,036 more rows
Inilah bentu data yg rapih atau ‘tidy’.