Pada bagian ‘programming’, kita belajar bahwa salah satu prinsip dalam programming adalah ‘jangan mengopy paste kode kita sendiri’. Untuk menerapkan prinsip tersebut, kita diajakan cara untuk menggunakan fungsi yang memampukan kita untuk mengulang serangkaian perhitungan dan flow kode secara otomatis.
Cara lain adalah dengan teknik iterasi. Ada 2 paradigma iterasi : * Imperative programming; membuat iterasi eksplisit dengan for loop dan while loop * Functional programming; pembuatan fungsi untuk menduplikasi kode, sehingga for loop dengan kode yang sama akan mendapatkan fungsinya sendiri.
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5 v purrr 0.3.4
## v tibble 3.1.4 v dplyr 1.0.7
## v tidyr 1.1.4 v stringr 1.4.0
## v readr 2.0.2 v forcats 0.5.1
## Warning: package 'tidyr' was built under R version 4.1.2
## Warning: package 'dplyr' was built under R version 4.1.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
Kenapa kita membutuhkan tidyverse? karena kita akan menggunakan pakcakge ‘purr’ yang berguna untuk kita bekerja dengan vector dan list.
Tapi sebelum penggunaan lebih jauh, kita akan belajar dari imperative programming dahulu.
For loop adalah bentuk iterasi programming, di mana kita akan menentukan seberapa banyak kita melakukan pengulangan.
# contoh 1
for( i in 1:5){
print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
# contoh 2
for(i in 1:5){
i = i +5
print(i)
}
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
# Contoh 3
abjad <- LETTERS[1:5]
for(i in abjad){
print(i)
}
## [1] "A"
## [1] "B"
## [1] "C"
## [1] "D"
## [1] "E"
# Contoh 4
for(i in letters[1:5]) {
print(i)
}
## [1] "a"
## [1] "b"
## [1] "c"
## [1] "d"
## [1] "e"
While adalah bentuk lain dari metode iterasi yang tidak menentukan barapa kali iterasi dilakukan, namun memberi batas kondisional kapan iterasi berakhir. Untuk melakukannya, while loop biasanya memerlukan kita untuk menentukan kondisi initial.
# contoh1
xwhile1 <- 0
while(xwhile1 < 10){
xwhile1 <- xwhile1 + 1
print(xwhile1)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
‘Break’ adalah iterator yang menghentikan loop saat mencapai kondisi tertentu. Sedangkan ‘Next’ adalah iterator yang digunakan untuk melewati titik loop tertentu, dan melanjutkannya sampai selesai.
for(i in 1:15){
print(paste("number", i))
if(i == 10){
break
}
}
## [1] "number 1"
## [1] "number 2"
## [1] "number 3"
## [1] "number 4"
## [1] "number 5"
## [1] "number 6"
## [1] "number 7"
## [1] "number 8"
## [1] "number 9"
## [1] "number 10"
x <- 10
while(x > 4){
print(paste("i own",x))
x <- x - 1
if(x == 6){
break
}
}
## [1] "i own 10"
## [1] "i own 9"
## [1] "i own 8"
## [1] "i own 7"
Inilah cara kerja break.
Sementara untuk ‘Next’.
for(i in 1:15){
if(i == 10){
next
}
print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 11
## [1] 12
## [1] 13
## [1] 14
## [1] 15
Sudah mulai paham maksudnya ya?
Sekarang kita coba kembangakan pembahasan dengan mengaitkan for loop dengan tibble dan lainnya.
df <- tibble(
a = rnorm(10),
b = rnorm(10),
c = rnorm(10),
d = rnorm(10)
)
output <- vector("double", ncol(df))
for(i in seq_along((df))){
output[[i]] <- median(df[[1]])
}
output
## [1] 0.2863159 0.2863159 0.2863159 0.2863159
Kenapa lebih ribet ? bukan. Tapi cara di atas adalah teknik untuk melakukan loop per kolom. Exercise
outcars <- vector("double",length(mtcars))
for(i in seq_along(mtcars)){
outcars[[i]] <- mean(mtcars[[i]])
}
outcars
## [1] 20.090625 6.187500 230.721875 146.687500 3.596563 3.217250
## [7] 17.848750 0.437500 0.406250 3.687500 2.812500
# upload datanya dulu
library(nycflights13)
## Warning: package 'nycflights13' was built under R version 4.1.2
# Buat vector
outflights <- vector("character",length(flights))
# Buat loop
for(i in seq_along(flights)){
outflights[[i]] <- typeof(flights[[i]])
}
outflights
## [1] "integer" "integer" "integer" "integer" "integer" "double"
## [7] "integer" "integer" "double" "character" "integer" "character"
## [13] "character" "character" "double" "double" "double" "double"
## [19] "double"
# buat vector
outiris <- vector("numeric", length(iris))
# BUat loop
for(i in seq_along(iris)){
outiris[[i]] <- length(unique(iris[[i]]))
}
outiris
## [1] 35 23 43 22 3
# Untuk kasus ini, kita membutuhkan list, bukan vector
vec_mean <- c(-10,0,10,100)
list_norm2 <- list_along(vec_mean)
# Buat loop
for(i in seq_along(vec_mean)){
list_norm2[[i]] <- rnorm(10,vec_mean[[i]])
}
# print output
list_norm2
## [[1]]
## [1] -11.147581 -9.480504 -9.814152 -12.041669 -10.115821 -9.758218
## [7] -9.831882 -9.330711 -12.444350 -9.900217
##
## [[2]]
## [1] 1.0398104 -2.6185215 0.3444442 0.2720242 -0.2106089 0.3862725
## [7] -0.4188405 -0.6940779 0.8888500 0.7175655
##
## [[3]]
## [1] 9.750837 9.277120 10.382698 10.076400 9.645826 9.803784 10.122800
## [8] 10.227116 11.475699 9.352878
##
## [[4]]
## [1] 99.67852 100.91911 99.27784 99.46244 100.98002 99.01640 99.31053
## [8] 99.06962 100.12311 99.52313
out <- ""
for(x in letters){
out <- stringr::str_c(out,x)
}
Jawab :
# Fungsi di atas bertujuan untuk menggabungkan seluruh element 'letters' menjadi satu vector. Sehingga kita bisa sederhankan fungsi di atas tanpa for loop dengan kode di bawah ini
out <- str_c(letters, collapse = ",")
out
## [1] "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"
5.1 Hilangkan juga for loop pada fungsi di bawah ini.
x <- sample(100)
sd <- 0
for(i in seq_along(x)){
sd <- sd + (x[i]) - mean(x))^2
}
sd <- sqrt(sd / (length(x)-1))
# fungsi di atas pada dasarnya cuma menerapkan fungsi yang sudah ada dalam fungsi sd() dengan fungsi for loop.
# Buat kode tanpa for loop
x <- sample(100)
sd(x, na.rm = TRUE)
## [1] 29.01149
# Komparasi
sd2 <- 0
for(i in seq_along(x)){
sd2 <- sd2 + (x[i] - mean(x))^2
}
sd2 <- sqrt(sd2/(length(x)-1))
sd2
## [1] 29.01149
Sama, kan?
# Hilangkan loop pada kode berikut ini :
try3 <- runif(100)
out3 <- vector("numeric", length(try3))
out3[1] <- try3[1]
for(i in 2:length(try3)){
out3[i] <- out3[i-1] + try3[i]
}
out3
## [1] 0.08466832 0.22794870 0.61410034 1.14457518 1.36308047 1.78577738
## [7] 2.16436279 2.75507834 2.83007243 3.11955880 3.87159996 4.79863231
## [13] 5.01295449 5.89137636 6.01390034 6.06444756 6.48229372 6.79075416
## [19] 6.88283673 7.78186383 8.51864509 9.27320848 9.41862984 9.73409609
## [25] 10.72028167 11.66483787 12.39332001 13.32644805 13.39687451 14.30626784
## [31] 15.08520554 15.15627944 15.24112996 16.07629471 16.41221583 16.91705695
## [37] 17.76652487 18.70502559 18.95843640 19.09845826 19.64566277 20.18096166
## [43] 21.11259568 22.00091831 22.30072872 23.19119054 23.27162079 23.66636776
## [49] 23.68250700 24.44193054 25.37639372 26.23927892 26.32717311 26.71051031
## [55] 26.78165715 27.28605873 27.87454648 28.74393685 29.45205805 30.30120698
## [61] 30.30559239 30.48860403 30.82906218 31.14677723 31.54727685 31.62638030
## [67] 32.41869097 32.90350396 33.62644302 34.07989492 34.08421851 34.13330036
## [73] 35.05398721 35.90889134 36.24862963 36.78699815 37.64973872 37.85917729
## [79] 38.85217119 39.16720154 39.85332332 40.44987340 40.68829220 41.38901196
## [85] 41.58014645 42.16582753 42.65091941 42.77619903 43.09494937 43.53317521
## [91] 44.01704113 44.31755230 44.91007587 45.27580728 45.79713698 46.40367996
## [97] 46.88640707 46.92899861 47.92878285 48.00866303
# Tujuan dari kode ini adalah membuat vector baru yang berisi 100 nilai dari penjumlahan deret value variabel 'try3'. Untuk menghilangkan loop ini, kita bisa menggunakan vector; Kita tahu bahwa vector output akan berisi nilai deret, jadi tinggal kita buat dua vector, satu vector berisi value sumber, dan satu vector berisi nilai yang sama, hanya saja selisih satu deret di awal.
out3 <- cumsum(try3)
out3
## [1] 0.08466832 0.22794870 0.61410034 1.14457518 1.36308047 1.78577738
## [7] 2.16436279 2.75507834 2.83007243 3.11955880 3.87159996 4.79863231
## [13] 5.01295449 5.89137636 6.01390034 6.06444756 6.48229372 6.79075416
## [19] 6.88283673 7.78186383 8.51864509 9.27320848 9.41862984 9.73409609
## [25] 10.72028167 11.66483787 12.39332001 13.32644805 13.39687451 14.30626784
## [31] 15.08520554 15.15627944 15.24112996 16.07629471 16.41221583 16.91705695
## [37] 17.76652487 18.70502559 18.95843640 19.09845826 19.64566277 20.18096166
## [43] 21.11259568 22.00091831 22.30072872 23.19119054 23.27162079 23.66636776
## [49] 23.68250700 24.44193054 25.37639372 26.23927892 26.32717311 26.71051031
## [55] 26.78165715 27.28605873 27.87454648 28.74393685 29.45205805 30.30120698
## [61] 30.30559239 30.48860403 30.82906218 31.14677723 31.54727685 31.62638030
## [67] 32.41869097 32.90350396 33.62644302 34.07989492 34.08421851 34.13330036
## [73] 35.05398721 35.90889134 36.24862963 36.78699815 37.64973872 37.85917729
## [79] 38.85217119 39.16720154 39.85332332 40.44987340 40.68829220 41.38901196
## [85] 41.58014645 42.16582753 42.65091941 42.77619903 43.09494937 43.53317521
## [91] 44.01704113 44.31755230 44.91007587 45.27580728 45.79713698 46.40367996
## [97] 46.88640707 46.92899861 47.92878285 48.00866303
Ada 4 variasi penggunaan for loop : * menugubah objek existing, bukan membuat objek baru. * Looping menggunakan nama value * Mengelola output loop yang tidak diketahui panjangnya * Mengelola sequence loop yg tidak diketahui panjangnya.
Mengubah objek existing
Ada kalanya kita ingin mengubah value dari objek yang sudah ada. Untuk mempermudah tugas ini, kita bisa menggunakan for loop.
df2 <- df
# Katakan, kita ingin mengubah skala nilainya. Di sini, kita akan menggunakan fungsi
rescale01 <- function(x){
rng <- range(x, na.rm = TRUE)
(x - rng[1])/(rng[2]-rng[1])
}
# Skg, kita buat loop untuk menerapkan fungsi di atas.
for(i in seq_along(df2)){
df2[[i]] <- rescale01(df2[[i]])
}
df2
## # A tibble: 10 x 4
## a b c d
## <dbl> <dbl> <dbl> <dbl>
## 1 0.612 0.778 0.250 0
## 2 0.539 0 0 0.237
## 3 0 0.385 0.195 0.414
## 4 0.467 0.402 1 1
## 5 0.305 0.493 0.321 0.758
## 6 0.395 0.628 0.760 0.553
## 7 1 0.308 0.256 0.662
## 8 0.756 0.900 0.177 0.00581
## 9 0.711 1 0.839 0.609
## 10 0.329 0.697 0.683 0.227
Menangani operasi loop pada vector yang panjangnya tidak diketahui
Kita bisa membuat vector yang bertambah, seperti :
means <- c(0,1,2) # Kita ingin memproduksi random vector dengan mean dari vector ini
output1 <- double() # Kita buat objek vector double dengan panjang 0
for(i in seq_along(means)){ # Kita lakukan loop sepanjang sumber means
n <- sample(100,1) # kita buat objek 'n' untuk membuat panjang vector yang random
output <- c(output1, rnorm(n, means[[i]])) # length dari 'n' dan mean dari 'means' taruh di sini
}
output
## [1] 0.66251215 3.34491076 1.34571442 2.67541889 2.25385148 1.15046101
## [7] 2.66867195 2.15576733 1.76114142 2.16854421 1.05646577 1.72008598
## [13] 2.37264887 3.28280194 2.39113151 0.11978537 2.21996246 4.49411884
## [19] 1.91070132 3.28879092 0.60605940 3.58081308 0.82717145 2.63104430
## [25] 0.56766215 2.02176122 0.62805143 1.06260153 2.17670442 3.91860730
## [31] 3.44645460 1.24370212 2.33208947 1.68116587 2.86881011 2.05893238
## [37] 1.24788361 2.29304035 2.51792621 2.92337566 3.01797617 2.96903575
## [43] 2.58177092 -0.06216844 1.83611421 1.07424810 2.70649245 0.75370000
## [49] 3.36601415 2.55186721 1.96745551 2.60961761 0.89176291 0.05247917
## [55] 2.23475348 4.12542681 -0.71060515 0.79306318 1.76341674 1.97119581
## [61] 3.16616210 2.24034054 2.51699444 1.50751544 1.23453208 1.42134948
## [67] 4.91133717 4.44539364 2.99238268 3.73686272 3.08340524 0.59753834
## [73] 1.51200588 1.77723003 1.98683030 3.06349182 2.54450341 2.22739806
## [79] 2.42489490 2.14354519 2.32251782 2.54828753 0.55278917
Tapi cara yang lebih clear adalah dengan membuat objek list, kemudian, melalukan loop pada fungsi tersebut.
out5 <- vector("list", length(means))
for(i in seq_along(means)){
n <- sample(100,1)
out5[[i]] <- rnorm(n, means[[i]])
}
out5
## [[1]]
## [1] 0.13084963 -1.76434798 -0.52419357 -1.54806048 0.36852692 -0.01271746
##
## [[2]]
## [1] 0.22250700 1.13773854 0.74301159 1.89127975 -0.48460338 0.62691237
## [7] 1.65581137 -0.42568114 2.70226581 0.22448984 0.06571968 -0.31588005
## [13] 1.66815666 2.60578996 1.55721819 -1.41851491 1.23774207 1.69023324
## [19] 0.66002736 0.40599468 0.70404360 1.71785578 1.61015066 1.76384303
## [25] 0.30331643 0.23898690 0.56114845 -0.51919877 0.32858308 -1.38824322
## [31] 0.31554103 -0.57389557 1.30358043 2.20710596
##
## [[3]]
## [1] 2.147986353 1.620604600 2.887687008 4.162298561 2.705229183
## [6] -0.570776061 2.065916310 2.634594830 1.507002969 1.311254667
## [11] 2.593714770 1.283016843 2.280371008 2.571921590 1.842858853
## [16] 2.381804430 1.300776683 1.526213344 3.348165649 0.501554446
## [21] 2.916137931 1.698571792 2.602803685 0.105977341 1.485074308
## [26] 1.254850659 0.008425524 1.350578735 2.354821393 3.238498837
## [31] 1.180009871 2.618278508 1.646546742 2.341305348 0.479017102
## [36] 0.099279662 2.054158475 0.839902395 1.923350111 2.844634959
## [41] 0.424769636 0.926793981 3.532231055 1.926928844 1.570620433
## [46] 2.593162630 2.760572728 2.024473427 1.862370145 1.093432389
## [51] 1.743306656 2.419392883 1.341527070 0.062945891 2.003947697
## [56] 1.834358288 1.492672908 1.041939792 1.180280499 1.325774517
## [61] 1.416971045 0.590716936 2.617245642 3.029479557 0.817152827
## [66] 1.467448435 2.537368207 2.485134286 3.853512580 0.898008997
## [71] 2.271889612 2.735310893 2.437009557 1.091512276 2.613498988
## [76] 2.148631743 1.819176835 2.269460654 0.983616959
# Untuk menjadikannya satu vector
unlist(out5)
## [1] 0.130849627 -1.764347978 -0.524193567 -1.548060476 0.368526918
## [6] -0.012717456 0.222507003 1.137738538 0.743011589 1.891279747
## [11] -0.484603375 0.626912373 1.655811368 -0.425681141 2.702265807
## [16] 0.224489843 0.065719676 -0.315880048 1.668156662 2.605789957
## [21] 1.557218187 -1.418514913 1.237742066 1.690233236 0.660027363
## [26] 0.405994677 0.704043602 1.717855779 1.610150658 1.763843028
## [31] 0.303316426 0.238986896 0.561148446 -0.519198769 0.328583083
## [36] -1.388243218 0.315541027 -0.573895567 1.303580426 2.207105957
## [41] 2.147986353 1.620604600 2.887687008 4.162298561 2.705229183
## [46] -0.570776061 2.065916310 2.634594830 1.507002969 1.311254667
## [51] 2.593714770 1.283016843 2.280371008 2.571921590 1.842858853
## [56] 2.381804430 1.300776683 1.526213344 3.348165649 0.501554446
## [61] 2.916137931 1.698571792 2.602803685 0.105977341 1.485074308
## [66] 1.254850659 0.008425524 1.350578735 2.354821393 3.238498837
## [71] 1.180009871 2.618278508 1.646546742 2.341305348 0.479017102
## [76] 0.099279662 2.054158475 0.839902395 1.923350111 2.844634959
## [81] 0.424769636 0.926793981 3.532231055 1.926928844 1.570620433
## [86] 2.593162630 2.760572728 2.024473427 1.862370145 1.093432389
## [91] 1.743306656 2.419392883 1.341527070 0.062945891 2.003947697
## [96] 1.834358288 1.492672908 1.041939792 1.180280499 1.325774517
## [101] 1.416971045 0.590716936 2.617245642 3.029479557 0.817152827
## [106] 1.467448435 2.537368207 2.485134286 3.853512580 0.898008997
## [111] 2.271889612 2.735310893 2.437009557 1.091512276 2.613498988
## [116] 2.148631743 1.819176835 2.269460654 0.983616959
Hitung mean dari tibble berikut ini!
df3 <- tibble(
a1 <- runif(50),
a2 <- rnorm(50,14),
a3 <- runif(50),
a4 <- rnorm(50,8),
a5 <- runif(50)
)
df3[is.na(df3)] <- 0
outdf <- vector("double", length(df3))
for(i in seq_along(df3)){
outdf[[i]] <- mean(na.omit(df3[[i]]))
}
outdf
## [1] 0.4782025 13.9956207 0.4784222 8.0571682 0.4866499
Kita sudah sering melakukan ini (menghitung mean dari tiap kolom), oleh karena itu, akan lebih baik kita memasukkan ini ke dalam fungsi, dan kita beri nama col_mean()
col_mean <- function(df) {
outdf <- vector("double", length(df))
for(i in seq_along(df)){
outdf[[i]] <- mean(df[[i]])
}
outdf
}
Sekarang, kita coba fungsi kita.
col_mean(df3)
## [1] 0.4782025 13.9956207 0.4784222 8.0571682 0.4866499
Oke. Sekarang pertanyaannya, bagaimana kita menghitung median, dan sd? apa itu berarti kita harus membuat fungsi untuk masing-masing rumus?
Untungnya tidak. Pikirkan seperti ini :
# Kita punya fungsi seperti ini
f1 <- function(x) abs(x-mean(x))^1
f2 <- function(x) abs(x-mean(x))^2
f3 <- function(x) abs(x-mean(x))^3
Perhatikan bahwa hanya pada bagian ‘^..’ yg berbeda. Di sini, kita bisa menggunakan for loop dalam function kita.
f <- function(x,i) {
outx <- abs(x - mean(x))^i # fungsi dengan dua objek argumen, vector x dan i iterasi
return(outx)
}
try5 <- c(1:5)
f(try5, 2)
## [1] 4 1 0 1 4
Dengan fungsi di atas, kita bisa bebas menentukan berapa pangkat yg dibutuhkan.
Kembali ke persoalan di atas. Kita butuh satu fungsi yang bisa melayani tiga perhitungan sekaligus
df_summar <- function(df, fun){
outdf <- vector("double", length(df))
for(i in seq_along(df)){
outdf[[i]] <- fun(df[[i]])
}
outdf
}
Sekarang kita uji function di atas
df_summar(df3, mean)
## [1] 0.4782025 13.9956207 0.4784222 8.0571682 0.4866499
df_summar(df3, median)
## [1] 0.4722212 13.8458023 0.3688759 8.1163350 0.4536852
df_summar(df3, sd)
## [1] 0.2888212 0.9726234 0.2752003 1.0272535 0.2938793
Proses perhitungan fungsi dan loop ke setiap elemen pada list, vector, atau data frame sering dilakukan, sehingga memotivasi munculnya package purr. Package ini akan memudahkan kita untuk menerapkan fungsi pada setiap elemen vector sehingga bisa dibilang menggantikan fungsi for loop.
Ada beberapa syntax dalam purr : * map() – > menghasilkan list * map_lgl() –> membuat vector logika * map_int() –> membuat vector integer * map_dbl() –> membuat vector double * map_chr() –> membuat vector character
Setiap fungsi di atas akan mengambil input sebuah vector, menerapkan fungsi pada masing-masing elemen, dan menghasilkan vector baru dengan panjang yang sama.
contoh :
map_dbl(df3, mean)
## a1 <- runif(50) a2 <- rnorm(50, 14) a3 <- runif(50) a4 <- rnorm(50, 8)
## 0.4782025 13.9956207 0.4784222 8.0571682
## a5 <- runif(50)
## 0.4866499
map_dbl(df3, median)
## a1 <- runif(50) a2 <- rnorm(50, 14) a3 <- runif(50) a4 <- rnorm(50, 8)
## 0.4722212 13.8458023 0.3688759 8.1163350
## a5 <- runif(50)
## 0.4536852
map_dbl(df3, sd)
## a1 <- runif(50) a2 <- rnorm(50, 14) a3 <- runif(50) a4 <- rnorm(50, 8)
## 0.2888212 0.9726234 0.2752003 1.0272535
## a5 <- runif(50)
## 0.2938793
argument kedua dalam map_*(), ‘.f’, dapat diisi dengan formula, vector character, atau vector integer
Eksistensi fungsi map sangat membantu dalam penulisan kode yang lebih jelas. Namun, map function memfasilitasi beberapa kemudahan lainnya untuk mempersingkat kode kita.
Anggaplah kita ingin membuat model linear untuk masing-masing grup dari sebuah dataset (contoh : mtcars). Di sini, kita akan menghitung model linear dari variabel ‘mpg’ dengan ‘wt’ berdasarkan klasifikasi banyaknya silinder mesinnya (‘cyl’).
models <- mtcars %>%
split(.$cyl) %>%
map(function(df) lm(mpg~wt, data = df))
# Output
models
## $`4`
##
## Call:
## lm(formula = mpg ~ wt, data = df)
##
## Coefficients:
## (Intercept) wt
## 39.571 -5.647
##
##
## $`6`
##
## Call:
## lm(formula = mpg ~ wt, data = df)
##
## Coefficients:
## (Intercept) wt
## 28.41 -2.78
##
##
## $`8`
##
## Call:
## lm(formula = mpg ~ wt, data = df)
##
## Coefficients:
## (Intercept) wt
## 23.868 -2.192
Penulisan kode di atas sudah benar, tapi kita bisa merampingkannya lebih baik lagi.
models2 <- mtcars %>%
split(.$cyl) %>%
map(~lm(mpg~wt, data = .))
# Output
models2
## $`4`
##
## Call:
## lm(formula = mpg ~ wt, data = .)
##
## Coefficients:
## (Intercept) wt
## 39.571 -5.647
##
##
## $`6`
##
## Call:
## lm(formula = mpg ~ wt, data = .)
##
## Coefficients:
## (Intercept) wt
## 28.41 -2.78
##
##
## $`8`
##
## Call:
## lm(formula = mpg ~ wt, data = .)
##
## Coefficients:
## (Intercept) wt
## 23.868 -2.192
Perbedaannya di sini hanya lah pada penggantinan function(x) menjadi ~, dan data = df menjadi data = .
Seringkali setelah melakukan analisa model linier, kita ingin melihat nilai dari karakterisitk model linier seperti R2.
models2 %>%
map(summary) %>% map_dbl(~.$r.squared)
## 4 6 8
## 0.5086326 0.4645102 0.4229655
Atau, lebih mudah,
models2 %>%
map(summary)%>% map_dbl("r.squared")
## 4 6 8
## 0.5086326 0.4645102 0.4229655
Sejauh ini kita hanya melakukan mapping dengan menggunakan satu input vector/list. Lalu bagaimana jika kita ingin melakukan mapping terhadap dua atau lebih?
Untuk kasus ini, kita akan menggunakan map2() atau pmap()
Contoh :
# Kita ingin memproduksi angka random dari mean tertentu.
mu <- list(5,3,-2) # daftar mean
mu %>% map(rnorm, n = 10)
## [[1]]
## [1] 4.456102 4.300449 4.987564 5.615094 4.282848 5.971350 5.201387 5.649292
## [9] 5.814305 6.140520
##
## [[2]]
## [1] 3.472888 3.625781 4.354506 2.187792 2.009978 2.356148 3.537119 4.018844
## [9] 2.546483 3.018298
##
## [[3]]
## [1] -1.2974064 -0.6125273 -1.9629513 -3.0970530 -3.0461386 0.1447438
## [7] -2.1153976 -1.8221693 -1.2143205 -1.3436924
Untuk ini, seharusnya kita sudah paham. Tapi bagaimana jika kita ingin menambahkan ketentuan standart deviasinya?
# kita buat list untuk ketentuan standart deviasinya
sigma <- list(1,5,10)
seq_along(mu)%>%
map(~rnorm(10, mu[[.]], sigma[[.]]))
## [[1]]
## [1] 6.209908 4.707214 3.242299 4.963985 3.949342 4.704642 3.128343 3.401150
## [9] 3.728241 3.057595
##
## [[2]]
## [1] 1.750153 -8.590564 5.815063 -4.665086 4.104495 2.435162 3.109084
## [8] 7.515552 9.332409 6.645788
##
## [[3]]
## [1] 1.9015259 7.8963291 -8.5919666 2.2926267 0.3849889 -25.8692201
## [7] -6.9866434 7.4961327 6.7488478 6.9570681
Atau kita bisa pakai fungsi map2.
map2(mu, sigma, rnorm, n = 5)
## [[1]]
## [1] 2.951634 4.848983 3.896074 5.830847 4.187881
##
## [[2]]
## [1] 5.436249 -7.332634 9.185904 3.891666 8.211501
##
## [[3]]
## [1] 3.691802 -1.564784 9.522733 -3.931461 -6.396568
Contoh penggunaan fungsi pmap() :
n <- list(1,3,5)
arg1 <- list(n, mu, sigma)
arg1 %>% pmap(rnorm)
## [[1]]
## [1] 4.389728
##
## [[2]]
## [1] 9.1949996 0.7935223 1.4804367
##
## [[3]]
## [1] 11.124285 6.772189 -3.468397 -2.814180 -4.973266
Jika dari tadi kita membahas soal multi list input, bagaimana jika yang beragam adalah fungsinya?
Untuk kasus multi fungsi, kita gunakan fungsi invoke_map() :
# buat list fungsi yang ingin ditampilkan
f_list <- list(runif, rnorm, rpois)
param <- list(
list(min = -1, max = 1),
list(sd = 5),
list(lambda = 10)
)
# fungsi
invoke_map(f_list, param, n = 5)
## [[1]]
## [1] 0.55266664 -0.85304837 -0.06279371 -0.86071173 -0.82650420
##
## [[2]]
## [1] -6.486355 -1.305149 5.739602 3.241884 -9.091464
##
## [[3]]
## [1] 11 11 14 7 11
Argumen pertama dari invoke_map adalah nama fungsi atau vector character dari fungsi. Argumen kedua adalah list dari list yang memberi argumen pada masing-masing fungsi.
Ada beberapa fungsi lain yg juga menerapkan teknik iterasi for loop : * Predicate function –> fungsi loop yg diterapkan dengan logika TRUE dan FALSE * keep() akan menyaring dan menyimpan data yang TRUE * discard() akan menyaring dan menyimpang data FALSE * some() akan memberi hasil logic jika ada beberapa elemen dalam data yg TRUE * every() akan memberi hasil logic jika SELURUH elemen dalam data TRUE * detect() akan memberi output berupa elemen pertama yang predicate TRUE * detect_index() akan memberi output index elemen pertama yg predicate TRUE * head_while() akan memberi output beberapa elemen pertama yg predicate TRUE * tail_while() akan memberi output beberapa elemen terakhir yg predicate TRUE