Algoritma dan Pemrograman

Deden Istiawan

ITESA MUHAMMADIYAH
GANJIL 2025

Selamat Datang di R!

L2: database

Mengorganisir: Proyek

Sama seperti kita biasanya bekerja terorganisir dalam folder di komputer, di RStudio kita dapat melakukan hal yang sama untuk bekerja secara efisien dengan membuat proyek.

Sebuah proyek akan menjadi sebuah “folder” di dalam RStudio, sehingga direktori root kita secara otomatis akan menjadi folder proyek itu sendiri (memungkinkan kita berpindah dari satu proyek ke proyek lain menggunakan menu di kanan atas).

Kita dapat membuatnya di folder baru atau di folder yang sudah ada.

Paket Pertama: glue

Cara yang lebih intuitif untuk bekerja dengan teks adalah menggunakan paket glue: hal pertama yang harus dilakukan adalah “membeli bukunya” (jika kita belum pernah melakukannya sebelumnya). Setelah itu muat paketnya

install.packages("glue") # just the first time
library(glue)

Dengan fungsi glue() dari paket tersebut kita dapat menggunakan variabel di dalam string. Misalnya, “umur adalah … tahun”, di mana umur disimpan dalam sebuah variabel.

age <- 34
glue("I am {age} old")
I am 34 old

Di dalam kurung kurawal kita juga bisa menjalankan operasi

units <- "days"
glue("I am {age * 365} {units} old")
I am 12410 days old

Variabel Logika

Tipe fundamental lainnya adalah variabel logika atau biner (dua nilai):

  • TRUE: benar disimpan secara internal sebagai 1.

  • FALSE: salah disimpan secara internal sebagai 0.

single <- FALSE # Single? --> NO
class(single)
[1] "logical"

Karena disimpan secara internal sebagai variabel biner, kita dapat melakukan operasi aritmatika pada mereka

2 * TRUE
[1] 2
FALSE - 1
[1] -1

Variabel Logika

Seperti yang akan kita lihat sebentar lagi, variabel logika sebenarnya dapat mengambil nilai ketiga: NA atau data yang hilang, yang mewakili tidak tersedia, dan akan sangat umum ditemukan dalam database.

missing <- NA
missing + 1
[1] NA

Penting

Variabel logika BUKAN variabel teks: "TRUE" adalah teks, TRUE adalah nilai logika.

TRUE + 1
[1] 2
"TRUE" + 1
Error in "TRUE" + 1: non-numeric argument to binary operator

Kondisi Logika

Nilai logika biasanya merupakan hasil dari mengevaluasi kondisi logika. Misalnya, bayangkan kita ingin memeriksa apakah seseorang bernama Javi.

name <- "María"

Dengan operator logika == kita menanyakan apakah yang kita simpan di kiri sama dengan yang ada di kanan: kita BERTANYA

name == "Javi"
[1] FALSE

Dengan kebalikannya != kita menanyakan apakah berbeda.

name != "Javi"
[1] TRUE

Perhatikan bahwa…

Tidak sama antara <- (penugasan) dengan == (kita sedang bertanya, ini adalah perbandingan logika).

Kondisi Logika

Selain perbandingan “sama dengan” versus “berbeda”, juga terdapat perbandingan urutan seperti kurang dari <, lebih dari >, <= atau >=. Apakah orang tersebut berumur kurang dari 32 tahun?

age <- 34
age < 32 # less than 32 years old?
[1] FALSE

Apakah umurnya lebih dari atau sama dengan 38 tahun?

age >= 38
[1] FALSE

Apakah nama yang tersimpan sama dengan Javi?

name <- "Javi"
name == "Javi"
[1] TRUE

Variabel Tanggal

Tipe data yang sangat khusus: data bertipe tanggal.

date_char <- "2021-04-21"

Terlihat seperti string teks biasa tetapi seharusnya merepresentasikan suatu titik waktu. Apa yang terjadi jika kita menambahkan 1 ke sebuah tanggal?

date_char + 1
Error in date_char + 1: non-numeric argument to binary operator

Tanggal tidak boleh berupa string/teks: kita harus mengonversi string teks menjadi tanggal.

 

Untuk bekerja dengan tanggal kita akan menggunakan paket lubridate, yang harus diinstal sebelum dapat digunakan.

install.packages("lubridate")

Variabel Tanggal

Setelah terinstal, dari semua paket (buku) yang kita miliki, kita akan menginstruksikan untuk memuat paket ini secara spesifik.

library(lubridate) 

Attaching package: 'lubridate'
The following objects are masked from 'package:base':

    date, intersect, setdiff, union

Untuk mengonversi ke tipe tanggal kita akan menggunakan fungsi as_date() dari paket lubridate (format default yyyy-mm-dd).

 

# it's not a date, it's a text!
date_char + 1
Error in date_char + 1: non-numeric argument to binary operator
class(date_char)
[1] "character"
date <- as_date("2023-03-28")
date + 1
[1] "2023-03-29"
class(date)
[1] "Date"

Variabel Tanggal

Dalam as_date() format tanggal default adalah yyyy-mm-dd, jadi jika string tidak dimasukkan dengan benar…

as_date("28-08-2024")
Warning: All formats failed to parse. No formats found.
[1] NA

Untuk format lain kita harus menentukannya dalam argumen opsional format = ... di mana %d mewakili hari, %m bulan, %Y dalam format 4-digit tahun dan %y dalam format 2-digit tahun.

as_date("28-03-2023", format = "%d-%m-%Y")
[1] "2023-03-28"
as_date("28-03-23", format = "%d-%m-%y")
[1] "2023-03-28"
as_date("03-28-2023", format = "%m-%d-%Y")
[1] "2023-03-28"
as_date("28/03/2023", format = "%d/%m/%Y")
[1] "2023-03-28"

Variabel Tanggal

Dalam paket ini kita memiliki fungsi-fungsi yang sangat berguna untuk manajemen tanggal:

  • Dengan today() kita dapat langsung memperoleh tanggal saat ini.
today()
[1] "2026-07-22"
  • Dengan now() kita dapat memperoleh tanggal dan waktu saat ini
now()
[1] "2026-07-22 23:15:58 WIB"
  • Dengan year(), month() atau day() kita dapat mengekstrak tahun, bulan, dan hari
date_today <- today()
year(date_today)
[1] 2026
month(date_today)
[1] 7

Lembar Referensi

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Definisikan sebuah variabel yang menyimpan umurmu (disebut age) dan satu lagi dengan namamu (disebut name).

Code
age <- 34
name <- "Javi"

📝 Periksa dengan variabel age apakah nilainya BUKAN 60 tahun atau apakah namanya "Ornitorrinco" (hasilnya harus berupa variabel logika).

Code
age != 60 # different to
name == "Ornitorrinco" # equal to

📝 Mengapa kode di bawah ini menghasilkan error?

age + name
Error in age + name: non-numeric argument to binary operator

📝 Definisikan variabel lain bernama siblings yang menjawab pertanyaan “apakah kamu punya saudara?” dan variabel lain yang menyimpan tanggal lahirmu (disebut birth_date).

Code
siblings <- TRUE

library(lubridate) # if not before
birth_date <- as_date("1989-09-10")

📝 Definisikan variabel lain dengan nama belakangmu (disebut surname) dan gunakan glue() untuk memiliki, dalam satu variabel bernama full_name, nama depan dan belakangmu yang dipisahkan koma.

Code
surname <- "Álvarez Liébana"
full_name <- glue("{name}, {surname}")
full_name

📝 Dari birth_date ekstrak bulannya.

Code
month(birth_date)

📝 Hitung berapa hari yang telah berlalu sejak tanggal lahirmu hingga hari ini (dengan tanggal lahir yang didefinisikan di Latihan 4).

Code
today() - birth_date

Vektor: Penggabungan

Saat bekerja dengan data, kita sering memiliki kolom yang merepresentasikan variabel: kita akan menyebutnya sebagai vektor, yaitu sebuah gabungan dari sel-sel (nilai) bertipe sama (mirip kolom dalam tabel).

Cara paling sederhana untuk membuat vektor adalah dengan fungsi c() (c singkatan dari concatenate), dan kamu cukup memasukkan elemen di dalam tanda kurung, dipisahkan dengan koma.

ages <- c(32, 27, 60, 61)
ages
[1] 32 27 60 61

Tip

Sebuah angka tunggal x <- 1 (atau x <- c(1)) sebenarnya adalah vektor dengan panjang satu –> semua yang kita tahu cara melakukan dengan angka, dapat kita lakukan dengan vektor angka.

Urutan Numerik

Jenis vektor yang paling umum adalah numerik, khususnya urutan numerik yang terkenal (misalnya, hari-hari dalam sebulan), digunakan antara lain untuk mengindeks loop.

Fungsi seq(start, end) memungkinkan kita membuat urutan numerik dari elemen awal hingga akhir, maju satu per satu.

seq(1, 31)
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22
[23] 23 24 25 26 27 28 29 30 31

Perhatikan bahwa jika kita mencoba ini dengan karakter, tidak akan berhasil karena tidak ada urutan yang telah ditetapkan di antara string teks.

"a":"z"
Warning: NAs introduced by coercion
Warning: NAs introduced by coercion
Error in "a":"z": NA/NaN argument

Urutan Numerik

Sebuah pintasan adalah perintah 1:n, yang mengembalikan hasil yang sama dengan seq(1, n).

1:7
[1] 1 2 3 4 5 6 7

Jika elemen awal lebih besar dari elemen akhir, R memahami bahwa urutannya adalah menurun.

7:-3
 [1]  7  6  5  4  3  2  1  0 -1 -2 -3

Kita juga dapat mendefinisikan langkah yang berbeda antara elemen-elemen berurutan dengan argumen by = ....

seq(1, 7, by = 0.5) # seq from 1 to 7, with a step of 0.5
 [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0

Urutan Numerik

Terkadang kita mungkin ingin mendefinisikan urutan dengan panjang tertentu.

seq(1, 50, l = 7) # seq from 1 to 50 with length equal to 7
[1]  1.000000  9.166667 17.333333 25.500000 33.666667 41.833333
[7] 50.000000

Kita mungkin juga ingin membuat vektor dengan n elemen yang diulang.

rep(0, 7) # vector of 7 0's
[1] 0 0 0 0 0 0 0

Karena disimpan secara internal sebagai angka, kita juga bisa melakukan ini dengan tanggal.

seq(as_date("2023-09-01"), as_date("2023-09-10"), by = 1)
 [1] "2023-09-01" "2023-09-02" "2023-09-03" "2023-09-04" "2023-09-05"
 [6] "2023-09-06" "2023-09-07" "2023-09-08" "2023-09-09" "2023-09-10"

Vektor Teks

Vektor adalah gabungan elemen bertipe sama, namun tidak harus selalu berupa angka. Mari buat sebuah kalimat contoh.

sentence <- "My name is Javi"
sentence
[1] "My name is Javi"
length(sentence)
[1] 1

Pada kasus sebelumnya, itu bukan vektor, melainkan elemen teks tunggal. Untuk membuat vektor, kita perlu menggunakan c() lagi dan memisahkan elemen dengan koma.

sentence <- c("My", "name", "is", "Javi")
sentence
[1] "My"   "name" "is"   "Javi"
length(sentence)
[1] 4

Vektor Teks

Apa yang akan terjadi jika kita menggabungkan elemen dari tipe yang berbeda?

c(1, 2, "javi", "3", TRUE)
[1] "1"    "2"    "javi" "3"    "TRUE"

Perhatikan bahwa karena semua elemen harus bertipe sama, yang dilakukan R adalah mengonversi segalanya ke teks, melanggar integritas data.

c(3, 4, TRUE, FALSE)
[1] 3 4 1 0

Penting untuk dipahami bahwa nilai logika sebenarnya disimpan secara internal sebagai 0/1.

Operasi dengan Vektor

Dengan vektor numerik, kita dapat melakukan operasi aritmatika yang sama seperti dengan angka → sebuah angka adalah vektor (dengan panjang satu).

Apa yang akan terjadi jika kita menambahkan atau mengurangi nilai pada vektor?

x <- c(1, 3, 5, 7)
x + 1
[1] 2 4 6 8
x * 2
[1]  2  6 10 14

Peringatan

Kecuali ditentukan lain, dalam R, operasi vektor selalu dilakukan elemen per elemen.

Penjumlahan Vektor

Vektor juga dapat berinteraksi satu sama lain, sehingga kita dapat mendefinisikan, misalnya, penjumlahan vektor (elemen per elemen).

x <- c(2, 4, 6)
y <- c(1, 3, 5)
x + y
[1]  3  7 11

Karena operasi (misalnya penjumlahan) dilakukan elemen per elemen, apa yang terjadi jika kita menjumlahkan dua vektor dengan panjang berbeda?

z <- c(1, 3, 5, 7)
x + z
Warning in x + z: longer object length is not a multiple of shorter
object length
[1]  3  7 11  9

Yang dilakukannya adalah mendaur ulang elemen: jika kita memiliki vektor dengan 4 elemen dan menambahkan vektor lain dengan 3 elemen, elemen dari vektor yang lebih pendek akan didaur ulang.

Membandingkan Vektor

Operasi yang sangat umum adalah mengajukan pertanyaan pada data menggunakan kondisi logika. Misalnya, jika kita mendefinisikan vektor suhu…

Hari mana yang suhunya di bawah 22 derajat?

x <- c(15, 20, 31, 27, 15, 29)
x < 22
[1]  TRUE  TRUE FALSE FALSE  TRUE FALSE

Ini akan mengembalikan sebuah vektor logika, tergantung apakah setiap elemen memenuhi kondisi yang diberikan (dengan panjang yang sama dengan vektor yang dikueri).

Jika kita memiliki nilai yang hilang (karena kesalahan sensor pada hari itu), kondisi yang dievaluasi juga akan menjadi NA.

y <- c(15, 20, NA, 31, 27, 7, 29, 10)
y < 22
[1]  TRUE  TRUE    NA FALSE FALSE  TRUE FALSE  TRUE

Membandingkan Vektor

Kondisi logika dapat digabungkan dalam dua cara:

  • Irisan: semua kondisi yang digabungkan harus terpenuhi (konjungsi DAN dengan &) untuk mengembalikan TRUE.
x < 30 & x > 15
[1] FALSE  TRUE FALSE  TRUE FALSE  TRUE
  • Gabungan: cukup setidaknya satu kondisi yang terpenuhi (konjungsi ATAU dengan |).
x < 30 | x > 15
[1] TRUE TRUE TRUE TRUE TRUE TRUE

Dengan any() dan all(), kita dapat memeriksa apakah semua elemen memenuhi kondisi.

any(x < 30)
[1] TRUE
all(x < 30)
[1] FALSE

Mengambil Elemen

Operasi umum lainnya adalah mengakses atau mengambil elemen. Cara paling sederhana adalah menggunakan operator [i] (mengakses elemen ke-i).

ages <- c(20, 30, 33, NA, 61) 
ages[3] # get the age's third person
[1] 33

Karena sebuah angka hanyalah vektor dengan panjang satu, operasi ini juga dapat diterapkan menggunakan vektor indeks untuk dipilih.

y <- c("hi", "how", "are", "you", "?")
y[c(1:2, 4)] # first, second and fourth element
[1] "hi"  "how" "you"

Tip

Untuk mengakses elemen terakhir tanpa khawatir tentang posisinya, kamu dapat menggunakan panjang vektor sebagai indeks x[length(x)].

Menghapus Elemen

Terkadang, alih-alih memilih, kita mungkin ingin menghapus elemen. Ini dilakukan dengan operasi yang sama tetapi menggunakan pengindeksan negatif: operator [-i] «membatalkan pilihan» elemen ke-i

y
[1] "hi"  "how" "are" "you" "?"  
y[-2] # everything except the second element
[1] "hi"  "are" "you" "?"  

Dalam banyak kasus, kita ingin memilih atau menghapus elemen berdasarkan kondisi logika, tergantung nilainya, sehingga kita akan meneruskan kondisi itu sendiri sebagai indeks (ingat, x < 2 mengembalikan vektor logika).

ages <- c(15, 21, 30, 17, 45)
names <- c("javi", "maría", "sandra", "carla", "luis")
names[ages < 18] # names of people under 18
[1] "javi"  "carla"

Operasi Statistik

Kita juga dapat menggunakan operasi statistik, seperti sum(), yang, diberikan sebuah vektor, mengembalikan jumlah semua elemennya.

x <- c(1, -2, 3, -1)
sum(x)
[1] 1

Apa yang terjadi ketika data hilang?

x <- c(1, -2, 3, NA, -1)
sum(x)
[1] NA

Secara default, jika ada data yang hilang, operasi tersebut juga akan menghasilkan nilai yang hilang. Untuk mengabaikan data yang hilang, gunakan argumen opsional na.rm = TRUE.

sum(x, na.rm = TRUE)
[1] 1

Operasi Statistik

Seperti yang telah disebutkan, nilai logika disimpan secara internal sebagai 0 dan 1, sehingga kita dapat menggunakannya dalam operasi aritmatika.

Misalnya, jika kita ingin mengetahui jumlah elemen yang memenuhi kondisi (misalnya, kurang dari 3), yang memenuhi akan diberi nilai 1 (TRUE), dan yang tidak akan diberi 0 (FALSE). Oleh karena itu, menjumlahkan vektor logika akan memberi kita jumlah elemen yang memenuhi kondisi.

x <- c(2, 4, 6)
sum(x < 3)
[1] 1

Operasi Statistik

Operasi umum lain yang berguna adalah jumlah kumulatif dengan cumsum(), yang, diberikan sebuah vektor, mengembalikan vektor di mana setiap elemen adalah jumlah dari elemen pertama, pertama ditambah kedua, pertama ditambah kedua ditambah ketiga, dan seterusnya.

x <- c(1, 5, 2, -1, 8)
cumsum(x)
[1]  1  6  8  7 15

Apa yang terjadi ketika data hilang?

x <- c(1, -2, 3, NA, -1)
cumsum(x)
[1]  1 -1  2 NA NA

Dalam kasus jumlah kumulatif, yang terjadi adalah dari titik itu ke depan, semua nilai kumulatif berikutnya akan menjadi hilang.

Operasi Statistik

Operasi umum lain yang berguna adalah perbedaan (dengan jeda) dengan diff() yang, diberikan sebuah vektor, mengembalikan vektor dengan elemen kedua dikurangi pertama, ketiga dikurangi kedua, keempat dikurangi ketiga…dan seterusnya.

x <- c(1, 8, 5, 3, 9, 0, -1, 5)
diff(x)
[1]  7 -3 -2  6 -9 -1  6

Menggunakan argumen lag = kita dapat menentukan jeda dari perbedaan ini (misalnya lag = 3 berarti elemen keempat dikurangi pertama, kelima dikurangi kedua, dst.).

x <- c(1, 8, 5, 3, 9, 0, -1, 5)
diff(x, lag = 3)
[1]  2  1 -5 -4 -4

Operasi Statistik

Operasi umum lainnya adalah rata-rata, median, persentil, dll.

  • Rata-rata: ukuran pemusatan yang terdiri dari menjumlahkan semua elemen dan membaginya dengan jumlah elemen. Paling dikenal namun paling tidak robust: jika ada pencilan (nilai sangat besar atau sangat kecil), rata-rata sangat mudah terganggu.
x <- c(165, 170, 181, 191, 150, 155, 167, NA, 173, 177)
mean(x, na.rm = TRUE)
[1] 169.8889

Operasi Statistik

Operasi umum lainnya adalah rata-rata, median, persentil, dll.

  • Median: ukuran pemusatan yang terdiri dari mengurutkan elemen dan mengambil yang ada di tengah.
x <- c(165, 170, 181, 191, 150, 155, 167, 173, 177)
median(x)
[1] 170
  • Kuantil: ukuran posisi (membagi data menjadi bagian-bagian yang sama).
quantile(x) # by default quantiles/percentiles 0-25-50-75-100
  0%  25%  50%  75% 100% 
 150  165  170  177  191 
quantile(x, probs = c(0.1, 0.4, 0.9))
  10%   40%   90% 
154.0 167.6 183.0 

Mengurutkan Vektor

Terakhir, tindakan umum adalah mengetahui cara mengurutkan nilai:

  • sort(): mengembalikan vektor yang sudah diurutkan. Secara default dari terkecil ke terbesar tetapi dengan decreasing = TRUE bisa diubah.
ages <- c(81, 7, 25, 41, 65, 20, 33, 23, 77)
sort(ages)
[1]  7 20 23 25 33 41 65 77 81
sort(ages, decreasing = TRUE)
[1] 81 77 65 41 33 25 23 20  7
  • order(): mengembalikan vektor indeks yang harus kita gunakan untuk mengurutkan vektor
order(ages)
[1] 2 6 8 3 7 4 5 9 1
ages[order(ages)]
[1]  7 20 23 25 33 41 65 77 81

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Definisikan vektor x sebagai gabungan 5 bilangan ganjil pertama. Hitung panjang vektor tersebut.

Code
# Two ways
x <- c(1, 3, 5, 7, 9)
x <- seq(1, 9, by = 2)

length(x)

📝 Akses elemen ketiga dari x. Akses elemen terakhir (terlepas dari panjangnya, kode yang selalu bisa dijalankan). Hapus elemen pertama.

Code
x[3]
x[length(x)]
x[-1]

📝 Dapatkan elemen x yang lebih besar dari 4. Hitung vektor 1/x dan simpan dalam variabel.

Code
x[x > 4]
z <- 1/x
z

📝 Buat vektor yang merepresentasikan nama 5 orang, salah satunya tidak diketahui.

Code
names <- c("Javi", "Sandra", NA, "Laura", "Carlos")
names

📝 Dari vektor x latihan di atas, temukan elemen yang lebih besar dari 1 dan lebih kecil dari 7 (ketat). Temukan cara untuk mengetahui apakah semua elemen positif atau tidak.

Code
x[x > 1 & x < 7]
all(x > 0)

📝 Diberikan vektor x <- c(1, -5, 8, NA, 10, -3, 9), mengapa rata-ratanya mengembalikan bukan angka tetapi seperti yang ditunjukkan kode di bawah?

x <- c(1, -5, 8, NA, 10, -3, 9)
mean(x)
[1] NA

📝 Diberikan vektor x <- c(1, -5, 8, NA, 10, -3, 9), ekstrak elemen yang menempati lokasi 1, 2, 5, 6.

Code
x <- c(1, -5, 8, NA, 10, -3, 9)
x[c(1, 2, 5, 6)]
x[-2]

📝 Diberikan vektor x dari latihan sebelumnya, mana yang memiliki data hilang? Petunjuk: fungsi is.sesuatu() memeriksa apakah elemen bertipe sesuatu (tekan tab).

Code
is.na(x)

📝 Definisikan vektor x sebagai gabungan 4 bilangan genap pertama. Hitung jumlah elemen x yang kurang dari 5 (ketat).

Code
x[x < 5] 
sum(x < 5)

📝 Hitung vektor 1/x dan dapatkan versi terurut (dari terkecil ke terbesar) dalam dua cara yang memungkinkan.

Code
z <- 1/x
sort(z)
z[order(z)]

📝 Hitung nilai minimum dan maksimum dari vektor x sebelumnya.

Code
min(x)
max(x)

📝 Dari vektor x, temukan elemen yang lebih besar dari 1 dan lebih kecil dari 6 (ketat). Temukan cara untuk mengetahui apakah semua elemen negatif atau tidak.

Code
x[x > 1 & x < 7]
all(x > 0)

Lebih Lanjut dengan Variabel Teks

Meskipun kita tidak dapat melakukan operasi aritmatika dengan mereka, beberapa operasi yang dapat kita lakukan dengan string teks akan penting.

Untuk itu kita akan menggunakan paket stringr (dalam “alam semesta paket” yang sama dengan lubridate, yang akan kita bahas nanti).

library(stringr)

# Find a correct phone format
phone_number <- c("611093", "292039", "628810585", "600917043")
str_detect(phone_number, pattern = "[6]{1}[0-9]{8}")
[1] FALSE FALSE  TRUE  TRUE

Database Pertama

Saat menganalisis data kita biasanya memiliki beberapa variabel untuk setiap individu: kita memerlukan “tabel” untuk mengumpulkannya. Pilihan paling langsung adalah matriks: gabungan variabel bertipe sama dan panjang yang sama.

Bayangkan kita memiliki tinggi dan berat badan 4 orang. Bagaimana cara membuat dataset dengan dua variabel tersebut?

Pilihan paling umum adalah menggunakan cbind(): menggabungkan (bind) vektor dalam bentuk kolom (c)

h <- c(150, 160, 170, 180)
w <- c(63, 70, 85, 95)
data_mat <- cbind(h, w)
data_mat 
       h  w
[1,] 150 63
[2,] 160 70
[3,] 170 85
[4,] 180 95

Database Pertama

Kita juga dapat membangun matriks berdasarkan baris dengan fungsi rbind() (gabungkan - bind - berdasarkan baris - r), meskipun disarankan memiliki setiap variabel dalam kolom dan individu dalam baris sebagaimana yang akan kita lihat nanti.

rbind(h, w) # Matrix by rows
  [,1] [,2] [,3] [,4]
h  150  160  170  180
w   63   70   85   95
  • Kita dapat “melihat” matriks dengan View(matrix).
  • Kita dapat memeriksa dimensi dengan dim(), nrow() dan ncol(): matriks adalah jenis data tabular (terorganisir dalam baris dan kolom).
dim(data_mat)
[1] 4 2
nrow(data_mat)
[1] 4
ncol(data_mat)
[1] 2

Database Pertama

Kita juga dapat “membalik” (matriks transpos) dengan t().

t(data_mat)
  [,1] [,2] [,3] [,4]
h  150  160  170  180
w   63   70   85   95

Karena sekarang kita memiliki dua dimensi dalam data, untuk mengakses elemen dengan [] kita harus memberikan dua indeks yang dipisahkan koma: indeks baris dan kolom

data_mat[2, 1] # second row, first column
  h 
160 
data_mat[1, 2] # first row, second column
 w 
63 

Database Pertama

Dalam beberapa kasus kita ingin mendapatkan seluruh data untuk satu individu (baris tertentu tapi semua kolom) atau nilai dari satu variabel lengkap untuk semua individu (kolom tertentu tapi semua baris). Untuk itu, kita kosongkan salah satu indeks.

data_mat[2, ] # second individual
  h   w 
160  70 
data_mat[, 1] # first variable
[1] 150 160 170 180

Banyak hal yang telah kita pelajari dengan vektor dapat kita lakukan dengan matriks, sehingga kita dapat mengakses beberapa baris dan/atau kolom menggunakan urutan bilangan bulat 1:n

data_mat[c(1, 3), 1] # first variable for first and third individual
[1] 150 170

Database Pertama

Kita juga dapat mendefinisikan matriks dari vektor numerik, menyusun ulang nilai-nilai dalam bentuk matriks (dengan mengetahui bahwa elemen-elemen ditempatkan berdasarkan kolom).

z <- matrix(1:9, ncol = 3) 
z
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

Kita bahkan dapat mendefinisikan array dengan nilai konstan, misalnya nol (untuk diisi nanti)

matrix(0, nrow = 2, ncol = 3)
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0

Operasi Matriks

Dengan matriks sama seperti dengan vektor: saat kita menerapkan operasi aritmatika kita melakukannya elemen per elemen

z/5
     [,1] [,2] [,3]
[1,]  0.2  0.8  1.4
[2,]  0.4  1.0  1.6
[3,]  0.6  1.2  1.8

Untuk melakukan operasi dalam arti matriks kita harus menambahkan %%%, misalnya, untuk mengalikan matriks menggunakan %*%.

z * t(z)
     [,1] [,2] [,3]
[1,]    1    8   21
[2,]    8   25   48
[3,]   21   48   81
z %*% t(z)
     [,1] [,2] [,3]
[1,]   66   78   90
[2,]   78   93  108
[3,]   90  108  126

Operasi Matriks

Kita juga dapat melakukan operasi per kolom/baris tanpa loop dengan fungsi apply(), dan kita akan menunjukkan sebagai argumen

  • matriks
  • arah operasi (MARGIN = 1 untuk baris, MARGIN = 2 untuk kolom)
  • fungsi yang akan diterapkan
  • argumen tambahan yang diperlukan oleh fungsi

Misalnya, untuk menerapkan rata-rata pada setiap variabel, gunakan mean dengan MARGIN = 2 (fungsi yang sama untuk setiap kolom).

# Mean for each column (MARGIN = 2)
apply(data_mat, MARGIN = 2, FUN = "mean")
     h      w 
165.00  78.25 

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Modifikasi kode di bawah untuk mendefinisikan matriks x berisi satu-satu, dengan 3 baris dan 7 kolom.

x <- matrix(0, nrow = 2, ncol = 3)
x
Code
x <- matrix(1, nrow = 3, ncol = 7)
x

📝 Pada matriks di atas, tambahkan 1 ke setiap angka dan bagi hasilnya dengan 5. Kemudian hitung transposnya.

Code
new_matrix <- (x + 1)/5
t(new_matrix)

📝 Mengapa kode di bawah ini mengembalikan pesan peringatan seperti itu?

matrix(1:15, nrow = 4)
Warning in matrix(1:15, nrow = 4): data length [15] is not a
sub-multiple or multiple of the number of rows [4]
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12    1

📝 Definisikan matriks x <- matrix(1:12, nrow = 4). Kemudian dapatkan data individu pertama, data variabel ketiga, dan elemen (4, 1).

Code
x <- matrix(1:12, nrow = 4)
x[1, ] # first row
x[, 3] # third column
x[4, 1] # (4, 1) element

📝 Definisikan matriks dengan 2 variabel dan 3 individu sehingga setiap variabel mencatat tinggi dan umur 3 orang, di mana umur orang kedua tidak diketahui. Kemudian hitung rata-rata setiap variabel (kita harus mendapatkan angka!).

Code
data <- cbind("age" = c(20, NA, 25), "h" = c(160, 165, 170))
apply(data, MARGIN = 2, FUN = "mean", na.rm = TRUE) # mean by columns

📝 Mengapa kode di bawah ini mengembalikan error? Apa yang salah?

mat <- cbind("age" = c(15, 20, 25), "names" = c("javi", "sandra", "carlos"))
mat
     age  names   
[1,] "15" "javi"  
[2,] "20" "sandra"
[3,] "25" "carlos"
mat + 1
Error in mat + 1: non-numeric argument to binary operator

Percobaan Kedua: data.frame

Array memiliki masalah yang sama dengan vektor: jika kita menggabungkan data dari tipe yang berbeda, integritas data terganggu karena akan dikonversi (lihat kode di bawah: umur dan TRUE/FALSE dikonversi ke teks).

ages <- c(14, 24, NA)
single <- c(TRUE, NA, FALSE)
names <- c("javi", "laura", "lucía")
mat <- cbind(ages, single, names)
mat
     ages single  names  
[1,] "14" "TRUE"  "javi" 
[2,] "24" NA      "laura"
[3,] NA   "FALSE" "lucía"

Bahkan, karena bukan angka, kita tidak dapat lagi melakukan operasi aritmatika.

mat + 1
Error in mat + 1: non-numeric argument to binary operator

Percobaan Kedua: data.frame

Untuk bekerja dengan variabel dari tipe yang berbeda kita memiliki di R yang dikenal sebagai data.frame: gabungan variabel dengan panjang sama tetapi dapat bertipe berbeda.

table <- data.frame(ages, single, names)
class(table)
[1] "data.frame"
table
  ages single names
1   14   TRUE  javi
2   24     NA laura
3   NA  FALSE lucía

Percobaan Kedua: data.frame

Karena sebuah data.frame sudah merupakan upaya membuat database, variabel bukan sekadar vektor matematika: mereka memiliki makna dan kita dapat (kita harus) memberikan nama yang mendeskripsikan maknanya.

library(lubridate)
table <-
  data.frame("ages" = ages, "single" = single, "names" = names,
             "birth_date" = as_date(c("1989-09-10", "1992-04-01", "1980-11-27")))
table
  ages single names birth_date
1   14   TRUE  javi 1989-09-10
2   24     NA laura 1992-04-01
3   NA  FALSE lucía 1980-11-27

Percobaan Kedua: data.frame

Kita memiliki dataset pertama kita! (secara ketat kita belum bisa menyebutnya database, tetapi untuk saat ini tampilannya seperti itu). Kamu dapat memvisualisasikannya dengan mengetik namanya di konsol atau dengan View(table).

Mengakses Variabel

Jika kita ingin mengakses elemennya, karena ini data tabular, kita dapat mengaksesnya seperti di matriks (tidak disarankan): sekali lagi kita memiliki dua indeks (baris dan kolom, biarkan kosong yang tidak digunakan)

table[2, ]  # second row (all variables)
  ages single names birth_date
2   24     NA laura 1992-04-01
table[, 3]  # third column (all individuals)
[1] "javi"  "laura" "lucía"
table[2, 1] # first variable of the second individual
[1] 24

Tetapi juga memiliki keunggulan sebuah database: kita dapat mengakses variabel berdasarkan nama (disarankan karena variabel dapat berpindah posisi dan sekarang memiliki makna), dengan meletakkan nama tabel diikuti simbol $ (dengan tab, menu kolom untuk dipilih akan muncul).

Fungsi Informasi

  • names(): menampilkan nama-nama variabel
names(table)
[1] "ages"       "single"     "names"      "birth_date"
dim(table)
[1] 3 4
  • Variabel dapat diakses berdasarkan nama
table[c(1, 3), "names"]
[1] "javi"  "lucía"
table$names[c(1, 3)]
[1] "javi"  "lucía"

Menambahkan Variabel

Jika kita sudah memiliki data dan ingin menambahkan kolom, cukup gunakan fungsi data.frame() yang sudah kita pelajari untuk menggabungkan kolom. Mari tambahkan misalnya variabel baru, jumlah saudara kandung setiap individu.

# add a new column
siblings <- c(0, 2, 3)
table <- data.frame(table, "n_sib" = siblings)
table
  ages single names birth_date n_sib
1   14   TRUE  javi 1989-09-10     0
2   24     NA laura 1992-04-01     2
3   NA  FALSE lucía 1980-11-27     3

Upaya Terakhir: tibble

Tabel dalam format data.frame memiliki beberapa keterbatasan. Keterbatasan utamanya adalah tidak mengizinkan rekursi: bayangkan kita mendefinisikan database dengan tinggi dan berat badan, dan kita ingin variabel ketiga berupa BMI.

data.frame("height" = c(1.7, 1.8, 1.6), "weight" = c(80, 75, 70),
           "BMI" = weight / (height^2))
Error: object 'weight' not found

Selanjutnya kita akan menggunakan format tibble (data.frame yang disempurnakan) dari paket tibble.

library(tibble)
data_tb <- 
  tibble("height" = c(1.7, 1.8, 1.6), "weight" = c(80, 75, 70), "BMI" = weight / (height^2))
class(data_tb)
[1] "tbl_df"     "tbl"        "data.frame"
data_tb
# A tibble: 3 × 3
  height weight   BMI
   <dbl>  <dbl> <dbl>
1    1.7     80  27.7
2    1.8     75  23.1
3    1.6     70  27.3

Upaya Terakhir: tibble

data_tb <- 
  tibble("height" = c(1.7, 1.8, 1.6), "weight" = c(80, 75, 70), "BMI" = weight / (height^2))
class(data_tb)
[1] "tbl_df"     "tbl"        "data.frame"
data_tb
# A tibble: 3 × 3
  height weight   BMI
   <dbl>  <dbl> <dbl>
1    1.7     80  27.7
2    1.8     75  23.1
3    1.6     70  27.3

Tabel dalam format tibble memungkinkan kita pengelolaan data yang lebih cepat, efisien, dan konsisten, dengan 4 keunggulan utama:

  • Metainformasi: jika melihat headernya, secara otomatis menampilkan jumlah baris dan kolom, serta tipe setiap variabel
  • Rekursivitas: memungkinkan mendefinisikan variabel secara berurutan (seperti yang sudah kita lihat)

Last attempt: tibble

  • Konsistensi: jika mengakses kolom yang tidak ada, akan memberikan peringatan
data_tb$invent
Warning: Unknown or uninitialised column: `invent`.
NULL
  • Berdasarkan baris: buat berdasarkan baris (salin-tempel dari tabel) dengan tribble().
tribble(~colA, ~colB,
        "a",   1,
        "b",   2)
# A tibble: 2 × 2
  colA   colB
  <chr> <dbl>
1 a         1
2 b         2

Tip

Paket datapasta memungkinkan kita menyalin dan menempel tabel dari halaman web dan dokumen sederhana sebagai tribble. See more in https://milesmcbain.github.io/datapasta/articles/how-to-datapasta.html#pasting-a-table-as-a-formatted-tibble-definition-with-tribble_paste

Ringkasan…

  • Setiap sel dapat bertipe berbeda: angka, teks, tanggal, nilai logika, dll. Sebuah vektor adalah gabungan sel (kolom-kolom masa depan tabel kita) –> Dalam R secara default operasi dilakukan elemen per elemen.
  • Sebuah matriks memungkinkan kita menggabungkan variabel bertipe SAMA dan panjang SAMA –> data tabular.
  • Sebuah data.frame memungkinkan kita menggabungkan variabel bertipe BERBEDA dan panjang SAMA –> kita akan menggunakan tibble sebagai opsi database yang disempurnakan.

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Muat dari paket {datasets} dataset airquality (variabel kualitas udara New York dari Mei hingga September 1973). Apakah dataset airquality bertipe tibble? Jika tidak, konversikan ke tibble (lihat dokumentasi paket di https://tibble.tidyverse.org/index.html).

Code
library(tibble)
class(datasets::airquality)
airquality_tb <- as_tibble(datasets::airquality)

📝 Setelah dikonversi ke tibble, dapatkan nama variabel dan dimensi dataset. Berapa banyak variabel? Berapa banyak hari yang telah diukur?

Code
names(airquality_tb)
ncol(airquality_tb)
nrow(airquality_tb)

📝 Filter hanya data pengamatan kelima

Code
airquality_tb[5, ]

📝 Filter hanya data untuk bulan Agustus. Bagaimana cara menyampaikan bahwa kita hanya ingin baris yang memenuhi kondisi tertentu?

Code
airquality_tb[airquality_tb$Month == 8, ]

# other way
var_month <- airquality_tb$Month
airquality_tb[var_month == 8, ]

📝 Pilih data yang bukan dari bulan Juli atau Agustus.

Code
airquality_tb[airquality_tb$Month != 7 & airquality_tb$Month != 8, ]
airquality_tb[!(airquality_tb$Month %in% c(7, 8)), ]

📝 Modifikasi kode berikut untuk menyimpan hanya variabel ozon dan suhu (terlepas dari posisinya).

airquality_tb[, 3]

📝 Pilih data suhu dan angin untuk bulan Agustus.

Code
airquality_tb[airquality_tb$Month == 8, c("Temp", "Wind")]

📝 Terjemahkan nama variabel ke dalam bahasa Indonesia.

Code
names(airquality_tb) <- c("ozono", "rad_solar", "viento", "temp", "mes", "dia") 

🐣 Studi Kasus I

Dalam paket {datasets} (sudah terinstal secara default) kita memiliki beberapa dataset, salah satunya adalah airquality. Di bawah ini saya mengekstrak 3 variabel dari dataset tersebut (perhatikan cara mengaksesnya dengan data$variable, simbol dolar akan penting ke depannya). Data ini merekam pengukuran harian (n = 153 observasi) kualitas udara di New York, dari Mei hingga September 1973. Enam 6 variabel diukur: kadar ozon, radiasi matahari, angin, suhu, bulan, dan hari.

library(datasets)
temperature <- airquality$Temp
month <- airquality$Month
day <- airquality$Day

Coba jawab pertanyaan-pertanyaan yang ada di workbook

🐣 Studi Kasus II

Kita akan menggunakan file surveys.RData yang berisi semua survei jajak pendapat untuk Spanyol dari 1982 hingga 2019.

load(file = "./data/surveys.RData")
survey_data
# A tibble: 139,944 × 8
   date_elec  pollster field_date_from field_date_to exit_poll  size
   <date>     <chr>    <date>          <date>        <lgl>     <dbl>
 1 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 2 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 3 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 4 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 5 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 6 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 7 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 8 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
 9 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
10 1982-10-28 PSOE     1982-10-28      1982-10-28    TRUE      85300
# ℹ 139,934 more rows
# ℹ 2 more variables: party <chr>, estimation <dbl>

Coba jawab pertanyaan-pertanyaan yang ada di workbook

L3: if-else dan Quarto

Struktur alur: if-else dan loop. Fungsi di R. Quarto

Struktur Alur

Sebuah struktur alur atau kontrol terdiri dari serangkaian perintah yang bertujuan untuk menentukan jalur yang harus diikuti kode kamu

  • Jika kondisi A terpenuhi, apa yang terjadi?

  • Bagaimana jika B terjadi?

  • Bagaimana saya bisa mengulang ekspresi yang sama (tergantung pada sebuah variabel)?

Jika kamu pernah membuat program sebelumnya, kamu mungkin sudah familiar dengan yang dikenal sebagai struktur kondisional seperti if (bla bla) {...} else {...} atau loop for/while (sedapat mungkin dihindari).

If

Salah satu struktur kontrol yang paling terkenal adalah yang dikenal sebagai struktur kondisional if.

JIKA serangkaian kondisi terpenuhi (TRUE), maka jalankan apa pun yang ada di dalam tanda kurung kurawal.

Misalnya, struktur if (x == 1) { code A } yang dilakukannya adalah menjalankan kode A dalam tanda kurung kurawal tetapi HANYA JIKA kondisi dalam tanda kurung benar (hanya jika x adalah 1). Dalam kasus lain, tidak akan melakukan apa-apa

Misalnya, mari definisikan vektor umur 8 orang

ages <- c(14, 17, 24, 56, 31, 20, 87, 73)
ages < 18
[1]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

If

Struktur kondisional kita akan melakukan hal berikut: jika ada yang di bawah umur, akan mencetak sebuah pesan.

if (any(ages < 18)) { 
  
  print("There is a minor")
  
}
[1] "There is a minor"

If

if (any(ages < 18)) { 
  
  print("There is a minor")
  
}

Jika kondisi tidak benar di dalam if() (FALSE), tidak ada yang terjadi.

if (all(ages >= 18)) { 
  
  print("All of them are of legal age")
  
}

Kita tidak mendapat pesan karena kondisi all(ages >= 18) bukan TRUE, sehingga tidak mengeksekusi apa-apa.

If-else

Struktur if (condition) { code A } dapat digabungkan dengan else { code B }: ketika kondisi tidak terpenuhi, ia akan menjalankan kode alternatif B di dalam else { }, memungkinkan kita memutuskan apa yang terjadi ketika kondisi terpenuhi dan ketika tidak

Misalnya, if (x == 1) { code A } else { code B } akan menjalankan A jika x sama dengan 1 dan B dalam kasus lainnya.

if (all(ages >= 18)) { 
  
  print("All of them are of legal age")
  
} else {
  
  print("There is a minor")
}
[1] "There is a minor"

If-else

Struktur if - else ini dapat ditumpuk: bayangkan kita ingin menjalankan kode jika semua di bawah umur; jika tidak, tetapi semua berumur di atas 16, lakukan hal lain; dalam kasus lainnya, lakukan tindakan lain.

if (all(ages >= 18)) { 
  
  print("All of them are of legal age")
  
} else if (all(ages >= 16)) {
  
  print("There is a minor but all of them are greater or equal to 16 years old")
  
} else { print("There are any persons under 16 years of age") }
[1] "There are any persons under 16 years of age"

Tips

Kamu bisa memperkecil struktur dengan mengklik panah kiri di script-mu.

If-else Tervektorisasi

Struktur kondisional ini dapat di-vektorisasi (dalam satu baris) dengan if_else() (dari paket dplyr), yang argumennya adalah

  • kondisi yang akan dievaluasi

  • apa yang terjadi ketika terpenuhi dan ketika tidak

  • argumen opsional untuk saat kondisi yang dievaluasi adalah NA

Kita akan memberi label bukan lebih besar/lebih kecil dan unknown ketika tidak diketahui.

library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
ages <- c(NA, ages)
if_else(ages >= 18, "legal age", "minor", missing = "unknown")
[1] "unknown"   "minor"     "minor"     "legal age" "legal age"
[6] "legal age" "legal age" "legal age" "legal age"

Dalam R base ada ifelse(): tidak memungkinkan kamu menentukan apa yang harus dilakukan dengan yang tidak ada, tetapi memungkinkan menentukan tipe data yang berbeda dalam TRUE dan FALSE.

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Apa yang akan menjadi output dari kode berikut?

if_else(sqrt(9) < 2, sqrt(9), 0)
Code
The output is 0 since sqrt(9) equals 3, and since it is not less than 2, it returns the second argument which is 0.

📝 Apa yang akan menjadi output dari kode berikut?

x <- c(1, NA, -1, 9)
if_else(sqrt(x) < 2, 0, 1)
Code
The output is the vector c(0, NA, NA, 1) since sqrt(1) is less than 2, sqrt(9) is not, and in the case of both sqrt(NA) (root of absent) and sqrt(-1) (returns NaN, not a number), its square root cannot be checked whether it is less than 2 or not, so the output is NA.

📝 Modifikasi kode di bawah sehingga, ketika akar kuadrat suatu angka tidak dapat diverifikasi kurang dari 2, mengembalikan -1.

x <- c(1, NA, -1, 9)
if_else(sqrt(x) < 2, 0, 1)
Code
x <- c(1, NA, -1, 9)
if_else(sqrt(x) < 2, 0, 1, missing = -1)

📝 Apa nilai x dan y dari kode di bawah untuk z <- 1, z <- -1, dan z <- -5?

z <- -1
if (z > 0) {
  
  x <- z^3
  y <- -sqrt(z)
  
} else if (abs(z) < 2) {
  
  x <- z^4
  y <- sqrt(-z)
  
} else {
  
  x <- z/2
  y <- abs(z)
  
}
Code
In the first case x = 1 and y = -1. In the second case x = 1 and y = 1. In the third case -1 and 2.

📝 Apa yang akan terjadi jika kita menjalankan kode di bawah ini?

z <- "a"
if (z > 0) {
  
  x <- z^3
  y <- -sqrt(z)
  
} else if (abs(z) < 2) {
  
  x <- z^4
  y <- sqrt(-z)
  
} else {
  
  x <- z/2
  y <- abs(z)
  
}
Code
# will give error since it is not a numeric argument
Error in z^3 : non-numeric argument to binary operator

📝 Dari paket lubridate, fungsi hour() mengembalikan jam dari tanggal tertentu, dan now() mengembalikan tanggal dan waktu saat ini. Dengan kedua fungsi tersebut, buat cat() mencetak “selamat malam” hanya setelah pukul 21:00.

Code
# loading library
library(lubridate)

# Current date-time
current_dt <- now()

# If structure
if (hour(current_dt) > 21) {
  
  cat("Good night") # print or cat (two ways of printing)
}

Berkomunikasi: rmd dan Quarto

Salah satu kekuatan utama R adalah kemudahan menghasilkan laporan, buku, web, catatan, bahkan slide (materi ini sendiri misalnya). Untuk itu, instal terlebih dahulu

  • paket rmarkdown (untuk menghasilkan file .rmd)
install.packages("rmarkdown")
  • instal Quarto (jika sudah mengenal R, .rmd “baru” sekarang menjadi .qmd)

Berkomunikasi: rmd dan Quarto

Sejauh ini kita hanya membuat program dalam skrip (file .R) dalam proyek, tetapi dalam banyak kesempatan kita tidak akan bekerja sendiri dan kita perlu mengkomunikasikan hasilnya dalam berbagai format:

  • catatan (untuk diri sendiri)
  • slide
  • halaman web
  • laporan

Untuk semua ini kita akan menggunakan Quarto (lihat lebih lanjut di https://ivelasq.quarto.pub/intro-to-quarto/)

Berkomunikasi: rmd dan Quarto

File dengan ekstensi .qmd (atau .rmd sebelumnya) akan memungkinkan kita dengan mudah menggabungkan:- Markdown:

  • bahasa penulisan yang memungkinkan kita membuat konten sederhana (seperti wordpress, dengan teks, tebal, miring, dll) dengan tata letak yang mudah dibaca.
  • Matematika (latex): bahasa untuk menulis notasi matematika seperti \(x^2\) atau \(\sqrt{y}\) atau \(\int_{a}^{b} f(x) dx\).
  • Kode dan output: kita tidak hanya dapat menampilkan langkah akhir tetapi juga kode yang sudah dibuat (dalam R, Python, C++, Julia, …), dengan kotak kode yang disebut CHUNK.
  • Gambar, grafik, tabel, gaya (css, js), dll.

Berkomunikasi: rmd dan Quarto

Keunggulan utama membuat materi semacam ini di Quarto/Rmarkdown adalah, dengan melakukannya dari RStudio, kamu dapat membuat laporan atau presentasi tanpa meninggalkan lingkungan pemrograman tempat kamu bekerja. Dengan cara ini kamu dapat menganalisis data, merangkumnya dan sekaligus mengkomunikasikannya dengan alat yang sama.

Baru-baru ini tim RStudio mengembangkan Quarto, versi yang disempurnakan dari Rmarkdown (file .qmd), dengan format yang sedikit lebih estetik dan sederhana. Semua dokumentasi dan contoh tersedia di https://quarto.org/

Contoh-contoh Quarto

Gambar diperoleh dari https://ivelasq.quarto.pub/intro-to-quarto/#/working-with-the-rstudio-visual-editor

Laporan Pertama Kita

Kita akan membuat file rmarkdown pertama dengan Quarto berekstensi .qmd. Untuk itu kita hanya perlu mengklik

File << New File << Quarto Document

Laporan Pertama Kita

Setelah itu, beberapa pilihan format output:

  • File .pdf

  • .html file (recommendable): dynamic document, allows user interaction, like a “web page”.

  • File .doc (tidak disarankan).

Untuk saat ini kita akan membiarkan format HTML default yang dipilih, dan kita akan menulis judul dokumen kita. Setelah itu kita akan memiliki file .qmd (bukan lagi skrip .R seperti yang kita buka sejauh ini).

Laporan Pertama Kita

Kamu seharusnya memiliki sesuatu yang mirip dengan tangkapan gambar dengan dua mode pengeditan: Source (dengan kode, pilihan yang disarankan sampai kamu menguasainya) dan Visual (lebih seperti blog).

Untuk menjalankan SELURUH dokumen kamu harus mengklik Render on Save dan menyimpannya.

Format Output Quarto

Kamu seharusnya mendapatkan output html yang serupa ini (dan sebuah file html telah dibuat di komputermu).

Editor: source vs visual

Seperti yang ditunjukkan, kamu memiliki dua cara bekerja: dengan kode murni dan sesuatu yang mirip dengan Notion (blog).

Gambar diambil dari https://ivelasq.quarto.pub/intro-to-quarto/#/working-with-the-rstudio-visual-editor

Laporan Pertama Kita

File .qmd pada dasarnya dibagi menjadi tiga bagian:

  • Header: bagian yang ada di awal di antara ---.

  • Teks: yang dapat kita format dan perkuat dengan tebal (ditulis sebagai tebal, dengan tanda bintang ganda di awal dan akhir), miring (miring, dengan garis bawah di awal dan akhir) atau menyorot nama fungsi atau variabel dari R. Kamu dapat menambahkan persamaan seperti \(x^2\) (saya menulisnya $x^2$, di antara tanda dolar).

  • Kode R

Header

The header dalam format YAML dan berisi metadata dari dokumen.

  • title dan subtitle: judul/subjudul dokumen
  • author: penulis dokumen
  • format: format output (dapat dikustomisasi)
    • theme: jika memiliki file gaya
    • toc: apakah ingin daftar isi atau tidak
    • toc-location: posisi daftar isi
    • toc-title: judul daftar isi
  • editor: apakah dalam mode visual atau source.
---
title: "latihan"
author: "nama penulis"
format:
  html:
editor: visual
---

Header

The header dalam format YAML dan berisi metadata dari dokumen.

  • title dan subtitle: judul/subjudul dokumen
  • author: penulis dokumen
  • format: format output (dapat dikustomisasi)
    • theme: jika memiliki file gaya
    • toc: apakah ingin daftar isi atau tidak
    • toc-location: posisi daftar isi
    • toc-title: judul daftar isi
  • editor: apakah dalam mode visual atau source.
---
title: "latihan"
author: "nama penulis"
format:
  html:
    style: style.css
    toc: true
editor: visual
---

Header

The header dalam format YAML dan berisi metadata dari dokumen.

  • title dan subtitle: judul/subjudul dokumen
  • author: penulis dokumen
  • format: format output (dapat dikustomisasi)
    • theme: jika memiliki file gaya
    • toc: apakah ingin daftar isi atau tidak
    • toc-location: posisi daftar isi
    • toc-title: judul daftar isi
  • editor: apakah dalam mode visual atau source.
---
title: "latihan"
author: "nama penulis"
format:
  html:
    style: style.css
    toc: true
    toc-location: left
editor: visual
---

Header

The header dalam format YAML dan berisi metadata dari dokumen.

  • title dan subtitle: judul/subjudul dokumen
  • author: penulis dokumen
  • format: format output (dapat dikustomisasi)
    • theme: jika memiliki file gaya
    • toc: apakah ingin daftar isi atau tidak
    • toc-location: posisi daftar isi
    • toc-title: judul daftar isi
  • editor: apakah dalam mode visual atau source.
---
title: "latihan"
author: "nama penulis"
format:
  html:
    style: style.css
    toc: true
    toc-location: left
    toc-title: Índice
editor: visual
---

Teks

Mengenai pengetikan hanya ada satu hal penting: kecuali kita tunjukkan sebaliknya, SEMUA yang akan kita ketikkan adalah teks (biasa); bukan kode R.

Kita akan mulai dengan menulis sebuah bagian di awal (# Intro dan di belakangnya, misalnya kalimat

Materi ini telah dirancang oleh Profesor nama penulis, profesor di Universitas Complutense Madrid

Selain Running Code kita akan menambahkan tanda #: tanda di luar chunk akan membantu kita membuat judul bagian dalam dokumen.

Indeks

Agar daftar isi menangkap bagian-bagian tersebut kita akan memodifikasi header file seperti yang ditunjukkan pada gambar (kamu dapat mengubah lokasi daftar isi dan judulnya jika ingin mencoba).

Teks

Mari kita sesuaikan teks sedikit dengan melakukan hal berikut:

  • Kita akan menambahkan tebal pada nama (menambahkan ** di awal dan di akhir).

  • Kita akan menambahkan miring pada kata material (menambahkan _ di awal dan di akhir).

  • Kita akan menambahkan tautan https://www.ucm.es, menghubungkannya ke nama Universitas. Untuk itu kita menaruh judul dalam tanda kurung siku dan di belakangnya tautan dalam tanda kurung [“Universidad Complutense de Madrid”](https://www.ucm.es).

Kode

Untuk memasukkan kode R kita harus membuat kotak kode yang disebut chunk: ditempatkan dalam teks markdown kita di mana kita dapat memasukkan kode dari hampir semua bahasa (beserta outputnya).

 

Untuk memasukkan chunk, gunakan pintasan Command + Option + I (Mac) atau Ctrl + Shift + I (Windows)

Kode

Di dalam kotak ini (yang kini memiliki warna berbeda dalam dokumen) tuliskan kode R seperti yang sudah kita lakukan sejauh ini dalam skrip.

Misalnya mari definisikan dua variabel dan jumlahnya dengan cara berikut, menuliskan kode ini di .qmd kita (di dalam chunk tersebut)

# R code
x <- 1
y <- 2
x + y
[1] 3

Menjalankan Chunk

Chunk dapat memiliki nama atau tag, sehingga kita dapat mereferensikannya kembali untuk menghindari pengulangan kode.

Menjalankan Chunk

Di setiap chunk terdapat dua tombol:

  • Tombol play: mengaktifkan jalankan dan keluarkan chunk tertentu tersebut (kamu dapat melihatnya di dalam RStudio-mu sendiri)

  • Tombol rewind: mengaktifkan jalankan dan keluarkan semua chunk hingga chunk tersebut (tanpa mencapainya).

 

Selain itu kita dapat memasukkan kode R di dalam baris teks (alih-alih menampilkan teks x jalankan kode R yang menampilkan variabel).

Menyesuaikan Chunk

Chunk dapat dikustomisasi dengan opsi di awal chunk yang didahului #|:

  • #| echo: false: jalankan kode dan tampilkan hasil tetapi tidak menampilkan kode di output.

  • #| include: false: menjalankan kode tetapi tidak menampilkan hasil dan tidak menampilkan kode di output.

  • #| eval: false: tidak menjalankan kode, tidak menampilkan hasil tetapi menampilkan kode di output.

  • #| message: false: menjalankan kode tetapi tidak menampilkan pesan output.

  • #| warning: false: menjalankan kode tetapi tidak menampilkan pesan peringatan.

  • #| error: true: menjalankan kode dan mengizinkan error menampilkan pesan error di output.

Opsi-opsi ini dapat diterapkan per chunk atau diatur secara global dengan knitr::opts_chunk$set() di awal dokumen (dalam sebuah chunk).

Menyesuaikan Chunk

Jika kita ingin menerapkan opsi ke semua chunk secara default kita harus menyertakannya di akhir header, sebagai opsi eksekusi

---
title: "¡Hola!"
format: html
editor: visual
execute:
  echo: false
---

Mengorganisir

Selain teks dan kode kita dapat memasukkan hal berikut:

  • Persamaan: kamu juga dapat menambahkan persamaan seperti \(x^2\) (saya menulisnya $x^2$, persamaan di antara tanda dolar).

  • Daftar: kamu dapat membuat daftar elemen dengan meletakkan * Langkah 1: ... *Langkah 2: ...

  • Referensi silang: kamu dapat menandai bagian dokumen (tag dibuat dengan {#section-name}) dan kemudian memanggil dengan [Bagian](@section-name).

Gambar dan Ilustrasi

Akhirnya, kita juga dapat menambahkan keterangan pada grafik atau gambar dengan menambahkan #| fig-cap: "...".

Perhatikan bahwa keterangan ada di margin (misalnya). Kamu dapat mengubahnya dengan memasukkan pengaturan header (semua tentang gambar dimulai dengan fig-, dan kamu dapat melihat opsinya dengan menekan tab). Info lebih lanjut di https://quarto.org/

Gaya/Tampilan

Akhirnya kamu dapat menambahkan tema kustom termasuk sebuah file gaya (file .scss atau .css). Saya telah menyediakan satu untuk kamu di https://github.com/dadosdelaplace/docencia-R-master-bio-2324/tree/main/material.

Penting

File gaya harus berada di folder yang sama dengan file .qmd.

Gaya/Tampilan

Kamu juga dapat melakukannya dengan cara sederhana menambahkan sedikit HTML ke teks. Misalnya, untuk mengkustomisasi warna teks, letakkan di antara tanda kurung siku dan tepat setelah teks, di antara tanda kurung kurawal, opsi gaya tersebut

This word is [red]{style="color:red;"} ...
... and this is [green in bold]{style="color:green; font-weight: bold;"}

This word is red

… and this is green in bold

Revealjs

Kamu dapat menambahkan “animasi” menggunakan Revealjs (javascript), menentukannya di header dan menggunakan blok bahasa tersebut yang dibatasi ::: di awal dan akhir. Contohnya {.incremental} mentransisikan elemen-elemen.

format:
  revealjs

 

::: {.incremental}
- I
- am
- Javi
:::
  • I
  • am
  • Javi

Call blocks

Kamu juga dapat menggunakan callout-blocks yang secara default adalah note, tip, warning, caution dan important (meskipun kamu dapat membuat dan mengkustomisasinya). Untuk itu, gunakan saja ::{.callout-type} dan tipe yang ingin digunakan

:::{.callout-tip}

Note that there are five types of callouts, including: 
`note`, `tip`, `warning`, `caution`, and `important`.

:::

Tip

Perhatikan ada lima jenis callout: note, tip, warning, caution, dan important.

Caution

Gunakan dengan bijaksana; terlalu banyak elemen visual kadang membingungkan.

Tata Letak Beberapa Kolom

Dengan :::: columns kita dapat mendefinisikan tata letak beberapa kolom di mana masing-masing didefinisikan oleh ::: {.column width="65%"} sesuatu :::, menunjukkan persentase yang diinginkan setiap kolom (hati-hati jangan ada spasi!).

:::: columns
::: {.column width="65%"}
This is how to define a vector
:::
::: {.column width="35%"}
x <- c(1, 2, 3)
x
:::
::::

 

Ini cara mendefinisikan vektor

x <- c(1, 2, 3)
x
[1] 1 2 3

Kode Non-R

Selain itu reticulate memungkinkan kita membuat chunk python di dalam Quarto di R (lihat https://quarto.org/docs/computations/python.html untuk membuat jupyter notebook langsung dari Quarto).

# install.packages("reticulate")
library(reticulate)

install_python("3.9.12") # Installing python if you have not done before

# Installing Python libraries
reticulate::py_install("numpy")
reticulate::py_install("matplotlib")
import numpy as np
import matplotlib.pyplot as plt
r = np.arange(0, 2, 0.05)
theta = 2 * np.pi * r
fig, ax = plt.subplots(
  subplot_kw = {'projection': 'polar'} 
)
ax.plot(theta, r)
plt.show()

🐣 Studi Kasus I: Struktur Alur

To practice control structures we are going to perform a simulation exercise

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

🐣 Studi Kasus II: Fungsi

Definisikan fungsi bernama temperature_converter yang, diberikan suhu dalam Fahrenheit, Celsius, atau Kelvin, mengonversinya ke salah satu yang lain

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

🐣 Studi Kasus III: Tugas Latihan

Mari lakukan simulasi kecil sebelum pengumpulan menggunakan dataset starwars dari paket dplyr.

🐣 Case study III: mock task

library(dplyr)
starwars
# A tibble: 87 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 C-3PO    167    75 <NA>       gold       yellow         112   none 
 3 R2-D2     96    32 <NA>       white, bl… red             33   none 
 4 Dart…    202   136 none       white      yellow          41.9 male 
 5 Leia…    150    49 brown      light      brown           19   fema…
 6 Owen…    178   120 brown, gr… light      blue            52   male 
 7 Beru…    165    75 brown      light      blue            47   fema…
 8 R5-D4     97    32 <NA>       white, red red             NA   none 
 9 Bigg…    183    84 black      light      brown           24   male 
10 Obi-…    182    77 auburn, w… fair       blue-gray       57   male 
# ℹ 77 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Kita memiliki berbagai variabel karakter Star Wars, dengan karakteristik rambut, kulit, tinggi, nama, dll.

🐣 Case study III: mock task

Buat dokumen .qmd dengan nama, judul, format, dan indeks. Setiap Latihan berikutnya akan menjadi subbagian dokumen. Jalankan chunk yang diperlukan dan beri komentar pada output untuk menjawab setiap pertanyaan

Latihan 1. Berapa banyak karakter dalam database? Berapa banyak karakteristik yang diukur?

Latihan 2. Ekstrak variabel names dan ages dari tabel. Tipe apa variabel name? Dan variabel birth_year?

Latihan 3. Dapatkan vektor nama karakter diurutkan dari tertua ke termuda.

🐣 Case study III: mock task

Latihan 4. Gunakan fungsi unique() untuk mengetahui modalitas variabel kualitatif warna mata. Berapa banyak yang berbeda?

Latihan 5. Apakah ada nilai yang hilang dalam variabel warna mata?

Latihan 6. Hitung rata-rata dan simpangan baku variabel tinggi dan berat (perhatikan nilai hilang). Definisikan tibble baru dan tambahkan variabel “BMI” untuk menghitung indeks massa tubuh. Sertakan formula BMI dengan $ $.

Tugas Akhir: dasar-dasar R Base

Tugas Akhir (intro R)

Pada hari pengumpulan kamu akan memiliki template pengumpulan dalam format .qmd di kampus.

  1. Ekstrak foldernya (penting! jika tidak diekstrak, meskipun bisa mengedit .qmd, kamu tidak akan bisa menghasilkan .html)

  2. Edit header dengan nama dan NIM-mu

  3. Kamu harus mengisi setiap chunk dengan kode yang sesuai (di beberapa saya telah meninggalkan petunjuk) dan mengubah dari #| eval: false ke #| eval: true (jika dihapus langsung, secara default sudah true)

  4. Kamu harus mengomentari dengan teks biasa apa yang kamu anggap sebagai jawaban atas pertanyaan-pertanyaan tersebut.

  5. WAJIB mengumpulkan file .html yang dihasilkan (hanya file itu yang akan dinilai), jadi render seiring mengisi dokumen, jangan tunggu sampai akhir.

PEMROGRAMAN DATA

L1: tidydata

Format favorit kita: tibble. Tidyverse: alam semesta tidy data

Sebelumnya, di Breaking Bad…

Format database akhir kita akan menjadi objek tipe tibble, sebuah data.frame yang disempurnakan.

library(tibble)
tibble("height" = c(1.7, 1.8, 1.6), "weight" = c(80, 75, 70), "BMI" = weight / (height^2))
# A tibble: 3 × 3
  height weight   BMI
   <dbl>  <dbl> <dbl>
1    1.7     80  27.7
2    1.8     75  23.1
3    1.6     70  27.3
  • Metainformasi: di header secara otomatis menampilkan jumlah baris dan kolom, serta tipe setiap variabel.

  • Rekursivitas: memungkinkan mendefinisikan variabel secara berurutan (seperti yang sudah kita lihat).

  • Konsistensi: jika mengakses kolom yang tidak ada, akan memberikan peringatan.

  • Berdasarkan baris: memungkinkan membuat berdasarkan baris dengan tribble().

Sebelumnya, di Breaking Bad…

Untuk mendefinisikan tibble() sendiri kita memiliki dua opsi:

  • Menggabungkan vektor yang sudah kita definisikan, menggunakan fungsi tibble() dari paket tibble (sudah termasuk dalam tidyverse)
height <- c(1.7, 1.8, 1.6)
weight <- c(80, 75, 70)
BMI <- weight / (height^2)
tibble("height" = height, "weight" = weight, "BMI" = BMI)
# A tibble: 3 × 3
  height weight   BMI
   <dbl>  <dbl> <dbl>
1    1.7     80  27.7
2    1.8     75  23.1
3    1.6     70  27.3

Sebelumnya, di Breaking Bad…

  • Langsung dalam tibble dengan memberikan nilai dan nama variabel secara manual
tibble("height" = c(1.7, 1.8, 1.6),
       "weight" = c(80, 75, 70),
       "BMI" = weight / (height^2))
# A tibble: 3 × 3
  height weight   BMI
   <dbl>  <dbl> <dbl>
1    1.7     80  27.7
2    1.8     75  23.1
3    1.6     70  27.3

R Base vs Tidyverse

Sejauh ini, semua yang telah kita lakukan di R dilakukan dalam paradigma pemrograman yang dikenal sebagai R base. Ketika R lahir sebagai bahasa, banyak yang memprogram di dalamnya meniru bentuk dan metodologi yang diwarisi dari bahasa lain, berdasarkan penggunaan

  • Loop for dan while

  • Tanda dolar $ untuk mengakses variabel

  • Struktur if-else

Dan meskipun mengetahui struktur-struktur ini bisa menarik dalam beberapa kasus, dalam sebagian besar kasus mereka sudah usang dan kita akan dapat menghindarinya (terutama loop) karena R dirancang khusus untuk bekerja secara fungsional (bukan elemen-per-elemen).

Apa itu tidyverse?

Dalam konteks pemrograman fungsional ini, satu dekade lalu lahirlah tidyverse, sebuah “alam semesta” paket untuk menjamin alur kerja yang efisien, koheren, dan sederhana, berdasarkan ide bahwa data kita bersih dan rapi.

Apa itu tidyverse?

Apa itu tidyverse?

Ide Dasar: Tidy Data

Dataset yang rapi semuanya serupa, tetapi setiap dataset yang berantakan memiliki cara berantakannya sendiri (Hadley Wickham, Ilmuwan Kepala di RStudio)

TIDYVERSE

Alam semesta paket tidyverse didasarkan pada ide yang diperkenalkan oleh Hadley Wickham (sang maestro) tentang standarisasi format data untuk

  • mensistematisasi pemrosesan data
  • membuatnya lebih mudah untuk dimanipulasi
  • kode yang mudah dibaca.

Aturan

Hal pertama yang harus dipahami adalah apa itu dataset tidydata, karena seluruh tidyverse didasarkan pada data yang terstandarisasi.

  1. Setiap variabel dalam satu kolom
  1. Setiap individu dalam baris yang berbeda
  1. Setiap sel dengan satu nilai
  1. Setiap dataset dalam tibble
  1. Jika kita ingin menggabungkan beberapa dataset kita harus memiliki kolom yang sama (kunci).

Pipe (Pipa)

Dalam tidyverse operator pipe (pipa) yang didefinisikan sebagai |> (ctrl+shift+M) akan menjadi kunci: ini adalah pipa yang melewati data dan mengubahnya. . . .

Dalam R base, jika kita ingin menerapkan tiga fungsi first(), second() dan third() secara berurutan, itu akan menjadi

third(second(first(data)))

Dalam tidyverse kita dapat membaca dari kiri ke kanan dan memisahkan data dari tindakan

data |> first() |> second() |> third()

Penting

Sejak versi 4.1.0 R kita memiliki |>, sebuah pipe native yang tersedia di luar tidyverse, menggantikan pipe lama %>% yang bergantung pada paket magrittr (cukup bermasalah).

Pipe (Pipa)

Keunggulan utamanya adalah kode sangat mudah dibaca (hampir literal) dan kamu dapat melakukan operasi besar pada data dengan kode yang sangat sedikit.

data |>
  tidy(...) |>
  filter(...) |>
  select(...) |>
  arrange(...) |>
  modify(...) |>
  rename(...) |>
  group(...) |>
  count(...) |>
  summarise(...) |>
  plot(...)

Data Berantakan

Tapi seperti apa data yang tidak rapi (berantakan) itu? Mari muat tabel table4a dari paket tidyr (sudah dimuat dari lingkungan tidyverse).

library(tidyr)
table4a
# A tibble: 3 × 3
  country     `1999` `2000`
  <chr>        <dbl>  <dbl>
1 Afghanistan    745   2666
2 Brazil       37737  80488
3 China       212258 213766

Apa yang mungkin salah?

Pivot Longer

table4a
# A tibble: 3 × 3
  country     `1999` `2000`
  <chr>        <dbl>  <dbl>
1 Afghanistan    745   2666
2 Brazil       37737  80488
3 China       212258 213766

❎ Setiap baris merepresentasikan dua pengamatan (1999 dan 2000) → kolom 1999 dan 2000 seharusnya menjadi nilai dari sebuah variabel bukan nama kolom.

Kita akan menyertakan kolom baru yang menyimpan tahun dan kolom lain yang menyimpan nilai variabel yang diminati di setiap tahun. Dan kita akan melakukannya dengan fungsi pivot_longer(): pivot tabel ke format panjang:

table4a |> 
  pivot_longer(cols = c("1999", "2000"), names_to = "year", values_to = "cases")
# A tibble: 6 × 3
  country     year   cases
  <chr>       <chr>  <dbl>
1 Afghanistan 1999     745
2 Afghanistan 2000    2666
3 Brazil      1999   37737
4 Brazil      2000   80488
5 China       1999  212258
6 China       2000  213766

Pivot Longer

table4a |> 
  pivot_longer(cols = c("1999", "2000"),
               names_to = "year",
               values_to = "cases")
# A tibble: 6 × 3
  country     year   cases
  <chr>       <chr>  <dbl>
1 Afghanistan 1999     745
2 Afghanistan 2000    2666
3 Brazil      1999   37737
4 Brazil      2000   80488
5 China       1999  212258
6 China       2000  213766

  • cols: nama variabel yang akan di-pivot.
  • names_to: nama variabel baru ke mana kita mengirim header tabel (nama-namanya).
  • values_to: nama variabel baru ke mana kita akan mengirim data.

Data Berantakan

Mari lihat contoh lain dengan tabel table2.

table2
# A tibble: 12 × 4
   country      year type            count
   <chr>       <dbl> <chr>           <dbl>
 1 Afghanistan  1999 cases             745
 2 Afghanistan  1999 population   19987071
 3 Afghanistan  2000 cases            2666
 4 Afghanistan  2000 population   20595360
 5 Brazil       1999 cases           37737
 6 Brazil       1999 population  172006362
 7 Brazil       2000 cases           80488
 8 Brazil       2000 population  174504898
 9 China        1999 cases          212258
10 China        1999 population 1272915272
11 China        2000 cases          213766
12 China        2000 population 1280428583

Apa yang mungkin salah?

Pivot Wider

# A tibble: 12 × 4
   country      year type            count
   <chr>       <dbl> <chr>           <dbl>
 1 Afghanistan  1999 cases             745
 2 Afghanistan  1999 population   19987071
 3 Afghanistan  2000 cases            2666
 4 Afghanistan  2000 population   20595360
 5 Brazil       1999 cases           37737
 6 Brazil       1999 population  172006362
 7 Brazil       2000 cases           80488
 8 Brazil       2000 population  174504898
 9 China        1999 cases          212258
10 China        1999 population 1272915272
11 China        2000 cases          213766
12 China        2000 population 1280428583

❎ Setiap pengamatan dibagi dalam dua bariscatatan dengan tahun yang sama seharusnya sama

Yang akan kita lakukan adalah kebalikannya: dengan pivot_wider() kita akan memperlebar tabel

table2 |>  pivot_wider(names_from = type, values_from = count)
# A tibble: 6 × 4
  country      year  cases population
  <chr>       <dbl>  <dbl>      <dbl>
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

Data Berantakan

Mari lihat contoh lain dengan tabel table3.

table3
# A tibble: 6 × 3
  country      year rate             
  <chr>       <dbl> <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

Apa yang mungkin salah?

Memisahkan

table3
# A tibble: 6 × 3
  country      year rate             
  <chr>       <dbl> <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

❎ Setiap sel berisi beberapa nilai

Yang akan kita lakukan adalah menggunakan fungsi separate() untuk memisahkan setiap nilai ke kolom yang berbeda.

table3 |> separate(rate, into = c("cases", "pop"))
# A tibble: 6 × 4
  country      year cases  pop       
  <chr>       <dbl> <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

Memisahkan

table3 |> separate(rate, into = c("cases", "pop"))
# A tibble: 6 × 4
  country      year cases  pop       
  <chr>       <dbl> <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

Perhatikan bahwa data, meskipun sudah dipisahkan, tetap sebagai teks padahal seharusnya berupa variabel numerik. Untuk itu kita dapat menambahkan argumen opsional convert = TRUE.

table3 |> separate(rate, into = c("cases", "pop"), convert = TRUE)
# A tibble: 6 × 4
  country      year  cases        pop
  <chr>       <dbl>  <int>      <int>
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

Data Berantakan

Mari lihat contoh terakhir dengan tabel table5.

table5
# A tibble: 6 × 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

Apa yang mungkin salah?

Menggabungkan

table5
# A tibble: 6 × 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

❎ Kita memiliki nilai yang sama yang dibagi dalam dua kolom

Kita akan menggunakan unite() untuk menyatukan nilai abad dan tahun dalam kolom yang sama

table5 |> unite(col = whole_year, century, year, sep = "")
# A tibble: 6 × 3
  country     whole_year 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

Menyarangkan Data

Kita juga dapat menyarangkan dataset di dalam dataset lain: bayangkan kita memiliki dataset dengan variabel x dan y, dengan dua catatan, satu lagi dengan satu catatan, dan satu lagi dengan 3 catatan.

data <-
  tibble("dataset" = c(1, 1, 2, 3, 3, 3), 
         "x" = c(0, 2, NA, -2, 6, 7),
         "y" = c(-1, NA, 5, 1.5, NA, -2))
data
# A tibble: 6 × 3
  dataset     x     y
    <dbl> <dbl> <dbl>
1       1     0  -1  
2       1     2  NA  
3       2    NA   5  
4       3    -2   1.5
5       3     6  NA  
6       3     7  -2  

Pada kenyataannya, semua yang memiliki nilai sama dalam dataset harus membentuk tibble-nya sendiri, jadi mari buat satu di dalam yang kita miliki

Menyarangkan Data

Untuk itu kita akan menggunakan fungsi nest() dengan menunjukkan variabel mana yang membentuk dataset yang akan disarangkan (dalam kasus ini variabel x dan y). Perhatikan bahwa yang disimpan di dalamnya adalah variabel bertipe list (karena setiap dataset memiliki panjang yang berbeda).

data_nest <-
  data |>
  nest(data = c(x, y))
data_nest
# A tibble: 3 × 2
  dataset data            
    <dbl> <list>          
1       1 <tibble [2 × 2]>
2       2 <tibble [1 × 2]>
3       3 <tibble [3 × 2]>

Menyarangkan Data

Untuk membuka sarang cukup gunakan fungsi unnest() dengan menunjukkan kolom yang akan dibuka sarangnya.

data_nest |> unnest(cols = c(data))
# A tibble: 6 × 3
  dataset     x     y
    <dbl> <dbl> <dbl>
1       1     0  -1  
2       1     2  NA  
3       2    NA   5  
4       3    -2   1.5
5       3     6  NA  
6       3     7  -2  

Contoh: Data Populasi Bank Dunia

Dalam paket tidyr kita memiliki dataset world_bank_pop yang berisi data dari Bank Dunia tentang populasi per negara dari tahun 2000 hingga 2018.

library(tidyr)
world_bank_pop
# A tibble: 1,064 × 20
   country indicator    `2000`  `2001`  `2002`  `2003`  `2004`  `2005`
   <chr>   <chr>         <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
 1 ABW     SP.URB.TOTL  4.16e4 4.20e+4 4.22e+4 4.23e+4 4.23e+4 4.24e+4
 2 ABW     SP.URB.GROW  1.66e0 9.56e-1 4.01e-1 1.97e-1 9.46e-2 1.94e-1
 3 ABW     SP.POP.TOTL  8.91e4 9.07e+4 9.18e+4 9.27e+4 9.35e+4 9.45e+4
 4 ABW     SP.POP.GROW  2.54e0 1.77e+0 1.19e+0 9.97e-1 9.01e-1 1.00e+0
 5 AFE     SP.URB.TOTL  1.16e8 1.20e+8 1.24e+8 1.29e+8 1.34e+8 1.39e+8
 6 AFE     SP.URB.GROW  3.60e0 3.66e+0 3.72e+0 3.71e+0 3.74e+0 3.81e+0
 7 AFE     SP.POP.TOTL  4.02e8 4.12e+8 4.23e+8 4.34e+8 4.45e+8 4.57e+8
 8 AFE     SP.POP.GROW  2.58e0 2.59e+0 2.61e+0 2.62e+0 2.64e+0 2.67e+0
 9 AFG     SP.URB.TOTL  4.31e6 4.36e+6 4.67e+6 5.06e+6 5.30e+6 5.54e+6
10 AFG     SP.URB.GROW  1.86e0 1.15e+0 6.86e+0 7.95e+0 4.59e+0 4.47e+0
# ℹ 1,054 more rows
# ℹ 12 more variables: `2006` <dbl>, `2007` <dbl>, `2008` <dbl>,
#   `2009` <dbl>, `2010` <dbl>, `2011` <dbl>, `2012` <dbl>,
#   `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>,
#   `2017` <dbl>

Apa yang mungkin salah?

Contoh: Data Populasi Bank Dunia

Pertama-tama, kita dapat melihat bahwa kita secara efektif memiliki variabel yang sama dalam 18 kolom: populasi.

Yang seharusnya kita miliki adalah kolom bernama pop dengan nilai-nilai ini dan kolom lain year yang menunjukkan tahun yang sesuai dengan pengukuran. Dan untuk itu kita akan menggunakan pivot_longer().

world_bank_pop_tidy <-
  world_bank_pop |> 
  pivot_longer(cols = -(country:indicator), names_to = "year", values_to = "value")
world_bank_pop_tidy
# A tibble: 19,152 × 4
   country indicator   year  value
   <chr>   <chr>       <chr> <dbl>
 1 ABW     SP.URB.TOTL 2000  41625
 2 ABW     SP.URB.TOTL 2001  42025
 3 ABW     SP.URB.TOTL 2002  42194
 4 ABW     SP.URB.TOTL 2003  42277
 5 ABW     SP.URB.TOTL 2004  42317
 6 ABW     SP.URB.TOTL 2005  42399
 7 ABW     SP.URB.TOTL 2006  42555
 8 ABW     SP.URB.TOTL 2007  42729
 9 ABW     SP.URB.TOTL 2008  42906
10 ABW     SP.URB.TOTL 2009  43079
# ℹ 19,142 more rows

Contoh: Data Populasi Bank Dunia

world_bank_pop_tidy
# A tibble: 19,152 × 4
   country indicator   year  value
   <chr>   <chr>       <chr> <dbl>
 1 ABW     SP.URB.TOTL 2000  41625
 2 ABW     SP.URB.TOTL 2001  42025
 3 ABW     SP.URB.TOTL 2002  42194
 4 ABW     SP.URB.TOTL 2003  42277
 5 ABW     SP.URB.TOTL 2004  42317
 6 ABW     SP.URB.TOTL 2005  42399
 7 ABW     SP.URB.TOTL 2006  42555
 8 ABW     SP.URB.TOTL 2007  42729
 9 ABW     SP.URB.TOTL 2008  42906
10 ABW     SP.URB.TOTL 2009  43079
# ℹ 19,142 more rows

Apakah semuanya sudah benar?

Jika kamu perhatikan kita memiliki dua jenis ukuran populasi, total ...TOTL dan pertumbuhannya ...GROW, selain itu kita memilikinya untuk setiap negara secara global SP.POP... dan hanya di area perkotaan SP.URB....

unique(world_bank_pop_tidy$indicator)
[1] "SP.URB.TOTL" "SP.URB.GROW" "SP.POP.TOTL" "SP.POP.GROW"

Contoh: Data Populasi Bank Dunia

Apa yang harus dilakukan?

Kita akan memisahkan variabel ini menjadi 3: satu untuk awalan SP (yang akan kita hapus nanti), satu untuk area (POP/URB) dan satu untuk nilai (variable), yang bisa berupa total atau pertumbuhan.

world_bank_pop_tidy2 <-
  world_bank_pop_tidy |>
  separate(indicator, c("dummy", "area", "variable"))
world_bank_pop_tidy2$dummy <- NULL
world_bank_pop_tidy2
# A tibble: 19,152 × 5
   country area  variable year  value
   <chr>   <chr> <chr>    <chr> <dbl>
 1 ABW     URB   TOTL     2000  41625
 2 ABW     URB   TOTL     2001  42025
 3 ABW     URB   TOTL     2002  42194
 4 ABW     URB   TOTL     2003  42277
 5 ABW     URB   TOTL     2004  42317
 6 ABW     URB   TOTL     2005  42399
 7 ABW     URB   TOTL     2006  42555
 8 ABW     URB   TOTL     2007  42729
 9 ABW     URB   TOTL     2008  42906
10 ABW     URB   TOTL     2009  43079
# ℹ 19,142 more rows

Contoh: Data Populasi Bank Dunia

Ini dapat dilakukan dengan cara yang lebih sederhana dengan menunjukkan dalam variabel yang ingin kita hapus bahwa nilainya adalah NA di dalam separate().

world_bank_pop_tidy <-
  world_bank_pop_tidy |>
  separate(indicator, c(NA, "area", "variable"))
world_bank_pop_tidy
# A tibble: 19,152 × 5
   country area  variable year  value
   <chr>   <chr> <chr>    <chr> <dbl>
 1 ABW     URB   TOTL     2000  41625
 2 ABW     URB   TOTL     2001  42025
 3 ABW     URB   TOTL     2002  42194
 4 ABW     URB   TOTL     2003  42277
 5 ABW     URB   TOTL     2004  42317
 6 ABW     URB   TOTL     2005  42399
 7 ABW     URB   TOTL     2006  42555
 8 ABW     URB   TOTL     2007  42729
 9 ABW     URB   TOTL     2008  42906
10 ABW     URB   TOTL     2009  43079
# ℹ 19,142 more rows

Apakah kita sudah berhasil? Pikirkan dengan cermat: apakah setiap variabel memiliki kolomnya sendiri?

Contoh: Data Populasi Bank Dunia

Jika kamu benar-benar melihat variabel total populasi dan pertumbuhan, mereka seharusnya menjadi variabel yang berbeda, karena bahkan memiliki satuan yang berbeda: satu adalah penduduk, yang lain adalah poin persentase.

Untuk melakukan kebalikan dari operasi awal, gunakan pivot_wider() (nanti kita akan menggunakan fungsi yang sangat berguna, clean_names() dari janitor yang menyatukan nama variabel).

world_bank_pop_tidy <-
  world_bank_pop_tidy |>
  pivot_wider(names_from = "variable", values_from = "value") |> 
  janitor::clean_names()
world_bank_pop_tidy
# A tibble: 9,576 × 5
   country area  year   totl   grow
   <chr>   <chr> <chr> <dbl>  <dbl>
 1 ABW     URB   2000  41625 1.66  
 2 ABW     URB   2001  42025 0.956 
 3 ABW     URB   2002  42194 0.401 
 4 ABW     URB   2003  42277 0.197 
 5 ABW     URB   2004  42317 0.0946
 6 ABW     URB   2005  42399 0.194 
 7 ABW     URB   2006  42555 0.367 
 8 ABW     URB   2007  42729 0.408 
 9 ABW     URB   2008  42906 0.413 
10 ABW     URB   2009  43079 0.402 
# ℹ 9,566 more rows

Contoh: Data Populasi Bank Dunia

Kode lengkapnya akan seperti ini: singkat, padat, mudah dibaca, dan mendeskripsikan dirinya sendiri.

world_bank_pop_tidy <-
  world_bank_pop |> 
  pivot_longer(cols = -(country:indicator), names_to = "year", values_to = "value") |> 
  separate(indicator, c(NA, "area", "variable")) |> 
  pivot_wider(names_from = "variable", values_from = "value") |> 
  janitor::clean_names()
world_bank_pop_tidy
# A tibble: 9,576 × 5
   country area  year   totl   grow
   <chr>   <chr> <chr> <dbl>  <dbl>
 1 ABW     URB   2000  41625 1.66  
 2 ABW     URB   2001  42025 0.956 
 3 ABW     URB   2002  42194 0.401 
 4 ABW     URB   2003  42277 0.197 
 5 ABW     URB   2004  42317 0.0946
 6 ABW     URB   2005  42399 0.194 
 7 ABW     URB   2006  42555 0.367 
 8 ABW     URB   2007  42729 0.408 
 9 ABW     URB   2008  42906 0.413 
10 ABW     URB   2009  43079 0.402 
# ℹ 9,566 more rows

Contoh: Dataset WHO

Dalam paket tidyr kita memiliki dataset who2 (dataset Organisasi Kesehatan Dunia)

library(tidyr)
who2
# A tibble: 7,240 × 58
   country      year sp_m_014 sp_m_1524 sp_m_2534 sp_m_3544 sp_m_4554
   <chr>       <dbl>    <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
 1 Afghanistan  1980       NA        NA        NA        NA        NA
 2 Afghanistan  1981       NA        NA        NA        NA        NA
 3 Afghanistan  1982       NA        NA        NA        NA        NA
 4 Afghanistan  1983       NA        NA        NA        NA        NA
 5 Afghanistan  1984       NA        NA        NA        NA        NA
 6 Afghanistan  1985       NA        NA        NA        NA        NA
 7 Afghanistan  1986       NA        NA        NA        NA        NA
 8 Afghanistan  1987       NA        NA        NA        NA        NA
 9 Afghanistan  1988       NA        NA        NA        NA        NA
10 Afghanistan  1989       NA        NA        NA        NA        NA
# ℹ 7,230 more rows
# ℹ 51 more variables: sp_m_5564 <dbl>, sp_m_65 <dbl>,
#   sp_f_014 <dbl>, sp_f_1524 <dbl>, sp_f_2534 <dbl>,
#   sp_f_3544 <dbl>, sp_f_4554 <dbl>, sp_f_5564 <dbl>, sp_f_65 <dbl>,
#   sn_m_014 <dbl>, sn_m_1524 <dbl>, sn_m_2534 <dbl>,
#   sn_m_3544 <dbl>, sn_m_4554 <dbl>, sn_m_5564 <dbl>, sn_m_65 <dbl>,
#   sn_f_014 <dbl>, sn_f_1524 <dbl>, sn_f_2534 <dbl>, …

Apakah ini tidy data? Mengapa?

Contoh: Dataset WHO

Langkah pertama untuk tidy data: kita harus me-pivot tabel (tips: gunakan kertas dan pena untuk membuat sketsa tampilan database yang seharusnya) sehingga ada kolom bernama cases (karena semua kolom mulai dari year sebenarnya sama, kasus suatu penyakit).

who_tidy <-
  who2 |> 
  pivot_longer(cols = -(country:year), names_to = "type", values_to = "cases")
who_tidy
# A tibble: 405,440 × 4
   country      year type      cases
   <chr>       <dbl> <chr>     <dbl>
 1 Afghanistan  1980 sp_m_014     NA
 2 Afghanistan  1980 sp_m_1524    NA
 3 Afghanistan  1980 sp_m_2534    NA
 4 Afghanistan  1980 sp_m_3544    NA
 5 Afghanistan  1980 sp_m_4554    NA
 6 Afghanistan  1980 sp_m_5564    NA
 7 Afghanistan  1980 sp_m_65      NA
 8 Afghanistan  1980 sp_f_014     NA
 9 Afghanistan  1980 sp_f_1524    NA
10 Afghanistan  1980 sp_f_2534    NA
# ℹ 405,430 more rows

Contoh: Dataset WHO

Jika kamu perhatikan, ada banyak baris yang tidak masuk akal untuk disimpan karena kita tidak memiliki kasus! Investigasi opsi pivot_longer() untuk melihat bagaimana kita dapat langsung menghapusnya dalam pivot.

who_tidy <-
  who2 |> 
  pivot_longer(cols = -(country:year), names_to = "type", values_to = "cases",
               values_drop_na = TRUE)
who_tidy
# A tibble: 76,046 × 4
   country      year type      cases
   <chr>       <dbl> <chr>     <dbl>
 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
# ℹ 76,036 more rows

Contoh: Dataset WHO

Sekarang dalam type kita mengkodekan informasi sebagai diagnosis_sex_age. Bagaimana memisahkannya menjadi 3 kolom? Investigasi opsi separate() dan pivot_longer().

# separate
who_tidy <-
  who_tidy |> 
  separate(col = "type", into = c("diagnosis", "sex", "age"))

# pivot_longer
who_tidy <-
  who2 |> 
  pivot_longer(cols = -(country:year), names_to = c("diagnosis", "sex", "age"),
               values_to = "cases", values_drop_na = TRUE,
               names_sep = "_")
who_tidy
# A tibble: 76,046 × 6
   country      year diagnosis sex   age   cases
   <chr>       <dbl> <chr>     <chr> <chr> <dbl>
 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
# ℹ 76,036 more rows

Contoh: Dataset WHO

Terakhir, pisahkan menjadi dua (age_inf, age_sup) rentang usia (yang berupa angka). Pikirkan cara melakukannya karena tidak selalu 4 angka (jika tidak ada batas atas usia yang ditentukan, masukkan Inf sebagai batas atas).

who_tidy <-
  who_tidy |> 
  separate(col = "age", into = c("age_inf", "age_sup"), sep = -2, convert = TRUE)
who_tidy$age_inf <- if_else(is.na(who_tidy$age_inf), 65, who_tidy$age_inf)
who_tidy$age_sup <- if_else(who_tidy$age_sup == 65, Inf, who_tidy$age_sup)
who_tidy
# A tibble: 76,046 × 7
   country      year diagnosis sex   age_inf age_sup cases
   <chr>       <dbl> <chr>     <chr>   <dbl>   <dbl> <dbl>
 1 Afghanistan  1997 sp        m           0      14     0
 2 Afghanistan  1997 sp        m          15      24    10
 3 Afghanistan  1997 sp        m          25      34     6
 4 Afghanistan  1997 sp        m          35      44     3
 5 Afghanistan  1997 sp        m          45      54     5
 6 Afghanistan  1997 sp        m          55      64     2
 7 Afghanistan  1997 sp        m          65     Inf     0
 8 Afghanistan  1997 sp        f           0      14     5
 9 Afghanistan  1997 sp        f          15      24    38
10 Afghanistan  1997 sp        f          25      34    36
# ℹ 76,036 more rows

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Gunakan dataset who2 asli dari tidyr dan jawab: berapa kasus tuberkulosis di Spanyol tahun 1995 di kalangan perempuan? Lakukan tanpa mengonversi ke tidydata, lalu dengan tidydata, dan bandingkan keterbacaan kodenya.

Code
# messy data
sum(who2[who2$country == "Spain" & who2$year == 1995,
     names(who2)[str_detect(names(who2), "f_")]], na.rm = TRUE)

# tidy data (at this moment)
sum(who_tidy[who_tidy$country == "Spain" &
           who_tidy$year == 1995 &
           who_tidy$sex == "f", ]$cases)

# in the future
who_tidy |> 
  filter(country == "Spain" & year == 1995 & sex == "f") |> 
  summarise(sum(cases))

📝 Menggunakan who_tidy tentukan jenis kelamin mana yang memiliki lebih banyak kasus, pria atau wanita? Buat variabel baru avg_age: jika rentang 25–34, rata-rata umur \((25+34)/2 = 29.5\) (jika Inf di atas, NA).

Code
# f vs m
sum(who_tidy[who_tidy$sex == "m", ]$cases)
sum(who_tidy[who_tidy$sex == "f", ]$cases)

# ave age
who_tidy$ave_age <- 
  if_else(is.infinite(who_tidy$age_sup), NA, (who_tidy$age_inf + who_tidy$age_sup)/2)

📝 Jika harus memilih negara dengan probabilitas infeksi terendah, negara mana antara Inggris Raya dan Prancis yang memiliki kasus paling sedikit di tahun terbaru?

Code
last_cases <- who_tidy[who_tidy$year == max(who_tidy$year), ]
sum(last_cases[last_cases$country == "United Kingdom of Great Britain and Northern Ireland", "cases"])
sum(last_cases[last_cases$country == "France", "cases"])
# better France

📝 Lihat tabel table4b dalam paket tidyr. Apakah ini tidydata? Jika tidak, apa yang salah dan bagaimana mengonversinya?

Code
table4b |>
  pivot_longer(cols = "1999":"2000", names_to = "year",
               values_to = "cases")

📝 Lihat tabel billboard dalam paket tidyr. Apakah ini tidydata? Jika tidak, apa yang salah dan bagaimana mengonversinya?

Code
billboard |>
  pivot_longer(cols = "wk1":"wk76",
               names_to = "week",
               names_prefix = "wk",
               values_to = "position",
               values_drop_na = TRUE)

🐣 Studi Kasus

Mari lakukan studi kasus dengan tabel relig_income dalam paket tidyr. Tabel ini merepresentasikan jumlah orang dalam setiap kelompok pendapatan tahunan (20k = $20.000) dan setiap agama.

relig_income

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

L2: tidyverse (baris)

Tidyverse: tindakan berdasarkan baris

Pra-pemrosesan: dplyr

Dalam tidyverse kita akan menggunakan paket dplyr untuk proses pra-pemrosesan data.

data |>
  tidy(...) |>
  filter(...) |>
  select(...) |>
  arrange(...) |>
  modify(...) |> # mutate in the code
  rename(...) |>
  group(...) |>
  count(...) |>
  summarise(...) |>
  plot(...) # actually ggplot

Idenya adalah agar kode semudah mungkin dibaca, seolah-olah merupakan daftar instruksi yang saat dibaca memberitahu kita secara jelas apa yang sedang dilakukan.

Asumsi: Tidydata

Semua proses pra-pemrosesan yang akan kita lakukan berasumsi bahwa data kita sudah dalam format tidydata

Ingat bahwa dalam tidyverse, operator pipe yang didefinisikan sebagai |> (ctrl+shift+M) akan menjadi kunci: ini adalah pipe yang melewati data dan mengubahnya.

Mari berlatih dengan dataset starwars dari paket dplyr.

library(tidyverse)
starwars

Pengambilan Sampel

Salah satu operasi paling umum adalah yang dikenal dalam statistik sebagai pengambilan sampel: sebuah pemilihan atau penyaringan catatan (baris) (subsampel).

  • Non-acak (berdasarkan kuota): berdasarkan kondisi logika pada catatan (filter()).
  • Non-acak (disengaja/diskresioner): berdasarkan posisi (slice()).
  • Acak sederhana (slice_sample()).
  • Terstratifikasi (group_by() + slice_sample()).

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Tindakan paling sederhana berdasarkan baris adalah saat menyaring catatan berdasarkan kondisi logika: dengan filter() hanya individu yang memenuhi kondisi tertentu yang akan dipilih (pengambilan sampel non-acak berdasarkan kondisi).

  • ==, !=: sama dengan atau berbeda dari (|> filter(variable == "a"))
  • >, <: lebih besar atau lebih kecil dari (|> filter(variable < 3))
  • >=, <=: lebih besar atau sama dengan atau lebih kecil atau sama dengan (|> filter(variable >= 5))
  • %in%: nilai termasuk dalam sekumpulan opsi diskrit (|> filter(variable %in% c("blue", "green")))
  • between(variable, val1, val2): jika nilai kontinu berada dalam rentang (|> filter(between(variable, 160, 180)))

Menyaring Baris: filter()

Kondisi logika ini dapat digabungkan dalam berbagai cara (dan, atau, atau saling eksklusif).

Penting

Ingat bahwa di dalam filter() harus selalu ada sesuatu yang mengembalikan vektor nilai logika.

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter dengan mata coklat?

Tipe variabel apa itu? –> Variabel eye_color bersifat kualitatif sehingga diwakili oleh teks.

starwars |>
  filter(eye_color == "brown")
# A tibble: 21 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Leia…    150  49   brown      light      brown           19   fema…
 2 Bigg…    183  84   black      light      brown           24   male 
 3 Han …    180  80   brown      fair       brown           29   male 
 4 Yoda      66  17   white      green      brown          896   male 
 5 Boba…    183  78.2 black      fair       brown           31.5 male 
 6 Land…    177  79   black      dark       brown           31   male 
 7 Arve…     NA  NA   brown      fair       brown           NA   male 
 8 Wick…     88  20   brown      brown      brown            8   male 
 9 Padm…    185  45   brown      light      brown           46   fema…
10 Quar…    183  NA   black      dark       brown           62   male 
# ℹ 11 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter yang tidak memiliki mata coklat?

starwars |>
  filter(eye_color != "brown")
# A tibble: 66 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 C-3PO    167    75 <NA>       gold       yellow         112   none 
 3 R2-D2     96    32 <NA>       white, bl… red             33   none 
 4 Dart…    202   136 none       white      yellow          41.9 male 
 5 Owen…    178   120 brown, gr… light      blue            52   male 
 6 Beru…    165    75 brown      light      blue            47   fema…
 7 R5-D4     97    32 <NA>       white, red red             NA   none 
 8 Obi-…    182    77 auburn, w… fair       blue-gray       57   male 
 9 Anak…    188    84 blond      fair       blue            41.9 male 
10 Wilh…    180    NA auburn, g… fair       blue            64   male 
# ℹ 56 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter yang memiliki mata coklat atau biru?

starwars |>
  filter(eye_color %in% c("blue", "brown"))
# A tibble: 40 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 Leia…    150    49 brown      light      brown           19   fema…
 3 Owen…    178   120 brown, gr… light      blue            52   male 
 4 Beru…    165    75 brown      light      blue            47   fema…
 5 Bigg…    183    84 black      light      brown           24   male 
 6 Anak…    188    84 blond      fair       blue            41.9 male 
 7 Wilh…    180    NA auburn, g… fair       blue            64   male 
 8 Chew…    228   112 brown      unknown    blue           200   male 
 9 Han …    180    80 brown      fair       brown           29   male 
10 Jek …    180   110 brown      fair       blue            NA   <NA> 
# ℹ 30 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Perhatikan bahwa %in% setara dengan menggabungkan beberapa == dengan konjungsi atau (|)

starwars |>
  filter(eye_color == "blue" | eye_color == "brown")
# A tibble: 40 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 Leia…    150    49 brown      light      brown           19   fema…
 3 Owen…    178   120 brown, gr… light      blue            52   male 
 4 Beru…    165    75 brown      light      blue            47   fema…
 5 Bigg…    183    84 black      light      brown           24   male 
 6 Anak…    188    84 blond      fair       blue            41.9 male 
 7 Wilh…    180    NA auburn, g… fair       blue            64   male 
 8 Chew…    228   112 brown      unknown    blue           200   male 
 9 Han …    180    80 brown      fair       brown           29   male 
10 Jek …    180   110 brown      fair       blue            NA   <NA> 
# ℹ 30 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter yang tingginya antara 120 dan 160 cm?

Tipe variabel apa itu? –> Variabel height adalah variabel kuantitatif kontinu sehingga kita harus memfilter berdasarkan rentang nilai (interval) –> gunakan between().

starwars |>
  filter(between(height, 120, 160))
# A tibble: 6 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Leia …    150    49 brown      light      brown             19 fema…
2 Mon M…    150    NA auburn     fair       blue              48 fema…
3 Nien …    160    68 none       grey       black             NA male 
4 Watto     137    NA black      blue, grey yellow            NA male 
5 Gasga…    122    NA none       white, bl… black             NA male 
6 Cordé     157    NA brown      light      brown             NA <NA> 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter yang bermata coklat dan bukan manusia?

starwars |>
  filter(eye_color == "brown" & species != "Human")
# A tibble: 3 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Yoda       66    17 white      green      brown            896 male 
2 Wicke…     88    20 brown      brown      brown              8 male 
3 Eeth …    171    NA black      brown      brown             NA male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menyaring Baris: filter()

data |>
  filtro(condition)
starwars |>
  filter(condition)

Bagaimana cara… menyaring karakter yang bermata coklat dan bukan manusia, atau berumur lebih dari 60 tahun? Pikirkan: tanda kurung itu penting: \((a+b)*c\) tidak sama dengan \(a+(b*c)\).

starwars |>
  filter((eye_color == "brown" & species != "Human") | birth_year > 60)
# A tibble: 18 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 C-3PO    167    75 <NA>       gold       yellow           112 none 
 2 Wilh…    180    NA auburn, g… fair       blue              64 male 
 3 Chew…    228   112 brown      unknown    blue             200 male 
 4 Jabb…    175  1358 <NA>       green-tan… orange           600 herm…
 5 Yoda      66    17 white      green      brown            896 male 
 6 Palp…    170    75 grey       pale       yellow            82 male 
 7 Wick…     88    20 brown      brown      brown              8 male 
 8 Qui-…    193    89 brown      fair       blue              92 male 
 9 Fini…    170    NA blond      fair       blue              91 male 
10 Quar…    183    NA black      dark       brown             62 male 
11 Shmi…    163    NA black      fair       brown             72 fema…
12 Mace…    188    84 none       dark       brown             72 male 
13 Ki-A…    198    82 white      pale       yellow            92 male 
14 Eeth…    171    NA black      brown      brown             NA male 
15 Clie…    183    NA brown      fair       blue              82 male 
16 Dooku    193    80 white      fair       brown            102 male 
17 Bail…    191    NA black      tan        brown             67 male 
18 Jang…    183    79 black      tan        brown             66 male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menghapus Nilai Hilang: drop_na()

data |>
  drop_missings(var1, var2, ...)
starwars |>
  drop_na(var1, var2, ...)

There is a special filter for one of the most common operations in debugging: remove absent. For this we can use inside a filter is.na(), which returns TRUE/FALSE debelum disiapkan on whether it is absent, or …

Gunakan drop_na(): jika kita tidak menentukan variabel, catatan dengan nilai hilang di variabel mana pun akan dihapus. Nanti kita akan melihat cara mengimputasi nilai hilang tersebut

starwars |>
  drop_na(mass, height)
# A tibble: 7 × 4
  name                mass height hair_color 
  <chr>              <dbl>  <int> <chr>      
1 Luke Skywalker        77    172 blond      
2 C-3PO                 75    167 <NA>       
3 R2-D2                 32     96 <NA>       
4 Darth Vader          136    202 none       
5 Leia Organa           49    150 brown      
6 Owen Lars            120    178 brown, grey
7 Beru Whitesun Lars    75    165 brown      
starwars |>
  drop_na()
# A tibble: 7 × 4
  name                mass height hair_color   
  <chr>              <dbl>  <int> <chr>        
1 Luke Skywalker        77    172 blond        
2 Darth Vader          136    202 none         
3 Leia Organa           49    150 brown        
4 Owen Lars            120    178 brown, grey  
5 Beru Whitesun Lars    75    165 brown        
6 Biggs Darklighter     84    183 black        
7 Obi-Wan Kenobi        77    182 auburn, white

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Pilih dari dataset starwars hanya karakter yang merupakan android atau yang nilai species-nya tidak diketahui.

Code
starwars |>
  filter(species == "Droid" | is.na(species))

📝 Pilih dari dataset starwars hanya karakter yang beratnya antara 65 dan 90 kg.

Code
starwars |> filter(between(mass, 65, 90))

📝 Setelah menghapus nilai hilang di semua variabel, pilih dari starwars hanya karakter yang manusia dan berasal dari Tatooine.

Code
starwars |>
  drop_na() |> 
  filter(species == "Human" & homeworld == "Tatooine")

📝 Pilih dari starwars asli karakter yang bukan manusia, berjenis kelamin male, tinggi antara 120–170 cm, atau karakter dengan mata coklat atau merah.

Code
starwars |>
  filter((species != "Human" & sex == "male" &
            between(height, 120, 170)) |
           eye_color %in% c("brown", "red"))

📝 Cari informasi tentang fungsi str_detect() dari paket stringr (dimuat dalam tidyverse). Tips: uji fungsi dengan vektor uji terlebih dahulu. Setelah mengetahui cara kerjanya, filter hanya karakter dengan nama belakang Skywalker.

Code
starwars |> filter(str_detect(name, "Skywalker"))

Mengiris Data: slice()

data |> slice(positions)
starwars |> slice(positions)

Terkadang kita mungkin tertarik melakukan pengambilan sampel diskresioner non-acak, atau dengan kata lain, filter berdasarkan posisi: dengan slice(positions) kita dapat memilih baris tertentu dengan memberikan vektor indeks sebagai argumen.

# fila 1
starwars |>
  slice(1)
# A tibble: 1 × 4
  name           height  mass hair_color
  <chr>           <int> <dbl> <chr>     
1 Luke Skywalker    172    77 blond     
# from the 7th to the 9th row
starwars |>
  slice(7:9)
# A tibble: 3 × 4
  name               height  mass hair_color
  <chr>               <int> <dbl> <chr>     
1 Beru Whitesun Lars    165    75 brown     
2 R5-D4                  97    32 <NA>      
3 Biggs Darklighter     183    84 black     
# 2, 7, 10 and 31th rows
starwars |>
  slice(c(2, 7, 10, 31))
# A tibble: 4 × 8
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 C-3PO     167    75 <NA>       gold       yellow           112 none 
2 Beru …    165    75 brown      light      blue              47 fema…
3 Obi-W…    182    77 auburn, w… fair       blue-gray         57 male 
4 Qui-G…    193    89 brown      fair       blue              92 male 

Mengiris Data: slice()

data |>
  slice(positions)
starwars |>
  slice(positions)

Kita memiliki opsi default:

  • dengan slice_head(n = ...) dan slice_tail(n = ...) kita dapat mengambil header dan ekor tabel
starwars |> slice_head(n = 2)
# A tibble: 2 × 4
  name           height  mass hair_color
  <chr>           <int> <dbl> <chr>     
1 Luke Skywalker    172    77 blond     
2 C-3PO             167    75 <NA>      
starwars |> slice_tail(n = 2)
# A tibble: 2 × 4
  name           height  mass hair_color
  <chr>           <int> <dbl> <chr>     
1 BB8                NA    NA none      
2 Captain Phasma     NA    NA none      

Mengiris Data: slice()

data |>
  slice(positions)
starwars |>
  slice(positions)

Kita memiliki opsi default:

  • dengan slice_max() dan slice_min() kita mendapatkan baris dengan nilai terkecil/terbesar dari suatu variabel (jika seri, semuanya kecuali with_ties = FALSE) yang kita tunjukkan dalam order_by = ....
starwars |> slice_min(mass, n = 2)
# A tibble: 2 × 4
  name         height  mass hair_color
  <chr>         <int> <dbl> <chr>     
1 Ratts Tyerel     79    15 none      
2 Yoda             66    17 white     
starwars |> slice_max(height, n = 2)
# A tibble: 2 × 4
  name        height  mass hair_color
  <chr>        <int> <dbl> <chr>     
1 Yarael Poof    264    NA none      
2 Tarfful        234   136 brown     

Pengambilan Sampel Acak: slice_sample()

data |>
  slice_aleatorias(positions)
starwars |>
  slice_sample(positions)

Yang disebut pengambilan sampel acak sederhana didasarkan pada memilih individu secara acak, sehingga setiap individu memiliki probabilitas tertentu untuk dipilih. Dengan slice_sample(n = ...) kita dapat mengekstrak n catatan secara acak (a priori equiprobable).

starwars |> slice_sample(n = 2)
# A tibble: 2 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Mon M…    150    NA auburn     fair       blue              48 fema…
2 Poe D…     NA    NA brown      light      brown             NA male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Penting

“Acak” tidak berarti equiprobable: dadu biasa sama acaknya dengan dadu curang. Tidak ada hal yang “lebih acak” dari yang lain, mereka hanya memiliki hukum probabilitas dasar yang berbeda.

Pengambilan Sampel Acak: slice_sample()

data |>
  slice_random(positions)
starwars |>
  slice_sample(positions)

Kita juga dapat menunjukkan proporsi data yang akan diambil sampelnya (bukan jumlahnya) dan apakah kita ingin dengan penggantian (bisa terulang).

# 5% of random rows with replacement
starwars |> 
  slice_sample(prop = 0.05, replace = TRUE)
# A tibble: 4 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Luke …    172    77 blond      fair       blue              19 male 
2 Grega…    185    85 black      dark       brown             NA <NA> 
3 Poggl…    183    80 none       green      yellow            NA male 
4 Dud B…     94    45 none       blue, grey yellow            NA male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Pengambilan Sampel Acak: slice_sample()

data |>
  slice_random(positions)
starwars |>
  slice_sample(positions)

Seperti yang sudah dikatakan, “acak” tidak sama dengan “equiprobable”, sehingga kita dapat meneruskan vektor probabilitas. Misalnya, mari paksa agar sangat tidak mungkin mengambil baris selain dua baris pertama

starwars |>
  slice_sample(n = 2, weight_by = c(0.495, 0.495, rep(0.01/85, 85)))
# A tibble: 2 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 C-3PO     167    75 <NA>       gold       yellow           112 none 
2 Luke …    172    77 blond      fair       blue              19 male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>
starwars |>
  slice_sample(n = 2, weight_by = c(0.495, 0.495, rep(0.01/85, 85)))
# A tibble: 2 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 C-3PO     167    75 <NA>       gold       yellow           112 none 
2 Luke …    172    77 blond      fair       blue              19 male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

sample()

Fungsi slice_sample() hanyalah integrasi tidyverse dari fungsi dasar R yang dikenal sebagai sample() yang memungkinkan kita mengambil sampel elemen

Misalnya, mari ambil sampel 10 lemparan dadu, dengan menyebutkan

  • dukungan variabel acak kita (nilai yang diizinkan dalam x)
  • ukuran sampel (size)
  • penggantian (jika TRUE maka bisa keluar berulang, seperti kasus dadu).
sample(x = 1:6, size = 10, replace = TRUE)
 [1] 6 3 5 4 6 3 4 5 5 2

sample()

Opsi sebelumnya menghasilkan kejadian dari variabel acak equiprobable tetapi seperti sebelumnya, kita dapat menetapkan vektor probabilitas atau fungsi massa kepadanya dengan argumen prob = ....

sample(x = 1:6, size = 50, replace = TRUE,
       prob = c(0.5, 0.2, 0.1, 0.1, 0.05, 0.05))
 [1] 4 1 2 1 6 4 4 2 1 5 1 1 1 1 1 1 4 2 4 1 1 2 4 1 2 3 2 2 2 5 4 1 1
[34] 3 5 1 1 2 3 1 1 1 3 1 1 4 1 6 1 3

sample()

Bagaimana cara membuat pernyataan berikut?

 

Misalkan episode flu musiman telah dipelajari di sebuah kota. Biarkan \(X_m\) dan \(X_p\) menjadi variabel acak sedemikian rupa sehingga \(X_m=1\) jika ibu terkena flu, \(X_m=0\) jika ibu tidak terkena flu, \(X_p=1\) jika ayah terkena flu dan \(X_p=0\) jika ayah tidak terkena flu. Model teoritis yang terkait dengan jenis epidemi ini menunjukkan bahwa distribusi bersama diberikan oleh \(P(X_m = 1, X_p=1)=0.02\), \(P(X_m = 1, X_p=0)=0.08\), \(P(X_m = 1, X_p=0)=0.1\) dan \(P(X_m = 0, X_p=0)=0.8\)

Buat sampel berukuran \(n = 1000\) (dukungan "10", "01", "00" dan "11") menggunakan runif() dan menggunakan sample().

Mengurutkan Baris: arrange()

data |> sort(var1, var2, ...)
starwars |> arrange(var1, var2, ...)

Kita juga dapat mengurutkan berdasarkan baris sesuai variabel tertentu dengan arrange().

starwars |> arrange(mass)
# A tibble: 5 × 6
  name                  height  mass hair_color skin_color  eye_color
  <chr>                  <int> <dbl> <chr>      <chr>       <chr>    
1 Ratts Tyerel              79    15 none       grey, blue  unknown  
2 Yoda                      66    17 white      green       brown    
3 Wicket Systri Warrick     88    20 brown      brown       brown    
4 R2-D2                     96    32 <NA>       white, blue red      
5 R5-D4                     97    32 <NA>       white, red  red      

Secara dari terkecil ke terbesar tetapi kita dapat membalik urutannya dengan desc().

starwars |> arrange(desc(height))
# A tibble: 5 × 3
  name         height  mass
  <chr>         <int> <dbl>
1 Yarael Poof     264    NA
2 Tarfful         234   136
3 Lama Su         229    88
4 Chewbacca       228   112
5 Roos Tarpals    224    82
starwars |> arrange(mass, desc(height))
# A tibble: 5 × 3
  name                  height  mass
  <chr>                  <int> <dbl>
1 Ratts Tyerel              79    15
2 Yoda                      66    17
3 Wicket Systri Warrick     88    20
4 R5-D4                     97    32
5 R2-D2                     96    32

Menghapus Duplikat: distinct()

data |> no_duplicates(var1, var2, ...)
starwars |> distinct(var1, var2, ...)

Berkali-kali kita perlu memastikan tidak ada duplikat dalam beberapa variabel dan kita dapat menghapus baris duplikat dengan distinct().

starwars |> distinct(sex)
# A tibble: 5 × 1
  sex           
  <chr>         
1 male          
2 none          
3 female        
4 hermaphroditic
5 <NA>          

Untuk menyimpan semua kolom tabel kita akan menggunakan .keep_all = TRUE.

starwars |> distinct(sex, .keep_all = TRUE)
# A tibble: 3 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Luke …    172    77 blond      fair       blue              19 male 
2 C-3PO     167    75 <NA>       gold       yellow           112 none 
3 Leia …    150    49 brown      light      brown             19 fema…
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Menambahkan Baris: bind_rows()

tibble1 |> include_rows(tibble2)
tibble1 |> bind_rows(tibble2)

Terakhir, kita dapat menambahkan baris baru dengan bind_rows() dengan pengamatan baru dalam tabel (jika kolom tidak cocok diisi dengan nilai hilang)

data <-
  tibble("name" = c("javi", "laura"), "age" = c(33, 50))
data
# A tibble: 2 × 2
  name    age
  <chr> <dbl>
1 javi     33
2 laura    50
data |> bind_rows(tibble("name" = c("carlos", NA), "cp" = c(28045, 28019)))
# A tibble: 4 × 3
  name     age    cp
  <chr>  <dbl> <dbl>
1 javi      33    NA
2 laura     50    NA
3 carlos    NA 28045
4 <NA>      NA 28019

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Pilih hanya karakter manusia bermata coklat, lalu urutkan dari tinggi menurun dan berat menaik.

Code
starwars |>
  filter(eye_color == "brown" & species == "Human") |> 
  arrange(height, desc(mass))

📝 Ekstrak 3 catatan secara acak.

Code
starwars |> slice_sample(n = 3)

📝 Ekstrak 10% catatan secara acak.

Code
starwars |> slice_sample(prop = 0.1)

📝 Ambil 10 karakter secara acak sedemikian rupa sehingga probabilitas setiap karakter dipilih sebanding dengan beratnya (lebih berat, lebih mungkin terpilih).

Code
starwars |>
  drop_na(mass) |> 
  slice_sample(n = 10, weight_by = mass)

📝 Pilih 3 karakter tertua.

Code
starwars |> slice_max(birth_year, n = 3)

📝 Untuk mengetahui nilai unik dalam warna rambut, hapus duplikat variabel hair_color dengan terlebih dahulu menghapus nilai yang hilang.

Code
starwars |>
  drop_na(hair_color) |> 
  distinct(hair_color)

📝 Dari karakter manusia dengan tinggi >160 cm, hapus duplikat warna mata, hapus nilai hilang pada berat, pilih 3 tertinggi, dan urutkan dari berat terbesar ke terkecil.

Code
starwars |>
  filter(species == "Human" & height > 160) |> 
  distinct(eye_color, .keep_all = TRUE) |> 
  drop_na(mass) |> 
  slice_max(height, n = 3) |> 
  arrange(desc(mass))

🐣 Studi Kasus

Mari kembali ke dataset yang sudah dikenal: dalam paket {datasets} kita memiliki beberapa dataset, salah satunya airquality yang sudah kita kerjakan. Data ini merekam pengukuran harian (n = 153 observasi) kualitas udara di New York, Mei–September 1973.

Saat itu kita mengerjakannya dari perspektif R base. Tujuan sekarang adalah mengerjakannya dari perspektif tidyverse sambil melihat perbedaan antara kedua cara tersebut.

library(datasets)
airquality

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

L3: tidyverse (kolom)

Tidyverse: tindakan berdasarkan kolom

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Hingga saat ini semua operasi yang dilakukan (meskipun menggunakan info kolom) adalah berdasarkan baris. Untuk kolom, tindakan paling sederhana adalah memilih variabel berdasarkan nama dengan select(), dengan memberikan nama kolom tanpa tanda kutip sebagai argumen.

starwars |> select(name, hair_color)
# A tibble: 87 × 2
   name               hair_color   
   <chr>              <chr>        
 1 Luke Skywalker     blond        
 2 C-3PO              <NA>         
 3 R2-D2              <NA>         
 4 Darth Vader        none         
 5 Leia Organa        brown        
 6 Owen Lars          brown, grey  
 7 Beru Whitesun Lars brown        
 8 R5-D4              <NA>         
 9 Biggs Darklighter  black        
10 Obi-Wan Kenobi     auburn, white
# ℹ 77 more rows

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Fungsi select() memungkinkan memilih beberapa variabel sekaligus, termasuk menghubungkan nama-namanya seolah indeks numerik dengan :

starwars |> select(name:eye_color) 
# A tibble: 4 × 6
  name           height  mass hair_color skin_color  eye_color
  <chr>           <int> <dbl> <chr>      <chr>       <chr>    
1 Luke Skywalker    172    77 blond      fair        blue     
2 C-3PO             167    75 <NA>       gold        yellow   
3 R2-D2              96    32 <NA>       white, blue red      
4 Darth Vader       202   136 none       white       yellow   

Dan kita dapat membatalkan pilihan kolom dengan tanda - di depannya

starwars |>  select(-mass, -(eye_color:starships))
# A tibble: 4 × 4
  name           height hair_color skin_color 
  <chr>           <int> <chr>      <chr>      
1 Luke Skywalker    172 blond      fair       
2 C-3PO             167 <NA>       gold       
3 R2-D2              96 <NA>       white, blue
4 Darth Vader       202 none       white      

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Kita juga memiliki kata-kata khusus: everything() untuk semua variabel….

starwars |> select(mass, homeworld, everything())
# A tibble: 4 × 14
   mass homeworld name          height hair_color skin_color eye_color
  <dbl> <chr>     <chr>          <int> <chr>      <chr>      <chr>    
1    77 Tatooine  Luke Skywalk…    172 blond      fair       blue     
2    75 Tatooine  C-3PO            167 <NA>       gold       yellow   
3    32 Naboo     R2-D2             96 <NA>       white, bl… red      
4   136 Tatooine  Darth Vader      202 none       white      yellow   
# ℹ 7 more variables: birth_year <dbl>, sex <chr>, gender <chr>,
#   species <chr>, films <list>, vehicles <list>, starships <list>

…and last_col() to refer to last column.

starwars |> select(name:mass, homeworld, last_col())
# A tibble: 4 × 5
  name           height  mass homeworld starships
  <chr>           <int> <dbl> <chr>     <list>   
1 Luke Skywalker    172    77 Tatooine  <chr [2]>
2 C-3PO             167    75 Tatooine  <chr [0]>
3 R2-D2              96    32 Naboo     <chr [0]>
4 Darth Vader       202   136 Tatooine  <chr [1]>

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Kita juga dapat bermain dengan pola dalam nama: yang dimulai dengan awalan (starts_with()), diakhiri dengan akhiran (ends_with()), mengandung teks (contains()), atau memenuhi ekspresi reguler (matches()).

# variables which col name finish as "color" and contains sex and gender
starwars |> select(ends_with("color"), matches("sex|gender"))
# A tibble: 87 × 5
   hair_color    skin_color  eye_color sex    gender   
   <chr>         <chr>       <chr>     <chr>  <chr>    
 1 blond         fair        blue      male   masculine
 2 <NA>          gold        yellow    none   masculine
 3 <NA>          white, blue red       none   masculine
 4 none          white       yellow    male   masculine
 5 brown         light       brown     female feminine 
 6 brown, grey   light       blue      male   masculine
 7 brown         light       blue      female feminine 
 8 <NA>          white, red  red       none   masculine
 9 black         light       brown     male   masculine
10 auburn, white fair        blue-gray male   masculine
# ℹ 77 more rows

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Kita bahkan dapat memilih berdasarkan rentang numerik jika memiliki variabel dengan awalan dan angka.

data <-
  tibble("wk1" = c(115, 141, 232), "wk2" = c(7, NA, 17),
         "wk3" = c(95, 162, NA), "wk4" = c(11, 19, 15),
         "wk5" = c(NA, 262, 190), "wk6" = c(21, 15, 23))

Dengan num_range() kita dapat memilih dengan awalan dan urutan numerik.

data |> select(num_range("wk", 1:4))
# A tibble: 3 × 4
    wk1   wk2   wk3   wk4
  <dbl> <dbl> <dbl> <dbl>
1   115     7    95    11
2   141    NA   162    19
3   232    17    NA    15

Memilih Kolom: select()

data |> select(var1, var2, ...)
starwars |> select(var1, var2, ...)

Terakhir, kita dapat memilih kolom berdasarkan tipe data menggunakan where() dan fungsi yang mengembalikan nilai logika berdasarkan tipe data.

# just numeric and string columns
starwars |> select(where(is.numeric) | where(is.character))
# A tibble: 87 × 11
   height  mass birth_year name  hair_color skin_color eye_color sex  
    <int> <dbl>      <dbl> <chr> <chr>      <chr>      <chr>     <chr>
 1    172    77       19   Luke… blond      fair       blue      male 
 2    167    75      112   C-3PO <NA>       gold       yellow    none 
 3     96    32       33   R2-D2 <NA>       white, bl… red       none 
 4    202   136       41.9 Dart… none       white      yellow    male 
 5    150    49       19   Leia… brown      light      brown     fema…
 6    178   120       52   Owen… brown, gr… light      blue      male 
 7    165    75       47   Beru… brown      light      blue      fema…
 8     97    32       NA   R5-D4 <NA>       white, red red       none 
 9    183    84       24   Bigg… black      light      brown     male 
10    182    77       57   Obi-… auburn, w… fair       blue-gray male 
# ℹ 77 more rows
# ℹ 3 more variables: gender <chr>, homeworld <chr>, species <chr>

Memindahkan Kolom: relocate()

data |>
  move(var1, after = var2)
starwars |>
  relocate(var1, .after = var2)

Untuk memfasilitasi pemindahan variabel kita memiliki fungsinya, relocate(), dengan menunjukkan di .after atau .before di belakang atau di depan kolom mana kita ingin memindahkannya.

starwars |> relocate(species, .before = name)
# A tibble: 87 × 14
   species name           height  mass hair_color skin_color eye_color
   <chr>   <chr>           <int> <dbl> <chr>      <chr>      <chr>    
 1 Human   Luke Skywalker    172    77 blond      fair       blue     
 2 Droid   C-3PO             167    75 <NA>       gold       yellow   
 3 Droid   R2-D2              96    32 <NA>       white, bl… red      
 4 Human   Darth Vader       202   136 none       white      yellow   
 5 Human   Leia Organa       150    49 brown      light      brown    
 6 Human   Owen Lars         178   120 brown, gr… light      blue     
 7 Human   Beru Whitesun…    165    75 brown      light      blue     
 8 Droid   R5-D4              97    32 <NA>       white, red red      
 9 Human   Biggs Darklig…    183    84 black      light      brown    
10 Human   Obi-Wan Kenobi    182    77 auburn, w… fair       blue-gray
# ℹ 77 more rows
# ℹ 7 more variables: birth_year <dbl>, sex <chr>, gender <chr>,
#   homeworld <chr>, films <list>, vehicles <list>, starships <list>

Mengganti Nama: rename()

data |> rename(new = old)
starwars |> rename(new = old)

Terkadang kita juga ingin memodifikasi “meta-informasi” data, mengganti nama kolom. Gunakan rename() dengan mengetikkan nama baru terlebih dahulu lalu nama lama.

starwars |> rename(nombre = name, altura = height, peso = mass)
# A tibble: 87 × 14
   nombre      altura  peso hair_color skin_color eye_color birth_year
   <chr>        <int> <dbl> <chr>      <chr>      <chr>          <dbl>
 1 Luke Skywa…    172    77 blond      fair       blue            19  
 2 C-3PO          167    75 <NA>       gold       yellow         112  
 3 R2-D2           96    32 <NA>       white, bl… red             33  
 4 Darth Vader    202   136 none       white      yellow          41.9
 5 Leia Organa    150    49 brown      light      brown           19  
 6 Owen Lars      178   120 brown, gr… light      blue            52  
 7 Beru White…    165    75 brown      light      blue            47  
 8 R5-D4           97    32 <NA>       white, red red             NA  
 9 Biggs Dark…    183    84 black      light      brown           24  
10 Obi-Wan Ke…    182    77 auburn, w… fair       blue-gray       57  
# ℹ 77 more rows
# ℹ 7 more variables: sex <chr>, gender <chr>, homeworld <chr>,
#   species <chr>, films <list>, vehicles <list>, starships <list>

Mengekstrak Kolom: pull()

data |> extract(var)
starwars |> pull(var)

Jika melihat output dari select(), itu masih berupa tabel tibble, mempertahankan sifat data kita.

starwars |> select(name)
# A tibble: 87 × 1
   name              
   <chr>             
 1 Luke Skywalker    
 2 C-3PO             
 3 R2-D2             
 4 Darth Vader       
 5 Leia Organa       
 6 Owen Lars         
 7 Beru Whitesun Lars
 8 R5-D4             
 9 Biggs Darklighter 
10 Obi-Wan Kenobi    
# ℹ 77 more rows

Mengekstrak Kolom: pull()

data |> extract(var)
starwars |> pull(var)

Terkadang kita tidak menginginkan struktur seperti itu, melainkan mengekstrak kolom secara harfiah sebagai VEKTOR, yang dapat dilakukan dengan pull().

starwars |> pull(name)
 [1] "Luke Skywalker"        "C-3PO"                
 [3] "R2-D2"                 "Darth Vader"          
 [5] "Leia Organa"           "Owen Lars"            
 [7] "Beru Whitesun Lars"    "R5-D4"                
 [9] "Biggs Darklighter"     "Obi-Wan Kenobi"       
[11] "Anakin Skywalker"      "Wilhuff Tarkin"       
[13] "Chewbacca"             "Han Solo"             
[15] "Greedo"                "Jabba Desilijic Tiure"
[17] "Wedge Antilles"        "Jek Tono Porkins"     
[19] "Yoda"                  "Palpatine"            
[21] "Boba Fett"             "IG-88"                
[23] "Bossk"                 "Lando Calrissian"     
[25] "Lobot"                 "Ackbar"               
[27] "Mon Mothma"            "Arvel Crynyd"         
[29] "Wicket Systri Warrick" "Nien Nunb"            
[31] "Qui-Gon Jinn"          "Nute Gunray"          
[33] "Finis Valorum"         "Padmé Amidala"        
[35] "Jar Jar Binks"         "Roos Tarpals"         
[37] "Rugor Nass"            "Ric Olié"             
[39] "Watto"                 "Sebulba"              
[41] "Quarsh Panaka"         "Shmi Skywalker"       
[43] "Darth Maul"            "Bib Fortuna"          
[45] "Ayla Secura"           "Ratts Tyerel"         
[47] "Dud Bolt"              "Gasgano"              
[49] "Ben Quadinaros"        "Mace Windu"           
[51] "Ki-Adi-Mundi"          "Kit Fisto"            
[53] "Eeth Koth"             "Adi Gallia"           
[55] "Saesee Tiin"           "Yarael Poof"          
[57] "Plo Koon"              "Mas Amedda"           
[59] "Gregar Typho"          "Cordé"                
[61] "Cliegg Lars"           "Poggle the Lesser"    
[63] "Luminara Unduli"       "Barriss Offee"        
[65] "Dormé"                 "Dooku"                
[67] "Bail Prestor Organa"   "Jango Fett"           
[69] "Zam Wesell"            "Dexter Jettster"      
[71] "Lama Su"               "Taun We"              
[73] "Jocasta Nu"            "R4-P17"               
[75] "Wat Tambor"            "San Hill"             
[77] "Shaak Ti"              "Grievous"             
[79] "Tarfful"               "Raymus Antilles"      
[81] "Sly Moore"             "Tion Medon"           
[83] "Finn"                  "Rey"                  
[85] "Poe Dameron"           "BB8"                  
[87] "Captain Phasma"       

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Filter karakter dan simpan hanya yang tidak memiliki data hilang pada variabel height. Dengan data tersebut, pilih hanya variabel name, height, serta semua variabel yang MENGANDUNG kata color dalam namanya.

Code
starwars_2 <-
  starwars |> 
  drop_na(height) |> 
  select(name, height, contains("color"))

📝 Dengan data dari latihan sebelumnya, terjemahkan nama kolom ke dalam bahasa Indonesia.

Code
starwars_2 |> 
  rename(nombre = name, altura = height, color_pelo = hair_color,
         color_piel = skin_color, color_ojos = eye_color)

📝 Dengan data dari Latihan 1, tempatkan variabel warna rambut tepat setelah variabel nama.

Con los data obtenidos del Exercise anterior, coloca la variable de color de pelo justo detrás de la variable de nombres.

Code
starwars_2 |>
  relocate(hair_color, .after = name)

📝 Dengan data dari Latihan 1, periksa berapa banyak modalitas unik dalam variabel warna rambut (tanpa menggunakan unique()).

Code
starwars_2 |>
  distinct(hair_color)

📝 Dari dataset asli, hapus kolom bertipe list, lalu hapus duplikat pada variabel eye_color. Setelah menghapus duplikat, ekstrak kolom tersebut ke dalam vektor.

Code
starwars |> 
  select(-where(is.list)) |> 
  distinct(eye_color, .keep_all = TRUE) |> 
  pull(eye_color)

📝 Dari dataset starwars asli, hanya dengan karakter yang tingginya diketahui, ekstrak variabel tersebut ke dalam vektor.

Code
starwars |> 
  drop_na(height) |> 
  pull(height)

📝 Setelah mendapatkan vektor dari latihan sebelumnya, gunakan vektor ini untuk mengambil sampel acak 50% data sehingga probabilitas karakter dipilih berbanding terbalik dengan tingginya (lebih pendek, lebih banyak kemungkinan).

Code
heights <-
  starwars |> 
  drop_na(height) |> 
  pull(height)
  
starwars |> 
  slice_sample(prop = 0.5, weight_by = 1/heights)

Memodifikasi Kolom: mutate()

data |> modify(new_var = funcion())
starwars |> mutate(new_var = function())

Dalam banyak kesempatan kita ingin memodifikasi atau membuat variabel dengan mutate().

Misalnya mari buat variabel baru height_m dengan tinggi dalam meter.

starwars |> mutate(height_m = height / 100)
# A tibble: 87 × 15
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 C-3PO    167    75 <NA>       gold       yellow         112   none 
 3 R2-D2     96    32 <NA>       white, bl… red             33   none 
 4 Dart…    202   136 none       white      yellow          41.9 male 
 5 Leia…    150    49 brown      light      brown           19   fema…
 6 Owen…    178   120 brown, gr… light      blue            52   male 
 7 Beru…    165    75 brown      light      blue            47   fema…
 8 R5-D4     97    32 <NA>       white, red red             NA   none 
 9 Bigg…    183    84 black      light      brown           24   male 
10 Obi-…    182    77 auburn, w… fair       blue-gray       57   male 
# ℹ 77 more rows
# ℹ 7 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>, height_m <dbl>

Memodifikasi Kolom: mutate()

data |> modify(new_var = funcion())
starwars |> mutate(new_var = function())

Selain itu dengan argumen opsional kita dapat memposisikan ulang kolom yang dimodifikasi

starwars |> 
  mutate(height_m = height / 100,
         BMI = mass / (height_m^2), .before = name)
# A tibble: 87 × 16
   height_m   BMI name    height  mass hair_color skin_color eye_color
      <dbl> <dbl> <chr>    <int> <dbl> <chr>      <chr>      <chr>    
 1     1.72  26.0 Luke S…    172    77 blond      fair       blue     
 2     1.67  26.9 C-3PO      167    75 <NA>       gold       yellow   
 3     0.96  34.7 R2-D2       96    32 <NA>       white, bl… red      
 4     2.02  33.3 Darth …    202   136 none       white      yellow   
 5     1.5   21.8 Leia O…    150    49 brown      light      brown    
 6     1.78  37.9 Owen L…    178   120 brown, gr… light      blue     
 7     1.65  27.5 Beru W…    165    75 brown      light      blue     
 8     0.97  34.0 R5-D4       97    32 <NA>       white, red red      
 9     1.83  25.1 Biggs …    183    84 black      light      brown    
10     1.82  23.2 Obi-Wa…    182    77 auburn, w… fair       blue-gray
# ℹ 77 more rows
# ℹ 8 more variables: birth_year <dbl>, sex <chr>, gender <chr>,
#   homeworld <chr>, species <chr>, films <list>, vehicles <list>,
#   starships <list>

Memodifikasi Kolom: mutate()

data |> modify(new_var = funcion())
starwars |> mutate(new_var = function())

Penting

Saat menerapkan mutate(), ingat bahwa operasi dilakukan vektor per vektor, elemen per elemen, sehingga fungsi yang digunakan harus mengembalikan vektor dengan panjang yang sama. Jika tidak, akan mengembalikan konstanta.

starwars |> 
  mutate(constante = mean(mass, na.rm = TRUE), .before = name)
# A tibble: 87 × 15
   constante name         height  mass hair_color skin_color eye_color
       <dbl> <chr>         <int> <dbl> <chr>      <chr>      <chr>    
 1      97.3 Luke Skywal…    172    77 blond      fair       blue     
 2      97.3 C-3PO           167    75 <NA>       gold       yellow   
 3      97.3 R2-D2            96    32 <NA>       white, bl… red      
 4      97.3 Darth Vader     202   136 none       white      yellow   
 5      97.3 Leia Organa     150    49 brown      light      brown    
 6      97.3 Owen Lars       178   120 brown, gr… light      blue     
 7      97.3 Beru Whites…    165    75 brown      light      blue     
 8      97.3 R5-D4            97    32 <NA>       white, red red      
 9      97.3 Biggs Darkl…    183    84 black      light      brown    
10      97.3 Obi-Wan Ken…    182    77 auburn, w… fair       blue-gray
# ℹ 77 more rows
# ℹ 8 more variables: birth_year <dbl>, sex <chr>, gender <chr>,
#   homeworld <chr>, species <chr>, films <list>, vehicles <list>,
#   starships <list>

Rekategorisasi: if_else()

Kita juga dapat menggabungkan mutate() dengan ekspresi kontrol if_else() untuk mengkategorikan ulang variabel: jika kondisi terpenuhi, lakukan satu hal, jika tidak lakukan hal lain.

starwars |> 
  mutate(human = if_else(species == "Human", "Human", "Not Human"),
         .after = name) |> 
  select(name:mass)
# A tibble: 87 × 4
   name               human     height  mass
   <chr>              <chr>      <int> <dbl>
 1 Luke Skywalker     Human        172    77
 2 C-3PO              Not Human    167    75
 3 R2-D2              Not Human     96    32
 4 Darth Vader        Human        202   136
 5 Leia Organa        Human        150    49
 6 Owen Lars          Human        178   120
 7 Beru Whitesun Lars Human        165    75
 8 R5-D4              Not Human     97    32
 9 Biggs Darklighter  Human        183    84
10 Obi-Wan Kenobi     Human        182    77
# ℹ 77 more rows

Rekategorisasi: case_when()

Untuk kategorisasi yang lebih kompleks kita memiliki case_when(), misalnya untuk membuat kategori karakter berdasarkan tinggi badannya.

starwars |> 
  drop_na(height) |> 
  mutate(altura = case_when(height < 120 ~ "dwarf",
                            height < 160 ~ "short",
                            height < 180 ~ "normal",
                            height < 200 ~ "tall",
                            TRUE ~ "giant"), .before = name)
# A tibble: 81 × 15
   altura name            height  mass hair_color skin_color eye_color
   <chr>  <chr>            <int> <dbl> <chr>      <chr>      <chr>    
 1 normal Luke Skywalker     172    77 blond      fair       blue     
 2 normal C-3PO              167    75 <NA>       gold       yellow   
 3 dwarf  R2-D2               96    32 <NA>       white, bl… red      
 4 giant  Darth Vader        202   136 none       white      yellow   
 5 short  Leia Organa        150    49 brown      light      brown    
 6 normal Owen Lars          178   120 brown, gr… light      blue     
 7 normal Beru Whitesun …    165    75 brown      light      blue     
 8 dwarf  R5-D4               97    32 <NA>       white, red red      
 9 tall   Biggs Darkligh…    183    84 black      light      brown    
10 tall   Obi-Wan Kenobi     182    77 auburn, w… fair       blue-gray
# ℹ 71 more rows
# ℹ 8 more variables: birth_year <dbl>, sex <chr>, gender <chr>,
#   homeworld <chr>, species <chr>, films <list>, vehicles <list>,
#   starships <list>

nest data

Kita juga dapat menyarangkan atau menyematkan dataset satu sama lain. Bayangkan kita memiliki dataset variabel x dan y dengan 2 catatan, satu lagi dengan satu catatan, dan satu lagi dengan 3 catatan.

data_1 <- tibble("x" = c(0, 2), "y" = c(-1, NA))
data_2 <- tibble("x" = c(NA), "y" = c(5))
data_3 <- tibble("x" = c(-2, 6, 7), "y" = c(1.5, NA, -2))

Sejauh ini satu-satunya cara yang kita tahu untuk menggabungkan 3 dataset adalah menggunakan bind_rows() (ngomong-ngomong, jika menggunakan argumen .id = "nama_variabel" kita dapat membuatnya menambahkan variabel baru yang memberi tahu dataset asal setiap baris).

data <- bind_rows(data_1, data_2, data_3, .id = "dataset")
data
# A tibble: 6 × 3
  dataset     x     y
  <chr>   <dbl> <dbl>
1 1           0  -1  
2 1           2  NA  
3 2          NA   5  
4 3          -2   1.5
5 3           6  NA  
6 3           7  -2  

nest data

data <- bind_rows(data_1, data_2, data_3, .id = "dataset")
data
# A tibble: 6 × 3
  dataset     x     y
  <chr>   <dbl> <dbl>
1 1           0  -1  
2 1           2  NA  
3 2          NA   5  
4 3          -2   1.5
5 3           6  NA  
6 3           7  -2  

Namun, dalam banyak kesempatan kita ingin memiliki ketiganya dalam objek yang sama TETAPI setiap dataset tersendiri: sebuah objek (list) yang menyimpan 3 dataset terpisah

Untuk itu gunakan fungsi nest() dengan menunjukkan variabel umum yang membentuk dataset (dalam kasus ini x dan y).

data_nest <-
  data |>
  nest(data = c(x, y))
data_nest
# A tibble: 3 × 2
  dataset data            
  <chr>   <list>          
1 1       <tibble [2 × 2]>
2 2       <tibble [1 × 2]>
3 3       <tibble [3 × 2]>

nest data

data_nest
# A tibble: 3 × 2
  dataset data            
  <chr>   <list>          
1 1       <tibble [2 × 2]>
2 2       <tibble [1 × 2]>
3 3       <tibble [3 × 2]>

Perhatikan bahwa sekarang data_nest adalah list karena setiap dataset yang disimpan bisa memiliki panjang yang berbeda

nest data

Untuk membuka sarang gunakan unnest() dengan menunjukkan kolom yang berisi dataset

data_nest |> unnest(cols = c(data))
# A tibble: 6 × 3
  dataset     x     y
  <chr>   <dbl> <dbl>
1 1           0  -1  
2 1           2  NA  
3 2          NA   5  
4 3          -2   1.5
5 3           6  NA  
6 3           7  -2  

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Pilih hanya variabel name, height, dan semua variabel terkait warna, sambil menyimpan hanya yang tidak memiliki nilai hilang pada height.

Code
starwars |> 
  select(name, height, contains("color")) |> 
  drop_na(height)

📝 Dengan data dari latihan sebelumnya, terjemahkan nama kolom ke dalam bahasa Indonesia.

Code
starwars |> 
  select(name, height, contains("color")) |> 
  drop_na(height) |> 
  rename(nombre = name, altura = height,
         color_pelo = eye_color, color_piel = skin_color,
         color_pelo = hair_color)

📝 Dengan data dari latihan sebelumnya, tempatkan variabel warna rambut tepat setelah variabel nama.

Code
starwars |>
  select(name, height, contains("color")) |> 
  drop_na(height) |> 
  rename(nombre = name, altura = height,
         color_pelo = eye_color, color_piel = skin_color,
         color_pelo = hair_color) |> 
  relocate(color_pelo, .after = nombre)

📝 Dengan data asli, periksa berapa banyak modalitas unik dalam variabel warna rambut.

Code
starwars |> 
  distinct(hair_color) |> 
  nrow()

📝 Dari dataset asli, pilih hanya variabel numerik dan teks. Kemudian definisikan variabel baru bernama under_18: TRUE jika di bawah umur dan FALSE jika tidak.

Code
starwars |> 
  select(where(is.numeric) | where(is.character)) |> 
  mutate(under_18 = birth_year < 18)

📝 Dari dataset asli, buat kolom baru bernama auburn yang bernilai TRUE jika warna rambut mengandung kata itu dan FALSE jika tidak (ingat str_detect()).

Code
starwars |> 
  mutate(auburn = str_detect(hair_color, "auburn"))

📝 Dari dataset asli, tambahkan kolom yang menghitung BMI. Kemudian buat variabel baru bernilai NA jika bukan manusia, underweight jika BMI <18, normal jika 18–30, overweight jika >30.

Code
starwars |> 
  mutate(IMC = mass / ((height/100)^2),
         IMC_recat = case_when(species != "Human" ~ NA,
                               IMC < 18 ~ "underweight",
                               IMC < 30 ~ "normal",
                               TRUE ~ "overweight"),
         .after = name)

🐣 Studi Kasus I: CIS Feminisme

belum disiapkan to submit

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

🐣 Studi Kasus II: Taylor Swift

Mari kembali ke analisis lagu-lagu Taylor Swift yang kita lakukan sebelumnya.

library(taylor)
taylor_album_songs
# A tibble: 240 × 29
   album_name   ep    album_release track_number track_name     artist
   <chr>        <lgl> <date>               <int> <chr>          <chr> 
 1 Taylor Swift FALSE 2006-10-24               1 Tim McGraw     Taylo…
 2 Taylor Swift FALSE 2006-10-24               2 Picture To Bu… Taylo…
 3 Taylor Swift FALSE 2006-10-24               3 Teardrops On … Taylo…
 4 Taylor Swift FALSE 2006-10-24               4 A Place In Th… Taylo…
 5 Taylor Swift FALSE 2006-10-24               5 Cold As You    Taylo…
 6 Taylor Swift FALSE 2006-10-24               6 The Outside    Taylo…
 7 Taylor Swift FALSE 2006-10-24               7 Tied Together… Taylo…
 8 Taylor Swift FALSE 2006-10-24               8 Stay Beautiful Taylo…
 9 Taylor Swift FALSE 2006-10-24               9 Should've Sai… Taylo…
10 Taylor Swift FALSE 2006-10-24              10 Mary's Song (… Taylo…
# ℹ 230 more rows
# ℹ 23 more variables: featuring <chr>, bonus_track <lgl>,
#   promotional_release <date>, single_release <date>,
#   track_release <date>, danceability <dbl>, energy <dbl>,
#   key <int>, loudness <dbl>, mode <int>, speechiness <dbl>,
#   acousticness <dbl>, instrumentalness <dbl>, liveness <dbl>,
#   valence <dbl>, tempo <dbl>, time_signature <int>, …

Perbedaannya adalah sekarang kita mencoba melakukan segalanya dari sudut pandang tidyverse bukan R base (menarik jika kamu mencoba menerjemahkan dari satu ke yang lain untuk menguasai kedua sudut pandang).

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

🐣 Studi Kasus III: The Lord of the Rings

Untuk berlatih beberapa fungsi dplyr kita akan menggunakan data dari film trilogi Lord of the Rings. Kita akan memuat data langsung dari web (Github dalam kasus ini), tanpa mengunduh terlebih dahulu, cukup menunjukkan tautan web sebagai path.

Code
library(readr)
lotr_1 <-
  read_csv(file = "https://raw.githubusercontent.com/jennybc/lotr-tidy/master/data/The_Fellowship_Of_The_Ring.csv")
Rows: 3 Columns: 4
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (2): Film, Race
dbl (2): Female, Male

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Code
lotr_2 <-
  read_csv(file = "https://raw.githubusercontent.com/jennybc/lotr-tidy/master/data/The_Two_Towers.csv")
Rows: 3 Columns: 4
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (2): Film, Race
dbl (2): Female, Male

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Code
lotr_3 <-
  read_csv(file = "https://raw.githubusercontent.com/jennybc/lotr-tidy/master/data/The_Return_Of_The_King.csv")
Rows: 3 Columns: 4
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (2): Film, Race
dbl (2): Female, Male

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

L4: tidyverse (ringkasan)

Summarise dan group_by(). Menghitung dan merangkum

count()

data |> count(var1, var2)
starwars |> count(var1, var2)

Sejauh ini kita hanya mengubah atau meminta data tetapi belum menghasilkan statistik. Mari mulai dengan yang sederhana: bagaimana cara menghitung (frekuensi)?

Ketika digunakan sendiri count() hanya mengembalikan jumlah catatan, tetapi ketika digunakan dengan variabel, dihitung yang dikenal sebagai frekuensi: jumlah elemen setiap modalitas.

starwars |> count(sex)
# A tibble: 5 × 2
  sex                n
  <chr>          <int>
1 female            16
2 hermaphroditic     1
3 male              60
4 none               6
5 <NA>               4

count()

data |> count(var1, var2)
starwars |> count(var1, var2)

Jika kita meneruskan beberapa variabel, dihitung yang dikenal sebagai tabel kontingensi. Dengan sort = TRUE akan mengembalikan hitungan terurut (yang paling sering pertama).

starwars |> count(sex, gender, sort = TRUE)
# A tibble: 6 × 3
  sex            gender        n
  <chr>          <chr>     <int>
1 male           masculine    60
2 female         feminine     16
3 none           masculine     5
4 <NA>           <NA>          4
5 hermaphroditic masculine     1
6 none           feminine      1

group_by()

data |>
  group(var1, var2) |> 
  some_action() |> 
  ungroup()
starwars |>
  group_by(var1, var2) |> 
  some_action() |> 
  ungroup()

Salah satu fungsi paling kuat untuk digabungkan dengan tindakan yang sudah dipelajari adalah group_by(), yang memungkinkan kita mengelompokkan catatan terlebih dahulu.

starwars |> 
  group_by(sex) |>
  count() |>
  ungroup()
# A tibble: 5 × 2
  sex                n
  <chr>          <int>
1 female            16
2 hermaphroditic     1
3 male              60
4 none               6
5 <NA>               4

group_by()

data |>
  group(var1, var2) |> 
  some_action() |> 
  ungroup()
starwars |>
  group_by(var1, var2) |> 
  some_action() |> 
  ungroup()

Saat menerapkan group_by() penting dipahami bahwa itu TIDAK MEMODIFIKASI data, tetapi membuat variabel grup (sub-tabel untuk setiap grup) yang akan memodifikasi tindakan mendatang: operasi akan diterapkan pada setiap sub-tabel secara terpisah

Misalnya, bayangkan kita ingin mengekstrak karakter tertinggi dengan slice_max().

starwars |> slice_max(height)
# A tibble: 1 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Yarae…    264    NA none       white      yellow            NA male 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

group_by()

data |>
  group(var1, var2) |> 
  some_action() |> 
  ungroup()
starwars |>
  group_by(var1, var2) |> 
  some_action() |> 
  ungroup()

Bagaimana jika kita ingin mengekstrak karakter tertinggi tetapi…dari masing-masing jenis kelamin?

starwars |>
  group_by(sex) |> 
  slice_max(height) |> 
  ungroup()
# A tibble: 5 × 14
  name   height  mass hair_color skin_color eye_color birth_year sex  
  <chr>   <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
1 Taun …    213    NA none       grey       black             NA fema…
2 Jabba…    175  1358 <NA>       green-tan… orange           600 herm…
3 Yarae…    264    NA none       white      yellow            NA male 
4 IG-88     200   140 none       metal      red               15 none 
5 Grega…    185    85 black      dark       brown             NA <NA> 
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

group_by()

data |>
  group(var1, var2) |> 
  some_action() |> 
  ungroup()
starwars |>
  group_by(var1, var2) |> 
  some_action() |> 
  ungroup()

Web https://tidydatatutor.com/ memungkinkan visualisasi operasi tidyverse (menggunakan pipe lama %>%)

group_by()

data |>
  group(var1, var2) |> 
  some_action() |> 
  ungroup()
starwars |>
  group_by(var1, var2) |> 
  some_action() |>
  ungroup()

Penting

Kamu harus selalu ingat untuk melakukan ungroup untuk menghapus variabel grup yang dibuat.

Versi “baru” dplyr sekarang memungkinkan menyertakan variabel grup dalam pemanggilan banyak fungsi dengan argumen by = ... atau .by = ....

starwars |> slice_max(height, by = sex)
# A tibble: 5 × 6
  name                  height  mass hair_color skin_color   eye_color
  <chr>                  <int> <dbl> <chr>      <chr>        <chr>    
1 Yarael Poof              264    NA none       white        yellow   
2 IG-88                    200   140 none       metal        red      
3 Taun We                  213    NA none       grey         black    
4 Jabba Desilijic Tiure    175  1358 <NA>       green-tan, … orange   
5 Gregar Typho             185    85 black      dark         brown    

Baris per Baris: rowwise()

Opsi yang sangat berguna sebelum operasi adalah rowwise(): setiap operasi yang mengikutinya akan diterapkan pada setiap baris secara terpisah. Misalnya, mari definisikan dataset nilai fiktif.

grades <- tibble("maths" = c(7.5, 8, 9.1, 3),
                 "language" = c(8, 6, 6.5, 9.2))

Jika kita menerapkan rata-rata secara langsung, nilainya akan identik karena dihitung secara global, tetapi kita ingin mendapatkan rata-rata per catatan. Untuk itu gunakan rowwise().

grades |> 
  rowwise() |> 
  mutate(ave_grades = mean(c(maths, language)))
# A tibble: 4 × 3
# Rowwise: 
  maths language ave_grades
  <dbl>    <dbl>      <dbl>
1   7.5      8         7.75
2   8        6         7   
3   9.1      6.5       7.8 
4   3        9.2       6.1 

Ringkasan: summarise()

data |> simple_summary()
starwars |> summarise()

Terakhir kita memiliki summarise(), yang memungkinkan mendapatkan ringkasan statistik. Misalnya, mari hitung rata-rata tinggi badan.

starwars |> 
  drop_na(height) |> 
  summarise(ave_height = mean(height))
# A tibble: 1 × 1
  ave_height
       <dbl>
1       175.

Be careful

Perhatikan bahwa mutate() mengembalikan sebanyak baris seperti catatan asli, sementara summarise() menghitung dataset ringkasan baru, hanya menyertakan apa yang ditunjukkan.

Ringkasan: summarise()

data |> simple_summary()
starwars |> summarise()

Jika kita juga menggabungkan ini dengan pengelompokan dari group_by() atau .by = ..., dalam beberapa baris kode kamu bisa mendapatkan statistik yang dipecah.

starwars |> 
  drop_na(sex, height, mass) |> 
  summarise(ave_height = mean(height),
            ave_mass = mean(mass),
            .by = sex)
# A tibble: 4 × 3
  sex            ave_height ave_mass
  <chr>               <dbl>    <dbl>
1 male                 178.     80.2
2 none                 140      69.8
3 female               172.     54.7
4 hermaphroditic       175    1358  

Ringkasan Lanjutan: reframe()

data |> complex_summary()
starwars |> reframe()

Dalam dplyr baru terdapat reframe() untuk menghindari masalah summarise() ketika kita mengembalikan lebih dari satu nilai per variabel dalam ringkasan yang lebih kompleks.

starwars |>
  drop_na(mass) |>
  summarise(quantile(mass))
Warning: Returning more (or less) than 1 row per `summarise()` group was
deprecated in dplyr 1.1.0.
ℹ Please use `reframe()` instead.
ℹ When switching from `summarise()` to `reframe()`, remember that
  `reframe()` always returns an ungrouped data frame and adjust
  accordingly.
# A tibble: 5 × 1
  `quantile(mass)`
             <dbl>
1             15  
2             55.6
3             79  
4             84.5
5           1358  
starwars |>
  drop_na(mass) |>
  reframe(quantile(mass))
# A tibble: 5 × 1
  `quantile(mass)`
             <dbl>
1             15  
2             55.6
3             79  
4             84.5
5           1358  

across()

Satu trik adalah memanfaatkan pemilih across() dan where(). Yang pertama memungkinkan kita bertindak pada beberapa kolom berdasarkan nama (dengan mutate() atau summarise()).

starwars |> summarise(ave = across(height:mass, mean, na.rm = TRUE), .by = sex)
Warning: There was 1 warning in `summarise()`.
ℹ In argument: `ave = across(height:mass, mean, na.rm = TRUE)`.
ℹ In group 1: `sex = "male"`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function
instead.

  # Previously
  across(a:b, mean, na.rm = TRUE)

  # Now
  across(a:b, \(x) mean(x, na.rm = TRUE))
# A tibble: 5 × 2
  sex            ave$height  $mass
  <chr>               <dbl>  <dbl>
1 male                 179.   80.2
2 none                 131.   69.8
3 female               172.   54.7
4 hermaphroditic       175  1358  
5 <NA>                 175    81  

Yang kedua, where(), memungkinkan hal yang sama tetapi memilih berdasarkan tipe.

starwars |> 
  summarise(across(where(is.numeric), mean, na.rm = TRUE), .by = c(sex, gender))
# A tibble: 6 × 5
  sex            gender    height   mass birth_year
  <chr>          <chr>      <dbl>  <dbl>      <dbl>
1 male           masculine   179.   80.2       84.8
2 none           masculine   140    69.8       53.3
3 female         feminine    172.   54.7       47.2
4 hermaphroditic masculine   175  1358        600  
5 <NA>           <NA>        175    81        NaN  
6 none           feminine     96   NaN        NaN  

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Hitung berapa banyak karakter dari setiap spesies, diurutkan dari paling ke paling jarang.

Code
starwars |> count(species, sort = TRUE)

📝 Setelah menghapus nilai hilang untuk berat dan tinggi, tambahkan variabel BMI dan tentukan rata-rata BMI karakter yang dipecah berdasarkan jenis kelamin.

Code
starwars |>
  drop_na(mass, height) |> 
  mutate(BMI = mass / ((height/100)^2)) |> 
  summarise(ave_BMI = mean(BMI), .by = sex)

📝 Dapatkan karakter termuda untuk setiap jenis kelamin.

Code
starwars |> # reminder that birth_year is in fact the age
  slice_min(birth_year, by = sex)

📝 Dapatkan umur karakter termuda dan tertua dari setiap jenis kelamin.

Code
starwars |>
  drop_na(birth_year) |>
  summarise(min(birth_year), max(birth_year), .by = sex)

📝 Tentukan jumlah karakter di setiap dekade (lihat round()), pertama tanpa dipecah lalu dipecah berdasarkan jenis kelamin.

Code
starwars |>
  count(birth_decade = round(birth_year, -1))

🐣 Studi Kasus I: Billboard

Kita akan melakukan rangkuman apa yang dipelajari dalam tidyverse dengan tabel billboard dari paket tidyr. Dataset ini merepresentasikan sesuatu mirip top 40 (versi Amerika, top 100): untuk setiap artis dan lagu kita menyimpan tanggal saat masuk peringkat dan posisi yang ditempati di setiap minggu (wk1, wk2, …).

billboard
# A tibble: 317 × 8
   artist         track     date.entered   wk1   wk2   wk3   wk4   wk5
   <chr>          <chr>     <date>       <dbl> <dbl> <dbl> <dbl> <dbl>
 1 2 Pac          Baby Don… 2000-02-26      87    82    72    77    87
 2 2Ge+her        The Hard… 2000-09-02      91    87    92    NA    NA
 3 3 Doors Down   Kryptoni… 2000-04-08      81    70    68    67    66
 4 3 Doors Down   Loser     2000-10-21      76    76    72    69    67
 5 504 Boyz       Wobble W… 2000-04-15      57    34    25    17    17
 6 98^0           Give Me … 2000-08-19      51    39    34    26    26
 7 A*Teens        Dancing … 2000-07-08      97    97    96    95   100
 8 Aaliyah        I Don't … 2000-01-29      84    62    51    41    38
 9 Aaliyah        Try Again 2000-03-18      59    53    38    28    21
10 Adams, Yolanda Open My … 2000-08-26      76    76    74    69    68
# ℹ 307 more rows

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

🐣 Studi Kasus II: Sepak Bola

Mari terus berlatih dalam tidyverse dengan file futbol.csv, berisi data pemain dari 5 liga sepak bola pria utama, dari 2005 hingga 2019. Data diekstrak menggunakan paket worldfootballR dari https://www.fbref.com.

data <- read_csv(file = "./data/futbol.csv")
Rows: 40393 Columns: 16
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr  (5): team, league, player, country, position
dbl (11): season, date_birth, minutes_playing, minutes_per_match_p...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
data
# A tibble: 40,393 × 16
   season team    league  player           country position date_birth
    <dbl> <chr>   <chr>   <chr>            <chr>   <chr>         <dbl>
 1   2005 Ajaccio Ligue 1 Djamel Abdoun    ALG     MF             1986
 2   2005 Ajaccio Ligue 1 Gaspar Azevedo   POR     DF             1975
 3   2005 Ajaccio Ligue 1 Yacine Bezzaz    ALG     MF             1981
 4   2005 Ajaccio Ligue 1 Nicolas Bonnal   FRA     MF             1976
 5   2005 Ajaccio Ligue 1 Marcelinho Cari… BRA     MF             1971
 6   2005 Ajaccio Ligue 1 Cyril Chapuis    FRA     FW             1979
 7   2005 Ajaccio Ligue 1 Xavier Collin    FRA     DF             1974
 8   2005 Ajaccio Ligue 1 Renaud Connen    FRA     MF             1980
 9   2005 Ajaccio Ligue 1 Yohan Demont     FRA     DF,MF          1978
10   2005 Ajaccio Ligue 1 Christophe Dest… FRA     DF             1973
# ℹ 40,383 more rows
# ℹ 9 more variables: minutes_playing <dbl>,
#   minutes_per_match_playing <dbl>, goals <dbl>, assist <dbl>,
#   goals_minus_pk <dbl>, pk <dbl>, pk_attemp <dbl>,
#   yellow_card <dbl>, red_card <dbl>

🐣 Case study II: soccer

Variabel-variabel mencatat informasi berikut:

  • season, team, league: musim, tim, dan liga.
  • player, country, position, date_birth: nama, negara, posisi, dan tahun lahir pemain.
  • minutes_playing, matches: total menit bermain dan pertandingan 90 menit.
  • goals, assist: gol dan assist.
  • pk, pk_attemp, goals_minus_pk: penalti, penalti yang dicoba, dan gol tanpa penalti.
  • yellow_card, red_card: kartu kuning/merah.

🐣 Case study II: soccer

data
# A tibble: 40,393 × 16
   season team    league  player           country position date_birth
    <dbl> <chr>   <chr>   <chr>            <chr>   <chr>         <dbl>
 1   2005 Ajaccio Ligue 1 Djamel Abdoun    ALG     MF             1986
 2   2005 Ajaccio Ligue 1 Gaspar Azevedo   POR     DF             1975
 3   2005 Ajaccio Ligue 1 Yacine Bezzaz    ALG     MF             1981
 4   2005 Ajaccio Ligue 1 Nicolas Bonnal   FRA     MF             1976
 5   2005 Ajaccio Ligue 1 Marcelinho Cari… BRA     MF             1971
 6   2005 Ajaccio Ligue 1 Cyril Chapuis    FRA     FW             1979
 7   2005 Ajaccio Ligue 1 Xavier Collin    FRA     DF             1974
 8   2005 Ajaccio Ligue 1 Renaud Connen    FRA     MF             1980
 9   2005 Ajaccio Ligue 1 Yohan Demont     FRA     DF,MF          1978
10   2005 Ajaccio Ligue 1 Christophe Dest… FRA     DF             1973
# ℹ 40,383 more rows
# ℹ 9 more variables: minutes_playing <dbl>,
#   minutes_per_match_playing <dbl>, goals <dbl>, assist <dbl>,
#   goals_minus_pk <dbl>, pk <dbl>, pk_attemp <dbl>,
#   yellow_card <dbl>, red_card <dbl>

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

🐣 Studi Kasus III: Pidato

Meskipun kita tidak dapat melakukan operasi aritmatika dengan mereka, beberapa operasi yang dapat kita lakukan dengan string teks akan penting. For that we will use the stringr package (within the same lubridate “universe of packages”).

library(stringr)

Datasetnya adalah discursos (pidato, dari https://github.com/lirondos/discursos-de-navidad) yang menyimpan pidato Natal kepala negara Spanyol 1946–2021 (dalam kediktatoran dan demokrasi)

load(file = "./data/discursos.RData")
# discursos = speeches in spanish

Coba jawab pertanyaan-pertanyaan yang ada di workbook.

L5: loop

Kembali ke R base: loop

Loop

Meskipun dalam banyak kasus dapat digantikan struktur yang lebih efisien dan mudah dibaca, penting mengetahui ekspresi kontrol paling terkenal: loop.

  • for { }: memungkinkan mengulang kode yang sama dalam jumlah tertentu dan diketahui kali.

  • while { }: memungkinkan mengulang kode yang sama dalam jumlah tidak ditentukan (sampai kondisi tidak lagi terpenuhi).

For loop

Loop for adalah struktur yang memungkinkan mengulang serangkaian perintah dalam jumlah terbatas, sudah ditentukan, dan diketahui berdasarkan sekumpulan indeks.

Mari definisikan vektor x <- c(0, -7, 1, 4) dan variabel kosong y. Kemudian kita mendefinisikan loop for dengan for () { }: di dalam tanda kurung kita menunjukkan indeks dan nilai-nilai yang akan dilalui, di dalam tanda kurung kurawal kode yang akan dieksekusi di setiap iterasi (dalam kasus ini, isi y sebagai x + 1).

x <- c(0, -7, 1, 4)
y <- c()

For loop

Loop for adalah struktur yang memungkinkan mengulang serangkaian perintah dalam jumlah terbatas, sudah ditentukan, dan diketahui berdasarkan sekumpulan indeks.

Mari definisikan vektor x <- c(0, -7, 1, 4) dan variabel kosong y. Kemudian kita mendefinisikan loop for dengan for () { }: di dalam tanda kurung kita menunjukkan indeks dan nilai-nilai yang akan dilalui, di dalam tanda kurung kurawal kode yang akan dieksekusi di setiap iterasi (dalam kasus ini, isi y sebagai x + 1).

x <- c(0, -7, 1, 4)
y <- c()

for (i in 1:4) {
  
}

For loop

Loop for adalah struktur yang memungkinkan mengulang serangkaian perintah dalam jumlah terbatas, sudah ditentukan, dan diketahui berdasarkan sekumpulan indeks.

Mari definisikan vektor x <- c(0, -7, 1, 4) dan variabel kosong y. Kemudian kita mendefinisikan loop for dengan for () { }: di dalam tanda kurung kita menunjukkan indeks dan nilai-nilai yang akan dilalui, di dalam tanda kurung kurawal kode yang akan dieksekusi di setiap iterasi (dalam kasus ini, isi y sebagai x + 1).

x <- c(0, -7, 1, 4)
y <- c()

for (i in 1:4) {
  y[i] <- x[i] + 1
}

Loop For

Perhatikan bahwa karena R bekerja secara vektor default, loop ini sama dengan melakukan x + 1 secara langsung.

x <- c(0, -7, 1, 4)
y <- c()

for (i in 1:4) {
  y[i] <- x[i] + 1
}
y
[1]  1 -6  2  5
y2 <- x + 1
y2
[1]  1 -6  2  5

Loop For

Opsi umum lainnya adalah menunjukkan indeks “secara otomatis”: dari yang pertama 1 hingga yang terakhir (sesuai panjang x length(x)).

x <- c(0, -7, 1, 4)
y <- c()

for (i in 1:length(x)) {
  y[i] <- x[i] + 1
}
y
[1]  1 -6  2  5

Loop For

Jadi struktur umum sebuah for-loop akan selalu sebagai berikut

for (index in set) { 
  código (usually depending on index)
}

Dalam kasus loop for kita SELALU mengetahui berapa banyak iterasi yang dilakukan (sebanyak elemen dalam set yang diindeks).

Menghindari Loop

Seperti yang sudah kita pelajari dengan paket microbenchmark, kita dapat memeriksa bagaimana loop biasanya sangat tidak efisien (sehingga harus dihindari dalam sebagian besar kasus)

library(microbenchmark)
x <- 1:1000
microbenchmark(y <- x^2, 
               for (i in 1:100) { y[i] <- x[i]^2 },
               times = 500)
Unit: microseconds
                                    expr    min     lq      mean
                                y <- x^2    1.9    2.2    3.9928
 for (i in 1:100) {     y[i] <- x[i]^2 } 2334.5 2496.7 2909.1480
 median     uq     max neval
    3.6    4.9    31.5   500
 2610.4 2972.1 24316.9   500

Loop For

Kita dapat melihat contoh lain dari loop yang menggabungkan angka dan teks: kita mendefinisikan vektor umur dan nama, lalu mencetak nama dan umur ke-i.

names <- c("Javi", "Sandra", "Carlos", "Marcos", "Marta")
ages <- c(33, 27, 18, 43, 29)

for (i in 1:5) { 
  
  print(glue("{names[i]} are {ages[i]} old")) 
  
}
Javi are 33 old
Sandra are 27 old
Carlos are 18 old
Marcos are 43 old
Marta are 29 old

Loop For

Meskipun biasanya diindeks dengan vektor numerik, loop dapat diindeks pada struktur vektor apapun, terlepas dari tipe set-nya.

library(stringr)
week_days <- c("monday", "tuesday", "wednesday", "thursday",
               "friday", "saturday", "sunday")

for (days in week_days) {
  
  print(days)
}
[1] "monday"
[1] "tuesday"
[1] "wednesday"
[1] "thursday"
[1] "friday"
[1] "saturday"
[1] "sunday"

For + if-else

Mari gabungkan struktur kondisional dan loop: menggunakan set swiss dari paket {datasets}, mari tetapkan NA jika nilai kesuburan lebih dari 80.

for (i in 1:nrow(swiss)) {
  
  if (swiss$Fertility[i] > 80) { 
    
    swiss$Fertility[i] <- NA
    
  }
}

This is «the same» as a vectorized if_else().

data("swiss")
swiss$Fertility <- if_else(swiss$Fertility > 80, NA, swiss$Fertility)

Loop While

Cara lain membuat loop adalah dengan struktur while { }, yang akan berulang dalam jumlah yang tidak diketahui, hingga kondisi tidak lagi terpenuhi (bahkan mungkin tidak pernah berakhir). Misalnya, kita menginisialisasi variabel times <- 1, ditambah setiap langkah, dan tidak keluar dari loop sampai times > 3.

times <- 1
while(times <= 3) {
  
  print(glue("Not yet, we are in the {times}-th iteration")) 
  times <- times + 1
  
}
Not yet, we are in the 1-th iteration
Not yet, we are in the 2-th iteration
Not yet, we are in the 3-th iteration
print(glue("Now! We are in the {times}-th iteration")) 
Now! We are in the 4-th iteration

Loop While

A while loop will always look like this

while(condition) {
  
  code to be executed while condition is TRUE
  # usually some variable is updated here
  
}

Loop While

Apa yang terjadi ketika kondisi tidak pernah FALSE? Coba sendiri

while (1 > 0) {
  
  print("Press ESC to exit")
  
}

 

Peringatan

Loop while { } bisa cukup “berbahaya” jika kita tidak mengontrol dengan baik cara menghentikannya.

Loop While

We have two reserved commands to abort a loop or force it forward:

  • break: allows abort a loop even if its end has not been reached
for(i in 1:10) {
  if (i == 3) {
    
    break # if i = 3, we abort
    
  }
  print(i)
}
[1] 1
[1] 2

Loop While

We have two reserved commands to abort a loop or force it forward:

  • next: forces a loop to advance to the next iteration
for(i in 1:5) {
  if (i == 3) {
    
    next # if i = 3, we advance to the next iteration
    
  }
  print(i)
}
[1] 1
[1] 2
[1] 4
[1] 5

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Modifikasi kode di bawah untuk mencetak pesan di layar jika dan hanya jika semua data dalam airquality adalah untuk bulan selain Januari.

library(datasets)
months <- airquality$Month

if (months == 2) {
  print("No data in January")
}
Code
library(datasets)
months <- airquality$Month

if (all(months != 1)) {
  print("No data in January")
}

📝 Modifikasi kode di bawah untuk menyimpan dalam variabel temp_high nilai TRUE jika ada catatan dengan suhu di atas 90°F dan FALSE dalam kasus lain.

temp <- airquality$Temp

if (temp == 100) {
  print("Some of the records have temperatures in excess of 90 degrees Fahrenheit")
}
Code
# Option 1
temp <- airquality$Temp
temp_high <- FALSE
if (any(temp > 90)) {
   temp_high <- TRUE
}

# Option 2
temp_high <- any(airquality$Temp > 90)

📝 Modifikasi kode di bawah untuk merancang loop for dengan 5 iterasi yang melewati 5 bilangan ganjil pertama (dan mencetak setiap langkahnya).

for (i in 1:5) {
  
  print(i)
}
Code
for (i in c(1, 3, 5, 7, 9)) {
  
  print(i)
}

📝 Modifikasi kode di bawah untuk merancang loop while yang dimulai dengan penghitung count <- 1 dan berhenti ketika mencapai 6.

count <- 1
while (count == 2) {
  
  print(count)
}
Code
count <- 1
while (count < 6) {
  
  print(count)
  count <- count + 1
  
}

🐣 Studi Kasus I: Simulasi

Coba jawab pertanyaan-pertanyaan yang ada di workbook. On it you will have to design some simulation studies using conditional loops and structures.

🐣 Studi Kasus II: Masalah Monty Hall

Bayangkan kamu ada dalam kontes TV di mana diberikan pilihan 3 pintu: di salah satunya ada hadiah jutaan dan di 2 lainnya ada kue oreo.

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook. On it you will have to design some simulation studies using conditional loops and structures.

L6: fungsi dan join

Kembali ke R base: fungsi dan join

Own functions

Kita tidak hanya dapat menggunakan fungsi bawaan yang sudah dimuat dalam paket, kita juga dapat membuat fungsi sendiri untuk mengotomatisasi tugas. Bagaimana cara membuat fungsi kita sendiri? Mari lihat skema dasarnya:

  • Nama: misalnya name_fun (tanpa spasi atau karakter aneh). Pada nama kita menetapkan kata khusus function().

  • Definisikan argumen input (di dalam function()).

  • Isi/tubuh fungsi di dalam { }.

  • Kita mengakhiri fungsi dengan argumen output menggunakan return().

name_fun <- function() {
  
}

Own functions

Kita tidak hanya dapat menggunakan fungsi bawaan yang sudah dimuat dalam paket, kita juga dapat membuat fungsi sendiri untuk mengotomatisasi tugas. Bagaimana cara membuat fungsi kita sendiri? Mari lihat skema dasarnya:

  • Nama: misalnya name_fun (tanpa spasi atau karakter aneh). Pada nama kita menetapkan kata khusus function().

  • Definisikan argumen input (di dalam function()).

  • Isi/tubuh fungsi di dalam { }.

  • Kita mengakhiri fungsi dengan argumen output menggunakan return().

name_fun <- function(arg1, arg2, ...) {
  
}

Own functions

Kita tidak hanya dapat menggunakan fungsi bawaan yang sudah dimuat dalam paket, kita juga dapat membuat fungsi sendiri untuk mengotomatisasi tugas. Bagaimana cara membuat fungsi kita sendiri? Mari lihat skema dasarnya:

  • Nama: misalnya name_fun (tanpa spasi atau karakter aneh). Pada nama kita menetapkan kata khusus function().

  • Definisikan argumen input (di dalam function()).

  • Isi/tubuh fungsi di dalam { }.

  • Kita mengakhiri fungsi dengan argumen output menggunakan return().

name_fun <- function(arg1, arg2, ...) {
  
  code to be executed
  
}

Own functions

Kita tidak hanya dapat menggunakan fungsi bawaan yang sudah dimuat dalam paket, kita juga dapat membuat fungsi sendiri untuk mengotomatisasi tugas. Bagaimana cara membuat fungsi kita sendiri? Mari lihat skema dasarnya:

  • Nama: misalnya name_fun (tanpa spasi atau karakter aneh). Pada nama kita menetapkan kata khusus function().

  • Definisikan argumen input (di dalam function()).

  • Isi/tubuh fungsi di dalam { }.

  • Kita mengakhiri fungsi dengan argumen output menggunakan return().

name_fun <- function(arg1, arg2, ...) {
  
  code to be executed
  
  return(var_output)
  
}

Fungsi Buatan Sendiri

  • arg1, arg2, ...: adalah argumen input, argumen yang diterima fungsi untuk mengeksekusi kode di dalamnya.

  • code: baris kode yang ingin kita jalankan oleh fungsi.

  • return(var_output): argumen output akan dimasukkan.

name_fun <- function(arg1, arg2, ...) {
  
  # Code to be executed
  code
  
  # Output
  return(var_output)
  
}

Penting

Semua variabel yang kita definisikan di dalam fungsi adalah variabel LOKAL: hanya ada di dalam fungsi kecuali kita tentukan sebaliknya.

Own functions

Mari lihat contoh sangat sederhana dari fungsi untuk menghitung luas persegi panjang.

Karena luas persegi panjang dihitung sebagai perkalian sisi-sisinya, kita hanya memerlukan sisi-sisinya: itulah argumen input dan nilai yang dikembalikan adalah luasnya (\(side_1 * side_2\)).

# We define the name of function and input arguments
compute_area <- function(side_1, side_2) {
  
}

Own functions

Mari lihat contoh sangat sederhana dari fungsi untuk menghitung luas persegi panjang.

Karena luas persegi panjang dihitung sebagai perkalian sisi-sisinya, kita hanya memerlukan sisi-sisinya: itulah argumen input dan nilai yang dikembalikan adalah luasnya (\(side_1 * side_2\)).

# We define the name of function and input arguments
compute_area <- function(side_1, side_2) {
  
  area <- side_1 * side_2
  
}

Own functions

Mari lihat contoh sangat sederhana dari fungsi untuk menghitung luas persegi panjang.

Karena luas persegi panjang dihitung sebagai perkalian sisi-sisinya, kita hanya memerlukan sisi-sisinya: itulah argumen input dan nilai yang dikembalikan adalah luasnya (\(side_1 * side_2\)).

# We define the name of function and input arguments
compute_area <- function(side_1, side_2) {
  
  area <- side_1 * side_2
  return(area)
  
}

Fungsi Buatan Sendiri

Kita juga dapat membuat definisi variabel secara langsung tanpa menyimpan di tengah jalan.

# We define the name of function and input arguments
compute_area <- function(side_1, side_2) {
  
  return(side_1 * side_2)
  
}

How to apply our function?

compute_area(5, 3) # area of 5 x 3 rectangle
[1] 15
compute_area(1, 5) # area of 1 x 5 rectangle
[1] 5

Fungsi Buatan Sendiri

Tip

Meskipun tidak wajib, disarankan membuat pemanggilan argumen secara eksplisit, menentukan nilai untuk setiap argumen agar tidak bergantung pada urutannya, membuat kode lebih mudah dibaca.

compute_area(side_1 = 5, side_2 = 3) # area of 5 x 3 rectangle
[1] 15
compute_area(side_2 = 3, side_1 = 5) # area of 5 x 3 rectangle
[1] 15

Argumen Default

Bayangkan kita menyadari bahwa 90% waktu kita menggunakan fungsi tersebut untuk menghitung luas persegi secara default (yaitu, hanya butuh satu sisi). Untuk itu, kita dapat mendefinisikan argumen default dalam fungsi: argumen akan mengambil nilai tersebut kecuali kita tetapkan nilai lain.

Mengapa tidak menetapkan side_2 = side_1 secara default, untuk menghemat baris kode dan waktu?

compute_area <- function(side_1, side_2 = side_1) {
  
  # Code to be executed
  area <- side_1 * side_2
  
  # Output
  return(area)
  
}

Argumen Default

compute_area <- function(side_1, side_2 = side_1) {
  
  # Code to be executed
  area <- side_1 * side_2
  
  # Output
  return(area)
  
}

Sekarang secara default sisi kedua akan sama dengan sisi pertama (jika ditambahkan akan menggunakan keduanya).

compute_area(side_1 = 5) # square
[1] 25
compute_area(side_1 = 5, side_2 = 7) # rectangle
[1] 35

Keluaran Ganda

Mari perumit fungsi sedikit dan tambahkan dalam output nilai setiap sisi, berlabel side_1 dan side_2, mengemas output dalam sebuah vektor.

compute_area <- function(side_1, side_2 = side_1) {
  
  # Code
  area <- side_1 * side_2
  
  # Output
  return(c("area" = area, "side_1" = side_1, "side_2" = side_2))
  
}

Keluaran Ganda

Kita dapat memperumit output sedikit lagi dengan menambahkan variabel keempat yang memberi tahu kita, bergantung pada argumen, apakah persegi panjang atau persegi, dengan menambahkan variabel karakter (atau logika) dalam output.

compute_area <- function(side_1, side_2 = side_1) {
  
  # Code
  area <- side_1 * side_2
  
  # Output
  return(c("area" = area, "side_1" = side_1, "side_2" = side_2,
           "type" = if_else(side_1 == side_2, "square", "rectangle")))
  
}
compute_area(5, 3)
       area      side_1      side_2        type 
       "15"         "5"         "3" "rectangle" 

Masalah: saat mencoba menggabungkan angka dan teks, semuanya dikonversi menjadi angka. Kita bisa menyimpan semuanya dalam tibble() atau dalam objek yang dikenal di R sebagai list (akan kita lihat nanti).

Urutan Argumen

Sebelumnya kita tidak peduli dengan urutan argumen, tetapi sekarang urutan argumen input penting, karena kita menyertakan side_1 dan side_2 dalam output.

Tips

Seperti yang disebutkan, sangat disarankan membuat pemanggilan fungsi dengan menetapkan argumen secara eksplisit untuk meningkatkan keterbacaan dan interpretabilitas.

# Equivalent to compute_area(5, 3)
compute_area(side_1 = 5, side_2 = 3)
       area      side_1      side_2        type 
       "15"         "5"         "3" "rectangle" 

Menghasilkan Pengetahuan

Tampaknya sepele apa yang kita lakukan tetapi kita telah melewati batas penting: beralih dari mengonsumsi pengetahuan (kode dari paket orang lain), ke menghasilkan pengetahuan dengan membuat fungsi kita sendiri.

Fungsi akan menjadi kunci dalam pekerjaan sehari-hari karena memungkinkan kamu mengotomatisasi kode yang akan diulang berkali-kali: dengan mengemas kode tersebut di bawah alias (nama fungsi) kamu akan dapat menggunakannya berulang kali tanpa harus memrogramnya lagi

Variabel Lokal vs Global

Aspek penting tentang fungsi: apa yang terjadi jika kita menamai variabel di dalam fungsi yang lupa kita tetapkan nilainya di dalam fungsi.

Kita harus berhati-hati saat menggunakan fungsi di R, karena berdasarkan “aturan leksikografi”, jika variabel tidak didefinisikan di dalam fungsi, R akan mencari variabel tersebut di lingkungan variabel.

x <- 1
fun_example <- function() {
    
  print(x) # No output, just doing an action
}
fun_example()
[1] 1

Variabel Lokal vs Global

Jika variabel sudah didefinisikan di luar fungsi (lingkungan global), dan juga digunakan di dalam untuk mengubah nilainya, nilai tersebut hanya berubah di dalam tetapi tidak di lingkungan global.

x <- 1
fun_example <- function() {
    
  x <- 2
  print(x) # value inside of function
}
# value inside of function (local)
fun_example()
[1] 2
# value output of function (global)
print(x)
[1] 1

Variabel Lokal vs Global

Jika kita ingin itu berubah secara lokal maupun global kita harus menggunakan penugasan ganda (<<-).

x <- 1
y <- 2
fun_example <- function() {
  
  # no change in a global way, just locally
  x <- 3 
  # change in a global way
  y <<- 0 #<<
  
  print(x)
  print(y)
}

fun_example() # value inside function (local)
[1] 3
[1] 0
x # global value
[1] 1
y # global value
[1] 0

💻 Giliranmu

Coba kerjakan latihan-latihan berikut tanpa melihat solusinya

📝 Modifikasi kode di bawah untuk mendefinisikan fungsi bernama sum_function, yang diberikan dua elemen mengembalikan jumlahnya.

name <- function(x, y) {
  sum_output <- # code
  return()
}
# we apply the function
sum_function(3, 7)
Code
sum_function<- function(x, y) {
  sum_output <- x + y
  return(sum_output)
}
sum_function(3, 7)

📝 Modifikasi kode di bawah untuk mendefinisikan fungsi product_function, yang diberikan dua elemen mengembalikan perkaliannya, tetapi secara default menghitung kuadrat.

name <- function(x, y) {
  prod_output <- # code
  return()
}
product_function(3)
product_function(3, -7)
Code
product_function <- function(x, y = x) {
  
  prod_output <- x * y
  return(prod_output)
  
}
product_function(3)
product_function(3, -7)

📝 Definisikan fungsi equal_names yang, diberikan dua nama, memberi tahu apakah sama atau tidak. Lakukan ini dengan mempertimbangkan case-sensitive dan case-insensitive menggunakan paket stringr.

Code
# Case-sensitive
equal_names <- function(person_1, person_2) {
  
  return(person_1 == person_2)
  
}
equal_names("Javi", "javi")
equal_names("Javi", "Lucía")

# Case-insensitive
library(stringr)
equal_names <- function(person_1, person_2) {
  
  return(str_equal(person_1, person_2, ignore_case = TRUE))
  
  # other option
  # return(str_to_lower(person_1) == str_to_lower(person_2))
  
  # other option
  # return(str_to_upper(person_1) == str_to_upper(person_2))
  
}
equal_names("Javi", "javi")
equal_names("Javi", "Lucía")

📝 Buat fungsi compute_BMI yang, diberikan berat, tinggi (meter), dan nama, mengembalikan list dengan BMI (\(weight/(height^2)\)) dan nama.

Code
compute_BMI <- function(name, weight, height) {
  
  return(list("name" = name, "BMI" = weight/(height^2)))
  
}

📝 Ulangi latihan sebelumnya dengan argumen opsional tambahan units (default units = "meters"). Kembangkan fungsi agar benar untuk units = "meters" dan units = "centimeters".

Code
compute_BMI <- function(name, weight, height, units = "meters") {
  
  if (units == "meters") {
    
    return(list("name" = name, "BMI" = weight / (height^2)))
  } else if (units == "centimeters") {
    
    return(list("name" = name, "BMI" = weight / ((height/100)^2)))
  }
}

📝 Buat tibble fiktif 7 orang, dengan tiga variabel (nama karangan, berat dan tinggi simulasi dalam cm), dan terapkan fungsi agar mendapatkan kolom keempat berisi BMI.

Code
data <-
  tibble("name" = c("javi", "sandra", "laura",
                       "ana", "carlos", "leo", NA),
         "weight" = rnorm(n = 7, mean = 70, sd = 1),
         "height" = rnorm(n = 7, mean = 168, sd = 5))

data |> 
  mutate(BMI = compute_BMI(name, weight, height, units = "centimeters")$BMI)

📝 Buat fungsi shortcut dengan dua argumen numerik x dan y. Jika keduanya sama, kembalikan equal dan fungsi berhenti. PERINGATAN: x dan y bisa berupa vektor. Jika berbeda (panjang sama) hitung proporsi elemen yang berbeda. Jika berbeda (panjang berbeda), kembalikan elemen yang tidak sama.

Code
shortcut <- function(x, y) {
  
  if (all(x == y) & length(x) == length(y)) { return("equal") }
  else {
   
    if (length(x) == length(y)) {
      
      n_diff <- sum(x != y) / length(x)
      return(n_diff)
      
    } else {
      
      diff_elem <- unique(c(setdiff(x, y), setdiff(y, x)))
      return(diff_elem)
    }
    
  }
}

🐣 Studi Kasus I: Konverter Suhu

Untuk berlatih dengan fungsi kita akan membuat konverter suhu lengkap yang, diberikan suhu dalam Fahrenheit, Celsius, atau Kelvin, mengonversinya ke salah satu yang lain.

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

Penggabungan Tabel (Joins)

Saat bekerja dengan data kita tidak selalu memiliki informasi dalam satu tabel, dan terkadang kita tertarik untuk mereferensikan silang informasi dari sumber yang berbeda.

Untuk itu kita akan menggunakan klasik dari setiap bahasa yang menangani data: join yang terkenal, alat yang memungkinkan kita menggabungkan satu atau beberapa tabel, menggunakan kolom identifikasi dari masing-masing tabel.

table_1 |>
  xxx_join(table_2, by = id)

Penggabungan Tabel (Joins)

  • inner_join(): hanya catatan dengan id di kedua tabel yang bertahan.

  • full_join(): menyimpan semua catatan di kedua tabel.

  • left_join(): menyimpan semua catatan dari tabel pertama, dan mencari yang juga memiliki id di tabel kedua (jika tidak ada, diisi dengan NA pada field tabel ke-2).

  • right_join(): menyimpan semua catatan di tabel kedua, dan mencari yang juga memiliki id di tabel pertama.

Penggabungan Tabel (Joins)

Mari uji berbagai join dengan contoh sederhana

tb_1 <- tibble("key" = 1:3, "val_x" = c("x1", "x2", "x3"))
tb_2 <- tibble("key" = c(1, 2, 4), "val_y" = c("y1", "y2", "y3"))
tb_1
# A tibble: 3 × 2
    key val_x
  <int> <chr>
1     1 x1   
2     2 x2   
3     3 x3   
tb_2
# A tibble: 3 × 2
    key val_y
  <dbl> <chr>
1     1 y1   
2     2 y2   
3     4 y3   

left_join()

Bayangkan kita ingin memasukkan ke tb_1 informasi dari tabel_2, mengidentifikasi catatan berdasarkan kolom kunci (by = "key"): kita ingin menyimpan semua catatan tabel pertama dan mencari yang memiliki nilai sama dalam key juga di tabel kedua.

tb_1 |> 
  left_join(tb_2, by = "key")
# A tibble: 3 × 3
    key val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     3 x3    <NA> 

left_join()

tb_1 |>
  left_join(tb_2, by = "key")
# A tibble: 3 × 3
    key val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     3 x3    <NA> 

Perhatikan bahwa catatan di tabel pertama yang kuncinya tidak ditemukan di tabel kedua diberi nilai hilang (NA).

right_join()

Operasi right_join() adalah kebalikannya: kita sekarang akan memasukkan ke tb_2 informasi dari tabel lain, mengidentifikasi catatan berdasarkan kolom key: kita ingin menyimpan semua catatan tabel kedua dan mencari yang memiliki nilai sama dalam key juga di tabel pertama.

tb_1 |> 
  right_join(tb_2, by = "key")
# A tibble: 3 × 3
    key val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     4 <NA>  y3   

right_join()

tb_1 |>
  right_join(tb_2, by = "key")
# A tibble: 3 × 3
    key val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     4 <NA>  y3   

Perhatikan bahwa sekarang catatan di tabel kedua yang kuncinya tidak ditemukan di tabel pertama yang diberi nilai hilang (NA).

Kunci dan Sufiks

Kolom kunci yang akan kita gunakan untuk penggabungan tidak selalu diberi nama yang sama.

tb_1 <- tibble("key_1" = 1:3, "val_x" = c("x1", "x2", "x3"))
tb_2 <- tibble("key_2" = c(1, 2, 4), "val_y" = c("y1", "y2", "y3"))
  • by = c("key_2" = "key_2"): kita menunjukkan di kolom mana dari setiap tabel terdapat kunci yang akan digabungkan.
# Left
tb_1  |> 
  left_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 3 × 3
  key_1 val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     3 x3    <NA> 
# Right
tb_1 |> 
  right_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 3 × 3
  key_1 val_x val_y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     4 <NA>  y3   

Kunci dan Sufiks

Kita juga dapat menggabungkan beberapa kolom sekaligus (akan menginterpretasikan catatan yang sama sebagai yang memiliki set kunci yang sama), dengan by = c("var1_t1" = "var1_t2", "var2_t1" = "var2_t2", ...).

tb_1 <- tibble("k_11" = 1:3, "k_12" = c("a", "b", "c"),  "val_x" = c("x1", "x2", "x3"))
tb_2 <- tibble("k_21" = c(1, 2, 4), "k_22" = c("a", "b", "e"), "val_y" = c("y1", "y2", "y3"))
# Left
tb_1 |> 
  left_join(tb_2,
            by = c("k_11" = "k_21", "k_12" = "k_22"))
# A tibble: 3 × 4
   k_11 k_12  val_x val_y
  <dbl> <chr> <chr> <chr>
1     1 a     x1    y1   
2     2 b     x2    y2   
3     3 c     x3    <NA> 
# Right
tb_1 |> 
  right_join(tb_2,
             by = c("k_11" = "k_21", "k_12" = "k_22"))
# A tibble: 3 × 4
   k_11 k_12  val_x val_y
  <dbl> <chr> <chr> <chr>
1     1 a     x1    y1   
2     2 b     x2    y2   
3     4 e     <NA>  y3   

Kunci dan Sufiks

Bisa juga terjadi bahwa saat menggabungkan dua tabel, terdapat kolom nilai yang diberi nama sama

tb_1 <- tibble("key_1" = 1:3, "val" = c("x1", "x2", "x3"))
tb_2 <- tibble("key_2" = c(1, 2, 4), "val" = c("y1", "y2", "y3"))
# Left
tb_1 |>
  left_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 3 × 3
  key_1 val.x val.y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     3 x3    <NA> 

Perhatikan bahwa secara default ditambahkan sufiks .x dan .y untuk memberi tahu kita dari tabel mana mereka berasal.

Kunci dan Sufiks

Sufiks ini dapat ditentukan dalam argumen opsional suffix = ..., yang memungkinkan kita membedakan variabel dari satu tabel dengan tabel lainnya.

# Left
tb_1 |>
  left_join(tb_2, by = c("key_1" = "key_2"),
            suffix = c("_table1", "_table2"))
# A tibble: 3 × 3
  key_1 val_table1 val_table2
  <dbl> <chr>      <chr>     
1     1 x1         y1        
2     2 x2         y2        
3     3 x3         <NA>      

full_join()

Dua kasus sebelumnya membentuk yang dikenal sebagai outer join: penggabungan di mana pengamatan yang muncul di setidaknya satu tabel disimpan. Outer join ketiga adalah full_join() yang akan menyimpan pengamatan dari kedua tabel, menambahkan baris yang tidak cocok dengan tabel lain.

tb_1  |> 
  full_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 4 × 3
  key_1 val.x val.y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
3     3 x3    <NA> 
4     4 <NA>  y3   

inner_join()

Berlawanan dengan outer join adalah yang dikenal sebagai inner join, dengan inner_join(): penggabungan di mana hanya pengamatan yang muncul di kedua tabel yang disimpan.

tb_1 |> 
  inner_join(tb_2,  by = c("key_1" = "key_2"))
# A tibble: 2 × 3
  key_1 val.x val.y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   

inner_join()

Perhatikan bahwa dalam hal catatan, inner_join bersifat komutatif, kita tidak peduli dengan urutan tabel: satu-satunya yang berubah adalah urutan kolom yang ditambahkan.

tb_1 |> 
  inner_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 2 × 3
  key_1 val.x val.y
  <dbl> <chr> <chr>
1     1 x1    y1   
2     2 x2    y2   
tb_2 |> inner_join(tb_1, by = c("key_2" = "key_1"))
# A tibble: 2 × 3
  key_2 val.x val.y
  <dbl> <chr> <chr>
1     1 y1    x1   
2     2 y2    x2   

semi/anti_join()

Terakhir kita memiliki dua alat menarik untuk memfilter (bukan menggabungkan) catatan: semi_join() dan anti_join(). Semi join menyisakan di tabel pertama catatan yang kuncinya juga ada di tabel kedua (seperti inner join tanpa menambahkan info dari tabel kedua). Anti join melakukan sebaliknya.

# semijoin
tb_1 |> 
  semi_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 2 × 2
  key_1 val  
  <int> <chr>
1     1 x1   
2     2 x2   
# antijoin
tb_1 |> 
  anti_join(tb_2, by = c("key_1" = "key_2"))
# A tibble: 1 × 2
  key_1 val  
  <int> <chr>
1     3 x3   

💻 Giliranmu

Untuk latihan kita akan menggunakan tabel dari paket nycflights13.

library(nycflights13)
  • airlines: nama maskapai (dengan singkatannya).
  • airports: data bandara (nama, bujur, lintang, ketinggian, dll).
  • flights, planes: data penerbangan dan pesawat.
  • weather: data cuaca per jam.

💻 It’s your turn

📝 Dari paket nycflights13 gabungkan data maskapai dari airlines ke tabel flights. Pertahankan semua catatan penerbangan.

Code
flights_airlines <-
  flights |> 
  left_join(airlines, by = "carrier")
flights_airlines

📝 Ke tabel dari bagian sebelumnya, tambahkan data pesawat dari planes, hanya untuk penerbangan yang kita miliki informasi pesawatnya.

Code
flights_airlines_planes <- 
  flights_airlines |> 
  inner_join(planes, by = "tailnum")
flights_airlines_planes

📝 Ulangi latihan sebelumnya tetapi simpan kedua variabel year (tahun penerbangan dan tahun pembuatan pesawat), dan bedakan keduanya.

Code
flights_airlines_planes <- 
  flights_airlines |>
  inner_join(planes, by = "tailnum",
             suffix = c("_flight", "_build_aircraft"))
flights_airlines_planes

📝 Tambahkan bujur dan lintang bandara dari airports, bedakan antara bandara tujuan dan asal.

Code
flights_airlines_planes |> 
  left_join(airports |> select(faa, lat, lon),
            by = c("origin" = "faa")) |> 
  rename(lat_origin = lat, lon_origin = lon) |> 
  left_join(airports |> select(faa, lat, lon),
            by = c("dest" = "faa")) |> 
  rename(lat_dest = lat, lon_dest = lon)

📝 Filter dari airports hanya bandara tempat penerbangan berangkat. Ulangi untuk bandara tujuan.

Code
airports |> 
  semi_join(flights, by = c("faa" = "origin"))
airports |> 
  semi_join(flights, by = c("faa" = "dest"))

📝 Berapa banyak penerbangan yang tidak kita miliki informasi pesawatnya? Hapus penerbangan tanpa ID pesawat (selain NA) terlebih dahulu.

Code
flights |>
  drop_na(tailnum) |>
  anti_join(planes, by = "tailnum") |>
  count(tailnum, sort = TRUE) 

🐣 Studi Kasus II: Beatles

Kita akan berlatih join sederhana menggunakan dataset band_members dan band_instruments yang sudah ada dalam paket dplyr.

library(dplyr)
band_members
# A tibble: 3 × 2
  name  band   
  <chr> <chr>  
1 Mick  Stones 
2 John  Beatles
3 Paul  Beatles
band_instruments
# A tibble: 3 × 2
  name  plays 
  <chr> <chr> 
1 John  guitar
2 Paul  bass  
3 Keith guitar

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

🐣 Studi Kasus III: Pendapatan per Kotamadya

Dalam file municipios.csv kita menyimpan informasi tentang kotamadya Spanyol per tahun 2019.

# 2019 data
mun_data <- read_csv(file = "./data/municipios.csv")
Rows: 8212 Columns: 8
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (8): codauto, ine.ccaa.name, cpro, ine.prov.name, cmun, name, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
mun_data
# A tibble: 8,212 × 8
   codauto ine.ccaa.name cpro  ine.prov.name cmun  name       LAU_CODE
   <chr>   <chr>         <chr> <chr>         <chr> <chr>      <chr>   
 1 01      Andalucía     04    Almería       001   Abla       04001   
 2 01      Andalucía     04    Almería       002   Abrucena   04002   
 3 01      Andalucía     04    Almería       003   Adra       04003   
 4 01      Andalucía     04    Almería       004   Albanchez  04004   
 5 01      Andalucía     04    Almería       005   Alboloduy  04005   
 6 01      Andalucía     04    Almería       006   Albox      04006   
 7 01      Andalucía     04    Almería       007   Alcolea    04007   
 8 01      Andalucía     04    Almería       008   Alcóntar   04008   
 9 01      Andalucía     04    Almería       009   Alcudia d… 04009   
10 01      Andalucía     04    Almería       010   Alhabia    04010   
# ℹ 8,202 more rows
# ℹ 1 more variable: codigo_ine <chr>

🐣 Case study III: income by municipalities

Di sisi lain, dalam file renta_mun kita memiliki pendapatan per kapita rata-rata setiap unit administratif (kotamadya, distrik, provinsi, komunitas otonom,…) untuk berbagai tahun.

renta_mun <- read_csv(file = "./data/renta_mun.csv")
Warning: One or more parsing issues, call `problems()` on your data frame for
details, e.g.:
  dat <- vroom(...)
  problems(dat)
Rows: 55273 Columns: 7
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (2): Unidad, codigo_ine
dbl (5): 2019, 2018, 2017, 2016, 2015

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
renta_mun
# A tibble: 55,273 × 7
   Unidad                `2019` `2018` `2017` `2016` `2015` codigo_ine
   <chr>                  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>     
 1 44001 Ababuj              NA     NA     NA     NA     NA 44001     
 2 4400101 Ababuj distr…     NA     NA     NA     NA     NA 4400101   
 3 4400101001 Ababuj se…     NA     NA     NA     NA     NA 4400101001
 4 40001 Abades           11429  10731  10314   9816   9904 40001     
 5 4000101 Abades distr…  11429  10731  10314   9816   9904 4000101   
 6 4000101001 Abades se…  11429  10731  10314   9816   9904 4000101001
 7 10001 Abadía            8954   8589   8207   7671   8416 10001     
 8 1000101 Abadía distr…   8954   8589   8207   7671   8416 1000101   
 9 1000101001 Abadía se…   8954   8589   8207   7671   8416 1000101001
10 27001 Abadín           10791  10258   9762   9478   9116 27001     
# ℹ 55,263 more rows

🐣 Case study III: income by municipalities

Sebelum memulai mari kita normalisasi nama variabel menggunakan clean_names() dari paket janitor.

mun_data <-
  mun_data |> 
  janitor::clean_names()
renta_mun <-
  renta_mun |> 
  janitor::clean_names()

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

L7: impor/ekspor

Impor dan ekspor data

Impor/Ekspor

Sejauh ini kita hanya menggunakan data yang sudah dimuat dalam paket tetapi sering kali kita perlu mengimpor data dari luar. Salah satu kekuatan utama R adalah kita dapat mengimpor data dengan sangat mudah dalam berbagai format:

  • R native formats: .rda, .RData and .rds formats.

  • Rectangular (tabular) data: .csv and .tsv formats

  • Untabulated data: .txt format.

  • Data in excel: .xls and .xlsx formats

  • Data from SAS/Stata/SPSS: .sas7bdat, .sav and .dat formats

  • Data from Google Drive

  • Data from API’s: aemet, catastro, twitter, spotify, etc.

Format Asli R

File paling sederhana untuk diimpor ke R (dan biasanya membutuhkan lebih sedikit ruang disk) adalah ekstensi aslinya: file dalam format .RData, .rda, dan .rds. Untuk memuat yang pertama cukup gunakan fungsi native load() dengan memberikan path file.

  • File RData: kita akan mengimpor file world_bank_pop.RData, yang menyertakan dataset world_bank_pop
load("./data/world_bank_pop.RData")
world_bank_pop
# A tibble: 1,064 × 20
   country indicator    `2000`  `2001`  `2002`  `2003`  `2004`  `2005`
   <chr>   <chr>         <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
 1 ABW     SP.URB.TOTL  4.16e4 4.20e+4 4.22e+4 4.23e+4 4.23e+4 4.24e+4
 2 ABW     SP.URB.GROW  1.66e0 9.56e-1 4.01e-1 1.97e-1 9.46e-2 1.94e-1
 3 ABW     SP.POP.TOTL  8.91e4 9.07e+4 9.18e+4 9.27e+4 9.35e+4 9.45e+4
 4 ABW     SP.POP.GROW  2.54e0 1.77e+0 1.19e+0 9.97e-1 9.01e-1 1.00e+0
 5 AFE     SP.URB.TOTL  1.16e8 1.20e+8 1.24e+8 1.29e+8 1.34e+8 1.39e+8
 6 AFE     SP.URB.GROW  3.60e0 3.66e+0 3.72e+0 3.71e+0 3.74e+0 3.81e+0
 7 AFE     SP.POP.TOTL  4.02e8 4.12e+8 4.23e+8 4.34e+8 4.45e+8 4.57e+8
 8 AFE     SP.POP.GROW  2.58e0 2.59e+0 2.61e+0 2.62e+0 2.64e+0 2.67e+0
 9 AFG     SP.URB.TOTL  4.31e6 4.36e+6 4.67e+6 5.06e+6 5.30e+6 5.54e+6
10 AFG     SP.URB.GROW  1.86e0 1.15e+0 6.86e+0 7.95e+0 4.59e+0 4.47e+0
# ℹ 1,054 more rows
# ℹ 12 more variables: `2006` <dbl>, `2007` <dbl>, `2008` <dbl>,
#   `2009` <dbl>, `2010` <dbl>, `2011` <dbl>, `2012` <dbl>,
#   `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>,
#   `2017` <dbl>

Format Asli R

  • File .rda: kita akan mengimpor dataset airquality dari airquality.rda
load("./data/airquality.rda")
airquality |> as_tibble()
# A tibble: 153 × 6
   Ozone Solar.R  Wind  Temp Month   Day
   <int>   <int> <dbl> <int> <int> <int>
 1    41     190   7.4    67     5     1
 2    36     118   8      72     5     2
 3    12     149  12.6    74     5     3
 4    18     313  11.5    62     5     4
 5    NA      NA  14.3    56     5     5
 6    28      NA  14.9    66     5     6
 7    23     299   8.6    65     5     7
 8    19      99  13.8    59     5     8
 9     8      19  20.1    61     5     9
10    NA     194   8.6    69     5    10
# ℹ 143 more rows

Format Asli R

Perhatikan bahwa file yang dimuat dengan load() secara otomatis dimuat ke dalam lingkungan (dengan nama yang aslinya disimpan), dan bukan hanya dataset yang dapat dimuat: load() memungkinkan kita memuat beberapa objek (bukan hanya data tabular)

File .rda dan .RData native adalah cara yang tepat untuk menyimpan lingkungan kerjamu.

load(file = "./data/multiple_objects.rda")

Format Asli R

  • File .rds: untuk tipe ini kita harus menggunakan readRDS(), dan perlu menyertakan argumen file dengan path. Dalam kasus ini kita akan mengimpor data kanker paru dari North Central Cancer Treatment Group. Perhatikan bahwa file impor .rds adalah satu database
lung_cancer <-
  readRDS(file = "./data/NCCTG_lung_cancer.rds") |>
  as_tibble()
lung_cancer
# A tibble: 228 × 10
    inst  time status   age   sex ph.ecog ph.karno pat.karno meal.cal
   <dbl> <dbl>  <dbl> <dbl> <dbl>   <dbl>    <dbl>     <dbl>    <dbl>
 1     3   306      2    74     1       1       90       100     1175
 2     3   455      2    68     1       0       90        90     1225
 3     3  1010      1    56     1       0       90        90       NA
 4     5   210      2    57     1       1       90        60     1150
 5     1   883      2    60     1       0      100        90       NA
 6    12  1022      1    74     1       1       50        80      513
 7     7   310      2    68     2       2       70        60      384
 8    11   361      2    71     2       2       60        80      538
 9     1   218      2    53     1       1       70        80      825
10     7   166      2    61     1       2       70        70      271
# ℹ 218 more rows
# ℹ 1 more variable: wt.loss <dbl>

Penting

The paths must always be without spaces, ñ, or accents.

Data Tabular: readr

Paket readr dalam lingkungan tidyverse berisi beberapa fungsi berguna untuk memuat data persegi panjang (tanpa pemformatan).

  • read_csv(): .csv files whose separator is comma
  • read_csv2(): semicolon
  • read_tsv(): tabulator.
  • read_table(): space.
  • read_delim(): generic function for character delimited files.

Semuanya membutuhkan argumen path file ditambah argumen opsional (lewati header atau tidak, desimal, dll). Lihat lebih lanjut di https://readr.tidyverse.org/

Data Tabular (.csv, .tsv)

Keunggulan utama readr adalah mengotomatisasi pemformatan untuk beralih dari file datar (tidak terformat) ke tibble (dalam baris dan kolom, dengan pemformatan).

  • File .csv: dengan read_csv() kita akan memuat file dipisahkan koma, memberikan argumen path di file = .... Mari impor dataset chickens.csv. Output-nya memberi kita tipe variabel.
library(readr)
chickens <- read_csv(file = "./data/chickens.csv")
Rows: 5 Columns: 4
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (3): chicken, sex, motto
dbl (1): eggs_laid

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
chickens
# A tibble: 5 × 4
  chicken                 sex     eggs_laid motto                     
  <chr>                   <chr>       <dbl> <chr>                     
1 Foghorn Leghorn         rooster         0 That's a joke, ah say, th…
2 Chicken Little          hen             3 The sky is falling!       
3 Ginger                  hen            12 Listen. We'll either die …
4 Camilla the Chicken     hen             7 Bawk, buck, ba-gawk.      
5 Ernie The Giant Chicken rooster         0 Put Captain Solo in the c…

Data Tabular (.csv, .tsv)

Format variabel biasanya dilakukan secara otomatis oleh read_csv(), dan kita dapat memeriksanya dengan spec().

spec(chickens)
cols(
  chicken = col_character(),
  sex = col_character(),
  eggs_laid = col_double(),
  motto = col_character()
)

Data Tabular (.csv, .tsv)

Meskipun biasanya dilakukan dengan baik secara otomatis, kita dapat menentukan format secara eksplisit dalam col_types = list() (dalam format list, dengan col_xxx() untuk setiap tipe variabel).

chickens <-
  read_csv(file = "./data/chickens.csv",
           col_types = list(col_character(), col_character(),
                            col_character(), col_character()))
chickens
# A tibble: 5 × 4
  chicken                 sex     eggs_laid motto                     
  <chr>                   <chr>   <chr>     <chr>                     
1 Foghorn Leghorn         rooster 0         That's a joke, ah say, th…
2 Chicken Little          hen     3         The sky is falling!       
3 Ginger                  hen     12        Listen. We'll either die …
4 Camilla the Chicken     hen     7         Bawk, buck, ba-gawk.      
5 Ernie The Giant Chicken rooster 0         Put Captain Solo in the c…

Data Tabular (.csv, .tsv)

Kita bahkan dapat menunjukkan variabel yang ingin dipilih (tanpa menghabiskan memori), dengan menunjukkannya dalam col_select = ....

chickens <-
  read_csv(file = "./data/chickens.csv",
           col_select = c(chicken, sex, eggs_laid))
Rows: 5 Columns: 3
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (2): chicken, sex
dbl (1): eggs_laid

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
chickens
# A tibble: 5 × 3
  chicken                 sex     eggs_laid
  <chr>                   <chr>       <dbl>
1 Foghorn Leghorn         rooster         0
2 Chicken Little          hen             3
3 Ginger                  hen            12
4 Camilla the Chicken     hen             7
5 Ernie The Giant Chicken rooster         0

Data Tidak Terstruktur (.txt)

Apa yang terjadi ketika pemisah tidak benar?

Jika menggunakan read_csv() diharapkan pemisah antar kolom adalah koma, tetapi seperti yang terlihat dengan .txt berikut, semuanya diinterpretasikan sebagai satu kolom: tidak ada koma dan tidak tahu di mana harus memisahkan

datos_txt <- read_csv(file = "./data/massey-rating.txt")
Rows: 10 Columns: 1
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr (1): UCC PAY LAZ KPK  RT   COF BIH DII ENG ACU Rank Team      ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
dim(datos_txt)
[1] 10  1
as_tibble(datos_txt)
# A tibble: 10 × 1
   UCC PAY LAZ KPK  RT   COF BIH DII ENG ACU Rank Team            Co…¹
   <chr>                                                              
 1 1   1   1   1   1     1   1   1   1   1    1 Ohio St          B10  
 2 2   2   2   2   2     2   2   2   4   2    2 Oregon           P12  
 3 3   4   3   4   3     4   3   4   2   3    3 Alabama          SEC  
 4 4   3   4   3   4     3   5   3   3   4    4 TCU              B12  
 5 6   6   6   5   5     7   6   5   6  11    5 Michigan St      B10  
 6 7   7   7   6   7     6  11   8   7   8    6 Georgia          SEC  
 7 5   5   5   7   6     8   4   6   5   5    7 Florida St       ACC  
 8 8   8   9   9  10     5   7   7  10   7    8 Baylor           B12  
 9 9  11   8  13  11    11  12   9  14   9    9 Georgia Tech     ACC  
10 13  10  13  11   8     9  10  11   9  10   10 Mississippi      SEC 
# ℹ abbreviated name:
#   ¹​`UCC PAY LAZ KPK  RT   COF BIH DII ENG ACU Rank Team            Conf`

Data Tidak Terstruktur (.txt)

Untuk itu kita memiliki:

  • read_csv2() ketika pemisah adalah titik koma, read_tsv() ketika tabulasi, dan read_table() ketika spasi.

  • read_delim() in general.

datos_txt <- read_table(file = "./data/massey-rating.txt")

── Column specification ──────────────────────────────────────────────
cols(
  UCC = col_double(),
  PAY = col_double(),
  LAZ = col_double(),
  KPK = col_double(),
  RT = col_double(),
  COF = col_double(),
  BIH = col_double(),
  DII = col_double(),
  ENG = col_double(),
  ACU = col_double(),
  Rank = col_double(),
  Team = col_character(),
  Conf = col_character()
)
Warning: 10 parsing failures.
row col   expected     actual                       file
  1  -- 13 columns 15 columns './data/massey-rating.txt'
  2  -- 13 columns 14 columns './data/massey-rating.txt'
  3  -- 13 columns 14 columns './data/massey-rating.txt'
  4  -- 13 columns 14 columns './data/massey-rating.txt'
  5  -- 13 columns 15 columns './data/massey-rating.txt'
... ... .......... .......... ..........................
See problems(...) for more details.
as_tibble(datos_txt)
# A tibble: 10 × 13
     UCC   PAY   LAZ   KPK    RT   COF   BIH   DII   ENG   ACU  Rank
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1     1     1     1     1     1     1     1     1     1     1     1
 2     2     2     2     2     2     2     2     2     4     2     2
 3     3     4     3     4     3     4     3     4     2     3     3
 4     4     3     4     3     4     3     5     3     3     4     4
 5     6     6     6     5     5     7     6     5     6    11     5
 6     7     7     7     6     7     6    11     8     7     8     6
 7     5     5     5     7     6     8     4     6     5     5     7
 8     8     8     9     9    10     5     7     7    10     7     8
 9     9    11     8    13    11    11    12     9    14     9     9
10    13    10    13    11     8     9    10    11     9    10    10
# ℹ 2 more variables: Team <chr>, Conf <chr>

Data Excel (.xls, .xlsx)

Paket impor kunci lainnya adalah readxl untuk mengimpor data dari Excel. Tiga fungsi yang menjadi kunci:

  • read_xls() specific to .xls, read_xlsx() specific to .xlsx.
  • read_excel(): for both .xls and .xlsx.

Kita akan mengimpor deaths.xlsx dengan catatan kematian selebriti.

library(readxl)
deaths <- read_xlsx(path = "./data/deaths.xlsx")
New names:
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
deaths
# A tibble: 18 × 6
   `Lots of people`             ...2           ...3  ...4  ...5  ...6 
   <chr>                        <chr>          <chr> <chr> <chr> <chr>
 1 simply cannot resist writing <NA>           <NA>  <NA>  <NA>  some…
 2 at                           the            top   <NA>  of    thei…
 3 or                           merging        <NA>  <NA>  <NA>  cells
 4 Name                         Profession     Age   Has … Date… Date…
 5 David Bowie                  musician       69    TRUE  17175 42379
 6 Carrie Fisher                actor          60    TRUE  20749 42731
 7 Chuck Berry                  musician       90    TRUE  9788  42812
 8 Bill Paxton                  actor          61    TRUE  20226 42791
 9 Prince                       musician       57    TRUE  21343 42481
10 Alan Rickman                 actor          69    FALSE 16854 42383
11 Florence Henderson           actor          82    TRUE  12464 42698
12 Harper Lee                   author         89    FALSE 9615  42419
13 Zsa Zsa Gábor                actor          99    TRUE  6247  42722
14 George Michael               musician       53    FALSE 23187 42729
15 Some                         <NA>           <NA>  <NA>  <NA>  <NA> 
16 <NA>                         also like to … <NA>  <NA>  <NA>  <NA> 
17 <NA>                         <NA>           at t… bott… <NA>  <NA> 
18 <NA>                         <NA>           <NA>  <NA>  <NA>  too! 

Data Excel (.xls, .xlsx)

deaths |> slice(1:6)
# A tibble: 6 × 6
  `Lots of people`             ...2       ...3  ...4     ...5    ...6 
  <chr>                        <chr>      <chr> <chr>    <chr>   <chr>
1 simply cannot resist writing <NA>       <NA>  <NA>     <NA>    some…
2 at                           the        top   <NA>     of      thei…
3 or                           merging    <NA>  <NA>     <NA>    cells
4 Name                         Profession Age   Has kids Date o… Date…
5 David Bowie                  musician   69    TRUE     17175   42379
6 Carrie Fisher                actor      60    TRUE     20749   42731

Satu hal yang sangat umum terjadi adalah ada semacam komentar atau teks di awal file, sehingga harus melewati baris-baris tersebut.

Data Excel (.xls, .xlsx)

Kita dapat melewati baris-baris ini langsung saat memuat dengan skip = ... (menunjukkan jumlah baris yang akan dilewati).

deaths <- read_xlsx(path = "./data/deaths.xlsx", skip = 4)
deaths
# A tibble: 14 × 6
   Name               Profession  Age   `Has kids` `Date of birth`    
   <chr>              <chr>       <chr> <chr>      <dttm>             
 1 David Bowie        musician    69    TRUE       1947-01-08 00:00:00
 2 Carrie Fisher      actor       60    TRUE       1956-10-21 00:00:00
 3 Chuck Berry        musician    90    TRUE       1926-10-18 00:00:00
 4 Bill Paxton        actor       61    TRUE       1955-05-17 00:00:00
 5 Prince             musician    57    TRUE       1958-06-07 00:00:00
 6 Alan Rickman       actor       69    FALSE      1946-02-21 00:00:00
 7 Florence Henderson actor       82    TRUE       1934-02-14 00:00:00
 8 Harper Lee         author      89    FALSE      1926-04-28 00:00:00
 9 Zsa Zsa Gábor      actor       99    TRUE       1917-02-06 00:00:00
10 George Michael     musician    53    FALSE      1963-06-25 00:00:00
11 Some               <NA>        <NA>  <NA>       NA                 
12 <NA>               also like … <NA>  <NA>       NA                 
13 <NA>               <NA>        at t… bottom,    NA                 
14 <NA>               <NA>        <NA>  <NA>       NA                 
# ℹ 1 more variable: `Date of death` <chr>

Data Excel (.xls, .xlsx)

Selain itu dengan col_names = ... kita sudah dapat mengganti nama kolom saat impor (jika menyediakan nama berarti baris pertama sudah dianggap sebagai data)

deaths <-
  read_xlsx(path = "./data/deaths.xlsx", skip = 5,
            col_names = c("name", "profession", "age", "kids", "birth", "death"))
deaths
# A tibble: 14 × 6
   name               profession age   kids  birth               death
   <chr>              <chr>      <chr> <chr> <dttm>              <chr>
 1 David Bowie        musician   69    TRUE  1947-01-08 00:00:00 42379
 2 Carrie Fisher      actor      60    TRUE  1956-10-21 00:00:00 42731
 3 Chuck Berry        musician   90    TRUE  1926-10-18 00:00:00 42812
 4 Bill Paxton        actor      61    TRUE  1955-05-17 00:00:00 42791
 5 Prince             musician   57    TRUE  1958-06-07 00:00:00 42481
 6 Alan Rickman       actor      69    FALSE 1946-02-21 00:00:00 42383
 7 Florence Henderson actor      82    TRUE  1934-02-14 00:00:00 42698
 8 Harper Lee         author     89    FALSE 1926-04-28 00:00:00 42419
 9 Zsa Zsa Gábor      actor      99    TRUE  1917-02-06 00:00:00 42722
10 George Michael     musician   53    FALSE 1963-06-25 00:00:00 42729
11 Some               <NA>       <NA>  <NA>  NA                  <NA> 
12 <NA>               also like… <NA>  <NA>  NA                  <NA> 
13 <NA>               <NA>       at t… bott… NA                  <NA> 
14 <NA>               <NA>       <NA>  <NA>  NA                  too! 

Data Excel (.xls, .xlsx)

Terkadang tanggal Excel diformat secara tidak benar (mengejutkan): kita dapat menggunakan convertToDate() dari paket openxlsx untuk mengonversinya.

library(openxlsx)
deaths$death <- convertToDate(deaths$death)
Warning in convertToDate(deaths$death): NAs introduced by coercion
deaths
# A tibble: 14 × 6
   name          profession age   kids  birth               death     
   <chr>         <chr>      <chr> <chr> <dttm>              <date>    
 1 David Bowie   musician   69    TRUE  1947-01-08 00:00:00 2016-01-10
 2 Carrie Fisher actor      60    TRUE  1956-10-21 00:00:00 2016-12-27
 3 Chuck Berry   musician   90    TRUE  1926-10-18 00:00:00 2017-03-18
 4 Bill Paxton   actor      61    TRUE  1955-05-17 00:00:00 2017-02-25
 5 Prince        musician   57    TRUE  1958-06-07 00:00:00 2016-04-21
 6 Alan Rickman  actor      69    FALSE 1946-02-21 00:00:00 2016-01-14
 7 Florence Hen… actor      82    TRUE  1934-02-14 00:00:00 2016-11-24
 8 Harper Lee    author     89    FALSE 1926-04-28 00:00:00 2016-02-19
 9 Zsa Zsa Gábor actor      99    TRUE  1917-02-06 00:00:00 2016-12-18
10 George Micha… musician   53    FALSE 1963-06-25 00:00:00 2016-12-25
11 Some          <NA>       <NA>  <NA>  NA                  NA        
12 <NA>          also like… <NA>  <NA>  NA                  NA        
13 <NA>          <NA>       at t… bott… NA                  NA        
14 <NA>          <NA>       <NA>  <NA>  NA                  NA        

Data Excel (.xls, .xlsx)

Kita juga dapat memuat Excel dengan beberapa sheet: untuk menunjukkan sheet (berdasarkan nama atau nomor) gunakan argumen sheet = ....

mtcars <- read_xlsx(path = "./data/datasets.xlsx", sheet = "mtcars")
mtcars
# A tibble: 32 × 11
     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
 3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
 4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
 5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
 6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
 7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
 8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
 9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
# ℹ 22 more rows

Data Excel (.xls, .xlsx)

Kita bahkan dapat menunjukkan rentang sel yang akan dimuat dengan range = ....

iris <- read_xlsx(path = "./data/datasets.xlsx", sheet = "iris", range = "C1:E4")
iris
# A tibble: 3 × 3
  Petal.Length Petal.Width Species
         <dbl>       <dbl> <chr>  
1          1.4         0.2 setosa 
2          1.4         0.2 setosa 
3          1.3         0.2 setosa 

Impor dari SAS/STATA/SPSS

Paket haven dalam orbit tidyverse memungkinkan kita mengimpor file dari 3 perangkat lunak komersial terpenting: SAS, SPSS, dan Stata.

library(haven)

# SAS
iris_sas <- read_sas(data_file = "./data/iris.sas7bdat")

# SPSS
iris_spss <- read_sav(file = "./data/iris.sav")

# Stata
iris_stata <- read_dta(file = "./data/iris.dta")

Ekspor

Dengan cara yang sama seperti kita dapat mengimpor, kita juga dapat mengekspor

  • diekspor dalam .RData (opsi yang disarankan untuk variabel yang disimpan di R). Ingat ekstensi ini hanya dapat digunakan di R. Gunakan saja save(object, file = path).
table <- tibble("a" = 1:4, "b" = 1:4)
save(table, file = "./data/table.RData")
rm(table) # eliminar
load("./data/table.RData")
table
# A tibble: 4 × 2
      a     b
  <int> <int>
1     1     1
2     2     2
3     3     3
4     4     4

Ekspor

Dengan cara yang sama seperti kita dapat mengimpor, kita juga dapat mengekspor

  • exported in .RData multiple objects
table <- tibble("a" = 1:4, "b" = 1:4)
a <- 1
b <- c("javi", "sandra")
save(table, a, b, file = "./data/mult_obj.RData")
rm(list = c("a", "b", "table"))
load("./data/mult_obj.RData")
table
# A tibble: 4 × 2
      a     b
  <int> <int>
1     1     1
2     2     2
3     3     3
4     4     4

Ekspor

Dengan cara yang sama seperti kita dapat mengimpor, kita juga dapat mengekspor

  • diekspor dalam .csv. Gunakan saja write_csv(object, file = path).
write_csv(table, file = "./data/table.csv")
read_csv(file = "./data/table.csv")
Rows: 4 Columns: 2
── Column specification ──────────────────────────────────────────────
Delimiter: ","
dbl (2): a, b

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 4 × 2
      a     b
  <dbl> <dbl>
1     1     1
2     2     2
3     3     3
4     4     4

Impor dari Website

Salah satu keunggulan utama R adalah kita dapat menggunakan fungsi impor langsung dari web, tanpa mengunduh secara manual: cukup berikan tautan sebagai pengganti path lokal. Misalnya, kita akan mengunduh data covid dari ISCIII (https://cnecovid.isciii.es/covid19/#documentaci%C3%B3n-y-datos)

covid_data <-
  read_csv(file = "https://cnecovid.isciii.es/covid19/resources/casos_hosp_uci_def_sexo_edad_provres.csv")
covid_data
Rows: 500 Columns: 8
── Column specification ──────────────────────────────────────────────
Delimiter: ","
chr  (3): provincia_iso, sexo, grupo_edad
dbl  (4): num_casos, num_hosp, num_uci, num_def
date (1): fecha

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 500 × 8
   provincia_iso sexo  grupo_edad fecha      num_casos num_hosp
   <chr>         <chr> <chr>      <date>         <dbl>    <dbl>
 1 A             H     0-9        2020-01-01         0        0
 2 A             H     10-19      2020-01-01         0        0
 3 A             H     20-29      2020-01-01         0        0
 4 A             H     30-39      2020-01-01         0        0
 5 A             H     40-49      2020-01-01         0        0
 6 A             H     50-59      2020-01-01         0        0
 7 A             H     60-69      2020-01-01         0        0
 8 A             H     70-79      2020-01-01         0        0
 9 A             H     80+        2020-01-01         0        0
10 A             H     NC         2020-01-01         0        0
# ℹ 490 more rows
# ℹ 2 more variables: num_uci <dbl>, num_def <dbl>

Impor dari Wikipedia

Paket rvest, salah satu yang paling berguna dari tidyverse, memungkinkan kita mengimpor langsung dari html. Misalnya, untuk mengekspor tabel wikipedia gunakan read_html() untuk mengimpor html, html_element("table") untuk mengekstrak objek tabel, dan html_table() untuk mengonversi ke tibble.

library(rvest)

Attaching package: 'rvest'
The following object is masked from 'package:readr':

    guess_encoding
wiki_jump <- 'https://en.wikipedia.org/wiki/Men%27s_long_jump_world_record_progression'
wiki_jump |> read_html() |> 
  html_element("table") |> 
  html_table()
# A tibble: 24 × 4
   Mark                     Athlete                      Place   Date 
   <chr>                    <chr>                        <chr>   <chr>
 1 6.97 m (22 ft 10+1⁄4 in) T. Rodgers (USA)             San Fr… 5 Ja…
 2 6.98 m (22 ft 10+3⁄4 in) Harry Worthington (USA)      Hanove… 8 Ma…
 3 7.11 m (23 ft 3+3⁄4 in)  Aleksander Klumberg (EST)    Tartu   19 D…
 4 7.49 m (24 ft 6+3⁄4 in)  William DeHart Hubbard (USA) Urbana  1 Ma…
 5 7.50 m (24 ft 7+1⁄4 in)  William DeHart Hubbard (USA) New Yo… 20 M…
 6 7.70 m (25 ft 3 in)      Jesse Owens (USA)            New Yo… 24 F…
 7 7.71 m (25 ft 3+1⁄2 in)  Eulace Peacock (USA)         New Yo… 23 F…
 8 7.82 m (25 ft 7+3⁄4 in)  Jesse Owens (USA)            New Yo… 23 F…
 9 7.85 m (25 ft 9 in)      Jesse Owens (USA)            New Yo… 23 F…
10 7.86 m (25 ft 9+1⁄4 in)  Irvin Roberson (USA)         New Yo… 20 F…
# ℹ 14 more rows

Impor dari Google Drive

Opsi lain (terutama jika bekerja dengan orang lain) adalah mengimpor dari spreadsheet Google Drive, menggunakan read_sheet() dari paket googlesheets4.

Pertama kali kamu akan diminta izin tidyverse untuk berinteraksi dengan drive-mu

library(googlesheets4)
google_sheet <-
  read_sheet("https://docs.google.com/spreadsheets/d/1Uz38nHjl3bmftxDpcXj--DYyPo1I39NHVf-xjeg1_wI/edit?usp=sharing")
google_sheet

Impor dari API (owid)

Opsi menarik lain adalah mengunduh data dari API: perantara antara aplikasi atau penyedia data dan R kita. Misalnya, mari muat pustaka {owidR}, yang memungkinkan mengunduh data dari https://ourworldindata.org/. Fungsi owid_covid() memuat lebih dari 400.000 catatan dengan lebih dari 60 variabel dari 238 negara.

library(owidR)
owid_covid() |> as_tibble()

Impor dari API (aemet)

Dalam banyak kesempatan untuk terhubung ke API kita harus terlebih dahulu mendaftar dan mendapatkan kunci, ini adalah kasus paket climaemet untuk mengakses data meteorologi Spanyol (https://opendata.aemet.es/centrodedescargas/inicio).

Setelah kita memiliki kunci API kita mendaftarkannya di RStudio agar dapat digunakan di masa depan.

library(climaemet)

# Api key
apikey <- "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqYXZhbHYwOUB1Y20uZXMiLCJqdGkiOiI4YTU1ODUxMS01MTE3LTQ4MTYtYmM4OS1hYmVkNDhiODBkYzkiLCJpc3MiOiJBRU1FVCIsImlhdCI6MTY2NjQ2OTcxNSwidXNlcklkIjoiOGE1NTg1MTEtNTExNy00ODE2LWJjODktYWJlZDQ4YjgwZGM5Iiwicm9sZSI6IiJ9.HEMR77lZy2ASjmOxJa8ppx2J8Za1IViurMX3p1reVBU"

aemet_api_key(apikey, install = TRUE)

Impor dari API (aemet)

Dengan paket ini kita dapat melakukan pencarian stasiun untuk mengetahui kode pos dan kode identifikasinya dalam jaringan AEMET

stations <- aemet_stations()
stations

Impor dari API (aemet)

Misalnya, untuk mendapatkan data dari stasiun bandara El Prat, Barcelona, kode yang diberikan adalah "0076", mendapatkan data per jam

aemet_last_obs("0076")

Impor dari API (Sensus AS)

Salah satu alat paling berguna dalam beberapa tahun terakhir dikenal sebagai tidycensus: alat untuk memfasilitasi proses mengunduh data sensus untuk Amerika Serikat dari R.

library(tidycensus)
  • get_decennial(): untuk mengakses data sensus (Sensus Sepuluh Tahunan AS), dilakukan setiap 10 tahun (tahun 2000, 2010, dan 2020).

  • get_acs(): untuk mengakses ACS (American Community Survey) tahunan dan lima tahunan (sensus ≠ survei)

  • get_estimates(): untuk mengakses perkiraan populasi, kelahiran, dan kematian tahunan

  • get_pums(): untuk mengakses mikro data (tidak teragregasi) dari ACS (dianonimkan di tingkat individu)

  • get_flows(): untuk mengakses data aliran migrasi.

Impor dari API (Sensus AS)

Misalnya, kita akan mengunduh data sensus (get_decennial()) di tingkat negara bagian (geography = "state") untuk populasi (variabel variables = "P001001") tahun 2010 (lihat variabel dalam tidycensus::load_variables()).

total_population_10 <-
  get_decennial(geography = "state", 
  variables = "P001001",
  year = 2010)
total_population_10

Import from API

Opsi lainnya:

💻 Giliranmu

Try to solve the following exercises without looking at the solutions

📊 Data

📝 Dataset who yang sudah kita gunakan dalam latihan sebelumnya, ekspor ke format native R dalam folder data proyek.

Code
library(tidyr)
save(who, file = "./data/who.RData")

📝 Muat dataset who dari folder data (impor file yang dibuat dalam latihan sebelumnya).

Code
load("./data/who.RData")

📝 Ulangi hal yang sama (ekspor dan impor) dalam 4 format: .csv, .xlsx, .sav (spss), dan .dta (stata).

Code
# csv
library(readr)
write_csv(who, file = "./data/who.csv")
who_data <- read_csv(file = "./data/who.csv")

# excel
library(openxlsx)
write.xlsx(who, file = "./data/who.xlsx")
who_data <- read_xlsx(path = "./data/who.xlsx")

# sas y stata
library(haven)
write_sav(who, path = "./data/who.sav")
who_data <- read_spss(path = "./data/who.sav")

write_dta(who, path = "./data/who.dta")
who_data <- read_dta(path = "./data/who.dta")

📝 Ulangi pemuatan who.csv tetapi hanya pilih 4 kolom pertama langsung saat pemuatan.

Code
who_select <-
  read_csv(file = "./data/who.csv",
           col_select = c("country", "iso2", "iso3", "year"))

🐣 Studi Kasus I: Survei CIS Feminisme

📊 Data

Kita akan mempraktikkan pemuatan dan pra-pemrosesan file dari SPSS. File berisi data dari barometer CIS «Persepsi tentang kesetaraan antara pria dan wanita dan stereotip gender» (ekstensi .sav dalam subfolder CIS-feminism) yang pekerjaan sampelnya dilakukan 6–14 November (4000 wawancara, kedua jenis kelamin, usia >16 tahun, 1174 kotamadya, 50 provinsi).

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

L8: faktor dan list

Menangani faktor dan list

List (Daftar)

Kita sudah melihat bahwa list adalah objek di R yang memungkinkan kita menyimpan koleksi variabel bertipe berbeda (seperti dengan data.frame dan tibble) tetapi juga panjang yang berbeda, dengan struktur sepenuhnya heterogen (bahkan sebuah list bisa memiliki list lain di dalamnya).

name <- "Javi"
age <- 34
marks <- c(7, 8, 5, 3, 10, 9)
parents <- c("Paloma", "Goyo")

list_var <- list("name" = name, "age" = age, "marks" = marks, "parents" = parents)
list_var$name
[1] "Javi"
list_var$marks
[1]  7  8  5  3 10  9

List (Daftar)

Kita juga dapat membuat list dengan list lain di dalamnya, sehingga untuk mengakses setiap level kita harus menggunakan operator [[]].

list_of_lists <- list("list_1" = list_var[1:2], "list_2" = list_var[3:4])
names(list_of_lists)
[1] "list_1" "list_2"
names(list_of_lists[[1]])
[1] "name" "age" 
list_of_lists[[1]][[1]]
[1] "Javi"

We are allowed to store n-dimensional data!

List (Daftar)

Salah satu kekurangannya adalah list tidak dapat divektorisasi secara langsung, sehingga operasi aritmatika yang diterapkan pada list akan memberikan error.

data <- list("a" = 1:5, "b" = 10:20)
data / 2
Error in data/2: non-numeric argument to binary operator

Untuk tujuan ini, salah satu opsi umum (tetapi sudah usang) adalah menggunakan keluarga lapply().

lapply(data, FUN = function(x) { x / 2})
$a
[1] 0.5 1.0 1.5 2.0 2.5

$b
 [1]  5.0  5.5  6.0  6.5  7.0  7.5  8.0  8.5  9.0  9.5 10.0

By default, the output of lapply()is always a list of equal length.

List (Daftar)

Opsi yang lebih fleksibel dan serbaguna adalah menggunakan paket purrr dari lingkungan tidyverse.

library(purrr)

Paket ini dimaksudkan untuk meniru pemrograman fungsional dari bahasa lain seperti Scala atau strategi map-reduce Hadoop (dari Google).

List (Daftar)

Fungsi paling sederhana dari paket purrr adalah fungsi map(), yang menerapkan fungsi tervektorisasi ke setiap elemen list. Mari lihat contoh pertama yang diterapkan pada vektor

map() allows us to “map” each list and apply the function element by element (if applicable).

x <- list("x1" = 1:4, "x2" = 11:20)
map(x, sqrt) 
$x1
[1] 1.000000 1.414214 1.732051 2.000000

$x2
 [1] 3.316625 3.464102 3.605551 3.741657 3.872983 4.000000 4.123106
 [8] 4.242641 4.358899 4.472136

Be careful

Dengan vektor kita memiliki vektorisasi default karena R melakukan operasi elemen per elemen. Perhatikan bahwa, secara default, output dari map adalah list.

List (Daftar)

Mari lihat contoh lain. Definisikan dalam sebuah list dua sampel dari 2 distribusi normal, dengan ukuran sampel dan rata-rata yang berbeda. Hitung rata-rata masing-masing.

Code
x <- list(rnorm(n = 1500, mean = 0, sd = 0.7),
          rnorm(n = 2800, mean = 2, sd = 1.5))
map(x, mean)
[[1]]
[1] -0.004560611

[[2]]
[1] 1.999587

List (Daftar)

Bagaimana jika kita ingin menghitung rata-rata dari nilai kuadratnya?

Code
map(x, function(x) { mean(x^2) })
[[1]]
[1] 0.4927901

[[2]]
[1] 6.268047

List (Daftar)

Selain lebih mudah dibaca dan efisien, dengan purrr kita dapat memutuskan format output setelah operasi

  • output as numeric (double) vector with map_dbl()
  • output as numeric (int) vector with map_int()
  • output as character vector with map_chr()
  • output as logical vector with map_lgl()
map_dbl(x, mean)
[1] -0.004560611  1.999587458
map_chr(x, function(x) { glue("Mean is {round(mean(x), 5)}") })
[1] "Mean is -0.00456" "Mean is 1.99959" 

List (Daftar)

c(x[[1]][3], x[[2]][3])
[1] 0.5447725 0.7859762

Juga, jika kamu meneruskan angka alih-alih fungsi, itu akan mengembalikan elemen ke-i dari setiap list.

map_dbl(x, 3)
[1] 0.5447725 0.7859762

List (Daftar)

list_dummy <- list("a" = dplyr::starwars, "b" = tidyr::billboard)

Kita juga dapat menggunakan pluck() untuk mengakses elemen ke-i dari sebuah list

list_dummy |> 
  pluck(1)
# A tibble: 87 × 14
   name  height  mass hair_color skin_color eye_color birth_year sex  
   <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke…    172    77 blond      fair       blue            19   male 
 2 C-3PO    167    75 <NA>       gold       yellow         112   none 
 3 R2-D2     96    32 <NA>       white, bl… red             33   none 
 4 Dart…    202   136 none       white      yellow          41.9 male 
 5 Leia…    150    49 brown      light      brown           19   fema…
 6 Owen…    178   120 brown, gr… light      blue            52   male 
 7 Beru…    165    75 brown      light      blue            47   fema…
 8 R5-D4     97    32 <NA>       white, red red             NA   none 
 9 Bigg…    183    84 black      light      brown           24   male 
10 Obi-…    182    77 auburn, w… fair       blue-gray       57   male 
# ℹ 77 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

List (Daftar)

Kita juga memiliki opsi untuk menggeneralisasikannya agar dapat menggunakan fungsi yang membutuhkan dua argumen dalam bentuk list (operasi biner), dengan map2()

x <- list("a" = 1:3, "b" = 4:6)
y <- list("c" = c(-1, 4, 0), "b" = c(5, -4, -1))
map2(x, y, function(x, y) { x^2 + y^2})
$a
[1]  2 20  9

$b
[1] 41 41 37

List (Daftar)

Kita dapat memperoleh output dalam bentuk data.frame dengan menambahkan list_rbind() atau list_cbind(), yang mengonversi list menjadi tabel.

x <- c("a", "b", "c")
y <- 1:3
map2(x, y, function(x, y) { tibble(x, y) }) |> list_rbind()
# A tibble: 3 × 2
  x         y
  <chr> <int>
1 a         1
2 b         2
3 c         3

List (Daftar)

Kita dapat menggeneralisasikannya lebih lanjut dengan pmap_xxx() yang memungkinkan penggunaan beberapa argumen (beberapa list).

x <- list(1, 1, 1)
y <- list(10, 20, 30)
z <- list(100, 200, 300)
pmap_dbl(list(x, y, z), sum)
[1] 111 221 331

List (Daftar)

Kita memiliki jenis iterator lain yang, meskipun menerima input, tidak mengembalikan apa-apa, seperti walk() (satu argumen), walk2() (dua argumen) dan pwalk() (beberapa argumen), semuanya mengembalikan secara tidak terlihat, hanya memanggil fungsi untuk efek sampingnya.

list("a" = 1:3, "b" = 4:6) |>
  map2(list("a" = 11:13, "b" = 14:16),
       function(x, y) { x + y }) |> 
  walk(print)
[1] 12 14 16
[1] 18 20 22

💻 Giliranmu

📝 Definisikan list dengan 4 elemen bertipe berbeda dan akses yang kedua (saya akan menyertakan satu yang berupa tibble agar kamu dapat melihat bahwa dalam list ada ruang untuk segalanya).

Code
list_example <-
  list("name" = "Javier", "cp" = 28019,
       "siblings" = TRUE,
       "marks" = tibble("maths" = c(7.5, 8, 9),
                        "lang" = c(10, 5, 6)))
list_example

📝 Dari list di atas, akses elemen yang menempati posisi 1 dan 4.

Code
list_example[c(1, 4)]

list_example$name
list_example$marks

list_example[c("name", "marks")]

📝 Muat dataset starwars dari paket dplyr dan akses film kedua yang muncul dalam starwars$films (untuk setiap karakter). Tentukan mana yang tidak muncul di lebih dari satu film.

second_film <- map(starwars$films, 2)
map_lgl(second_film, is.null)
 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE
[12] FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE
[23]  TRUE FALSE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE
[34] FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE
[45] FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
[56]  TRUE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE
[67] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE
[78]  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

Variabel Kualitatif: Faktor

Dalam statistik, ketika kita membicarakan variabel kualitatif, kita akan menyebut level atau modalitas sebagai nilai-nilai berbeda yang dapat diambil data tersebut. Misalnya, untuk variabel sex dalam set starwars, kita memiliki 4 level yang diizinkan: female, hermaphroditic, male dan none (di samping data hilang).

starwars |> count(sex)
# A tibble: 5 × 2
  sex                n
  <chr>          <int>
1 female            16
2 hermaphroditic     1
3 male              60
4 none               6
5 <NA>               4

Variabel Kualitatif: Faktor

Jenis variabel ini dikenal dalam R sebagai faktor, dan paket fundamental untuk menanganinya adalah forcats (dari lingkungan tidyverse).

Variabel Kualitatif: Faktor

Paket ini memungkinkan kita menetapkan level (disimpan secara internal sebagai levels) yang diambil variabel kategoris sehingga tidak ada kesalahan dalam pengumpulan dan pembuatan data. Ini juga membuat analisisnya lebih hemat komputasi, memberikan perlakuan yang berbeda dari string teks biasa.

Mari lihat contoh sederhana mensimulasikan variabel party dengan nilai "PP", "PSOE", dan "SUMAR" (ukuran 15)

set.seed(1234567)
party <- sample(x = c("PP", "PSOE", "SUMAR"), size = 15, replace = TRUE)
party
 [1] "PP"    "PSOE"  "SUMAR" "PP"    "PP"    "SUMAR" "PSOE"  "SUMAR"
 [9] "SUMAR" "SUMAR" "PP"    "PSOE"  "PP"    "PSOE"  "SUMAR"

Variabel party saat ini bertipe teks, tipe chr, yang dapat diperiksa dengan class(state).

class(party)
[1] "character"

Variabel Kualitatif: Faktor

Dari sudut pandang statistik dan komputasi, untuk R variabel ini sekarang setara dengan variabel bernama. Tetapi secara statistik variabel sebagai string tidak sama dengan variabel kategoris yang hanya dapat mengambil 3 level tersebut. Bagaimana cara mengonversi ke faktor?

Dengan menggunakan fungsi as_factor() dari paket forcats.

library(tidyverse)
party_fct <- tibble("id" = 1:length(party),
                    "party" = as_factor(party))
party_fct
# A tibble: 15 × 2
      id party
   <int> <fct>
 1     1 PP   
 2     2 PSOE 
 3     3 SUMAR
 4     4 PP   
 5     5 PP   
 6     6 SUMAR
 7     7 PSOE 
 8     8 SUMAR
 9     9 SUMAR
10    10 SUMAR
11    11 PP   
12    12 PSOE 
13    13 PP   
14    14 PSOE 
15    15 SUMAR

Variabel Kualitatif: Faktor

Tidak hanya kelas variabel yang berubah, tetapi sekarang, di bawah nilai yang disimpan, kalimat Levels: ... muncul: itulah modalitas atau level dari variabel kualitatif kita.

party_fct |> pull(party)
 [1] PP    PSOE  SUMAR PP    PP    SUMAR PSOE  SUMAR SUMAR SUMAR PP   
[12] PSOE  PP    PSOE  SUMAR
Levels: PP PSOE SUMAR

Variabel Kualitatif: Faktor

Bayangkan kita mendefinisikan database anggota parlemen dan anggota PP tidak hadir hari itu: meskipun variabel kita tidak mengambil nilai itu HARI ITU, nilai PSOE adalah level yang diizinkan dalam database (sehingga bahkan jika kita menghapusnya, karena itu faktor, level tetap ada).

party_fct |> 
  filter(party %in% c("PP", "SUMAR")) |> 
  pull(party)
 [1] PP    SUMAR PP    PP    SUMAR SUMAR SUMAR SUMAR PP    PP    SUMAR
Levels: PP PSOE SUMAR

Variabel Kualitatif: Faktor

Dengan fungsi factor() kita dapat secara eksplisit menentukan nama-nama modalitas dan menggunakan levels = ... kita dapat secara eksplisit memberi tahu “urutan” modalitas

party_fct <-
  tibble(id = 1:length(party),
         party = factor(party, levels = c("SUMAR", "PP", "PSOE")))
party_fct |> pull(party)
 [1] PP    PSOE  SUMAR PP    PP    SUMAR PSOE  SUMAR SUMAR SUMAR PP   
[12] PSOE  PP    PSOE  SUMAR
Levels: SUMAR PP PSOE

Variabel Kualitatif: Faktor

“Urutan” sebelumnya hanya dalam arti mana yang akan dihitung/digambar pertama) tetapi kita belum memiliki variabel ordinal

party_fct$party < "SUMAR"
Warning in Ops.factor(party_fct$party, "SUMAR"): '<' not meaningful
for factors
 [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

Bagaimana jika kita ingin mendefinisikan variabel kualitatif ORDINAL? Di dalam factor() kita harus menunjukkan bahwa ordered = TRUE.

marks <- c("A", "E", "F", "B", "A+", "A", "C", "C", "D", "B", "A", "C", "C", "E", "F", "D", "A+")
marks_database <-
  tibble("student" = 1:length(marks),
         "marks" =
           factor(marks, levels = c("F", "E", "D", "C", "B", "A", "A+"),
                  ordered = TRUE))
marks_database |> pull(marks)
 [1] A  E  F  B  A+ A  C  C  D  B  A  C  C  E  F  D  A+
Levels: F < E < D < C < B < A < A+

Variabel Kualitatif: Faktor

Apa yang berubah? Jika kamu perhatikan sekarang, meskipun variabel masih kualitatif, kita dapat membuat perbandingan dan mengurutkan catatan karena ada hierarki antara modalitas.

marks_database |> filter(marks >= "B")
# A tibble: 7 × 2
  student marks
    <int> <ord>
1       1 A    
2       4 B    
3       5 A+   
4       6 A    
5      10 B    
6      11 A    
7      17 A+   

Variabel Kualitatif: Faktor

Jika kita ingin menghapus level yang tidak digunakan saat itu (yang ingin kita kecualikan dari definisi) kita dapat melakukannya dengan fct_drop().

marks_database |> 
  filter(marks %in% c("F", "E", "D", "C", "B", "A")) |> 
  pull(marks)
 [1] A E F B A C C D B A C C E F D
Levels: F < E < D < C < B < A < A+

marks_database |> 
  filter(marks %in% c("F", "E", "D", "C", "B", "A")) |> 
  mutate(marks = fct_drop(marks)) |>  
  pull(marks)
 [1] A E F B A C C D B A C C E F D
Levels: F < E < D < C < B < A

Variabel Kualitatif: Faktor

Sama seperti kita dapat menghapus level, kita dapat memperluas level yang ada (bahkan jika tidak ada data untuk level itu saat ini) dengan fct_expand().

marks_database |> 
  mutate(marks = fct_expand(marks, c("F-", "A+", "A++"))) %>% 
  pull(marks)
 [1] A  E  F  B  A+ A  C  C  D  B  A  C  C  E  F  D  A+
Levels: F < E < D < C < B < A < A+ < F- < A++

Variabel Kualitatif: Faktor

Selain itu dengan fct_explicit_na() kita dapat menetapkan level untuk nilai yang hilang agar disertakan dalam analisis dan visualisasi.

fct_explicit_na(factor(c("a", "b", NA)))
Warning: `fct_explicit_na()` was deprecated in forcats 1.0.0.
ℹ Please use `fct_na_value_to_level()` instead.
[1] a         b         (Missing)
Levels: a b (Missing)

Variabel Kualitatif: Faktor

Bahkan setelah didefinisikan kita dapat mengurutkan ulang level dengan fct_relevel().

marks_database_expand <- 
  marks_database |>  
  mutate(marks = fct_expand(marks, c("F-", "A+", "A++"))) |> 
  pull(marks)

marks_database_expand |> 
  fct_relevel(c("F-", "F", "E", "D", "C", "B", "A", "A+", "A++"))
 [1] A  E  F  B  A+ A  C  C  D  B  A  C  C  E  F  D  A+
Levels: F- < F < E < D < C < B < A < A+ < A++

Variabel Kualitatif: Faktor

Cara bekerja dengan variabel kualitatif ini memungkinkan kita memberikan definisi teoritis dari database kita, dan kita bahkan dapat menghitung nilai yang belum ada (tetapi bisa ada), menggunakan fct_count().

marks_database |> 
  mutate(marks = fct_expand(marks, c("F-", "A+", "A++"))) |> 
  pull(marks) |> 
  fct_count()
# A tibble: 9 × 2
  f         n
  <ord> <int>
1 F         2
2 E         2
3 D         2
4 C         4
5 B         2
6 A         3
7 A+        2
8 F-        0
9 A++       0

Variabel Kualitatif: Faktor

Level juga dapat diurutkan berdasarkan frekuensi dengan fct_infreq().

marks_database |> 
  mutate(marks = fct_infreq(marks)) |> 
  pull(marks)
 [1] A  E  F  B  A+ A  C  C  D  B  A  C  C  E  F  D  A+
Levels: C < A < F < E < D < B < A+
marks_database |> 
  mutate(marks = fct_infreq(marks)) |> 
  pull(marks) |> 
  fct_count()
# A tibble: 7 × 2
  f         n
  <ord> <int>
1 C         4
2 A         3
3 F         2
4 E         2
5 D         2
6 B         2
7 A+        2

Variabel Kualitatif: Faktor

Terkadang kita ingin mengelompokkan level, misalnya, tidak mengizinkan level yang tidak muncul minimal sejumlah kali dengan fct_lump_min(..., min = ..) (pengamatan yang tidak memenuhi ini akan masuk ke level generik bernama Other).

marks_database |> 
  pull(marks) %>% 
  fct_lump_min(min = 3)
 [1] A     Other Other Other Other A     C     C     Other Other A    
[12] C     C     Other Other Other Other
Levels: C < A < Other
marks_database |> 
  pull(marks) |>
  fct_lump_min(min = 3,
               other_level = "Less frequent")
 [1] A             Less frequent Less frequent Less frequent
 [5] Less frequent A             C             C            
 [9] Less frequent Less frequent A             C            
[13] C             Less frequent Less frequent Less frequent
[17] Less frequent
Levels: C < A < Less frequent

Variabel Kualitatif: Faktor

Kita dapat melakukan sesuatu yang setara tetapi berdasarkan frekuensi relatif dengan fct_lump_prop().

marks_database |> 
  pull(marks) |> 
  fct_lump_prop(prop = 0.15,
                other_level = "less frequent")
 [1] A             less frequent less frequent less frequent
 [5] less frequent A             C             C            
 [9] less frequent less frequent A             C            
[13] C             less frequent less frequent less frequent
[17] less frequent
Levels: C < A < less frequent

Variabel Kualitatif: Faktor

Kita dapat menerapkan ini pada dataset kita untuk mengkategorikan ulang variabel dengan sangat cepat.

starwars |>  
  drop_na(species) |> 
  mutate(species =
           fct_lump_min(species, min = 3,
                        other_level = "Others")) |>  
  count(species)
# A tibble: 4 × 2
  species     n
  <fct>   <int>
1 Droid       6
2 Gungan      3
3 Human      35
4 Others     39

Variabel Kualitatif: Faktor

Dengan fct_reorder() kita juga dapat menunjukkan bahwa kita ingin mengurutkan faktor sesuai dengan fungsi yang diterapkan pada variabel lain.

starwars_factor <- 
  starwars |>  
  drop_na(height, species) |> 
  mutate(species =
           fct_lump_min(species, min = 3,
                        other_level = "Others"))
starwars_factor |>  pull(species)
 [1] Human  Droid  Droid  Human  Human  Human  Human  Droid  Human 
[10] Human  Human  Human  Others Human  Others Others Human  Others
[19] Human  Human  Droid  Others Human  Human  Others Human  Others
[28] Others Human  Others Human  Human  Gungan Gungan Gungan Human 
[37] Others Others Human  Human  Others Others Others Others Others
[46] Others Others Human  Others Others Others Others Others Others
[55] Others Others Human  Others Others Others Human  Human  Human 
[64] Human  Others Others Others Others Human  Droid  Others Others
[73] Others Others Others Human  Others
Levels: Droid Gungan Human Others
starwars_factor |> 
  mutate(species = fct_reorder(species, height, mean)) |> 
  pull(species)
 [1] Human  Droid  Droid  Human  Human  Human  Human  Droid  Human 
[10] Human  Human  Human  Others Human  Others Others Human  Others
[19] Human  Human  Droid  Others Human  Human  Others Human  Others
[28] Others Human  Others Human  Human  Gungan Gungan Gungan Human 
[37] Others Others Human  Human  Others Others Others Others Others
[46] Others Others Human  Others Others Others Others Others Others
[55] Others Others Human  Others Others Others Human  Human  Human 
[64] Human  Others Others Others Others Human  Droid  Others Others
[73] Others Others Others Human  Others
Levels: Droid Others Human Gungan

💻 Giliranmu

📝 Diberikan variabel months di bawah ini (vektor karakter), konversikan ke faktor.

months <- c("Jan", "Feb", "Mar", "Apr")
Code
months <- c("Jan", "Feb", "Mar", "Apr")
months_fct <- as_factor(months)
months_fct

📝 Diberikan variabel months di bawah ini, konversikan ke faktor dengan menunjukkan level yang benar.

months <- c(NA, "Apr", "Jan", "Oct", "Jul", "Jan", "Sep", NA, "Feb", "Dic",
           "Jul", "Mar", "Jan", "Mar", "Feb", "Apr", "May", "Oct", "Sep",  NA,
           "Dic", "Jul", "Nov", "Feb", "Oct", "Jun", "Sep", "Oct", "Oct", "Sep")
Code
months_fct <-
  factor(months,
         levels = c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dic"))
months_fct

📝 Hitung berapa banyak nilai untuk setiap bulan, ingat ini faktor (mungkin ada level yang tidak digunakan, hasilnya 0).

Code
meses_fct |>  fct_count()

📝 Karena ada nilai hilang, tetapkan level ketiga belas berlabel "missing".

Code
months_fct <- 
  months_fct |> 
  fct_explicit_na(na_level = "missing")
months_fct

📝 Hapus level yang tidak digunakan.

Code
months_fct <- 
  months_fct %>%
  fct_drop()
months_fct

📝 Urutkan level berdasarkan frekuensi kemunculan.

Code
months_fct |> 
  fct_infreq()

📝 Kelompokkan level yang muncul kurang dari 7% ke dalam level "other months".

Code
months_fct <-
  months_fct |> 
  fct_lump_prop(prop = 0.07, other_level = "other months")
months_fct 

🐣 Studi Kasus I: Survei CIS Feminisme

📊 Data

Kita akan bekerja lagi dengan file berisi data dari barometer CIS (Centro de Investigaciones Sociológicas) «Perceptions on equality between men and women and gender stereotypes» whose sample work was carried out from November 6 to 14 (4000 interviews of both sexes over 16 years old in 1174 municipalities and 50 provinces).

 

Coba jawab pertanyaan-pertanyaan yang ada di workbook

L9: dbplyr dan github

dbplyr: Koneksi SQL

Kita akan memperkenalkan paket dbplyr, yang memungkinkan kita menggabungkan kode SQL ke dalam R untuk melakukan kueri database

install.packages("dbplyr")

 

Jika kamu menggunakan R untuk analisis data, sebagian besar data yang dibutuhkan mungkin sudah ada dalam database. Kita akan belajar cara memuat data ke database lokal.

dbplyr: Koneksi SQL

install.packages("RSQLite")

Kita juga perlu menginstal paket backend DBI (antarmuka yang memungkinkan dplyr bekerja dengan banyak database berbeda menggunakan kode yang sama). Lima backend yang umum digunakan adalah:

  • RMariaDB connects to MySQL and MariaDB

  • RPostgres connects to Postgres and Redshift.

  • RSQLite embeds a SQLite database.

  • odbc connects to many commercial databases via the open database connectivity protocol.

  • bigrquery connects to Google’s BigQuery.

Selanjutnya, kita akan menggunakan backend RSQLite (secara otomatis terinstal saat menginstal dbplyr).

dbplyr: Koneksi SQL

Jika kita ingin bekerja dengan database menggunakan tata bahasa dplyr, kita harus terlebih dahulu terhubung ke sana. Koneksi dilakukan dengan DBI::dbConnect(). Argumen DBI::dbConnect() bervariasi dari database ke database, tetapi argumen pertama selalu backend database. SQLite hanya membutuhkan path ke database.

connection <- DBI::dbConnect(RSQLite::SQLite(), dbname = ":memory:")
connection
<SQLiteConnection>
  Path: :memory:
  Extensions: TRUE

Here, the string ":memory:" is a special path that creates a temporary in-memory database.

dbplyr: Koneksi SQL

Database sementara yang dibuat sebelumnya belum memiliki data. Kita akan menyalin database yang ada (misalnya, gapminder dari paket gapminder) menggunakan copy_to(). Menggunakan tbl() kita “mendapatkan” database (disebut sesuai nama dalam copy_to()).

Perbedaan utamanya adalah sekarang ini adalah sumber jarak jauh dalam database SQLite.

copy_to(connection, gapminder::gapminder, overwrite = TRUE, name = "gapminder_database")
gapminder_db <- tbl(connection, "gapminder_database")
gapminder_db
# Source:   table<`gapminder_database`> [?? x 6]
# Database: sqlite 3.50.4 [:memory:]
   country     continent  year lifeExp      pop gdpPercap
   <chr>       <chr>     <int>   <dbl>    <int>     <dbl>
 1 Afghanistan Asia       1952    28.8  8425333      779.
 2 Afghanistan Asia       1957    30.3  9240934      821.
 3 Afghanistan Asia       1962    32.0 10267083      853.
 4 Afghanistan Asia       1967    34.0 11537966      836.
 5 Afghanistan Asia       1972    36.1 13079460      740.
 6 Afghanistan Asia       1977    38.4 14880372      786.
 7 Afghanistan Asia       1982    39.9 12881816      978.
 8 Afghanistan Asia       1987    40.8 13867957      852.
 9 Afghanistan Asia       1992    41.7 16317921      649.
10 Afghanistan Asia       1997    41.8 22227415      635.
# ℹ more rows

dbplyr: Koneksi SQL

Tujuan utama dbplyr adalah secara otomatis menghasilkan SQL dari tata bahasa dplyr yang sudah kita kenal.

gapminder_db |>
  select(country, year, lifeExp)
# Source:   SQL [?? x 3]
# Database: sqlite 3.50.4 [:memory:]
   country      year lifeExp
   <chr>       <int>   <dbl>
 1 Afghanistan  1952    28.8
 2 Afghanistan  1957    30.3
 3 Afghanistan  1962    32.0
 4 Afghanistan  1967    34.0
 5 Afghanistan  1972    36.1
 6 Afghanistan  1977    38.4
 7 Afghanistan  1982    39.9
 8 Afghanistan  1987    40.8
 9 Afghanistan  1992    41.7
10 Afghanistan  1997    41.8
# ℹ more rows

dbplyr: Koneksi SQL

Perbedaan terpenting adalah sekarang kode R kita diterjemahkan ke SQL dan dieksekusi di database di server jarak jauh, bukan di R di mesin lokalmu: tidak pernah menarik data ke R kecuali kamu secara eksplisit memintanya, menunda pekerjaan hingga momen terakhir yang memungkinkan.

Baru saat kita meminta data (menulis gapminder_query di konsol, misalnya), verb dplyr menghasilkan SQL dan meminta hasilnya dari database.

gapminder_query <- 
  gapminder_db |>
  select(country, year, lifeExp)
gapminder_query
# Source:   SQL [?? x 3]
# Database: sqlite 3.50.4 [:memory:]
   country      year lifeExp
   <chr>       <int>   <dbl>
 1 Afghanistan  1952    28.8
 2 Afghanistan  1957    30.3
 3 Afghanistan  1962    32.0
 4 Afghanistan  1967    34.0
 5 Afghanistan  1972    36.1
 6 Afghanistan  1977    38.4
 7 Afghanistan  1982    39.9
 8 Afghanistan  1987    40.8
 9 Afghanistan  1992    41.7
10 Afghanistan  1997    41.8
# ℹ more rows

dbplyr: Koneksi SQL

Apa yang terjadi di balik layar?

dplyr menerjemahkan kode R kita ke verb SQL, yang dapat kita periksa (tanpa melakukan) dengan menggunakan show_query()

gapminder_query |> 
  show_query()
<SQL>
SELECT `country`, `year`, `lifeExp`
FROM `gapminder_database`

dbplyr: Koneksi SQL

Seperti yang dikomentari, kueri database jarak jauh kita tidak ada di R di mesin lokalmu: tidak pernah menarik data ke R kecuali kamu secara eksplisit memintanya. Kamu dapat mengulangi beberapa kali sebelum mengetahui data yang dibutuhkan, lalu gunakan collect().

gapminder_tibble <-
  gapminder_query |> 
  collect()
gapminder_tibble
# A tibble: 1,704 × 3
   country      year lifeExp
   <chr>       <int>   <dbl>
 1 Afghanistan  1952    28.8
 2 Afghanistan  1957    30.3
 3 Afghanistan  1962    32.0
 4 Afghanistan  1967    34.0
 5 Afghanistan  1972    36.1
 6 Afghanistan  1977    38.4
 7 Afghanistan  1982    39.9
 8 Afghanistan  1987    40.8
 9 Afghanistan  1992    41.7
10 Afghanistan  1997    41.8
# ℹ 1,694 more rows

dbplyr: Koneksi SQL

Kamu juga dapat menggunakan translate_sql() untuk menerjemahkan ekspresi individual dari dplyr ke SQL

dbplyr::translate_sql((x + y) / 2, con = connection)
<SQL> (`x` + `y`) / 2.0