Memahami Fungsi apply, sapply, lapply dan tapply

Fungsi apply, sapply, lapply dan tapply adalah fungsi-fungsi penting dalam bahasa pemrograman R. Keempatnya memungkinkan kita untuk menerapkan operasi pada setiap elemen atau kelompok elemen dalam objek vektor, matriks maupun dataframe. Pada tutorial ini, kita akan membahas secara rinci keempat fungsi ini dan bagaimana penerapannya dalam berbagai skenario.

apply

Fungsi apply memungkinkan Anda untuk menerapkan fungsi ke setiap baris atau kolom dalam matriks atau ke setiap elemen dalam vektor. Format umum penggunaannya adalah apply(objek, margin, fungsi), dimana:

  • objek: objek yang ingin kita aplikasikan fungsi kepadanya (misalnya, matriks, vektor).

  • margin: argumen untuk menentukan dimensi yang akan diterapkan pada fungsi (1 untuk baris, 2 untuk kolom atau c(1, 2) untuk aplikasi ke setiap elemen).

  • fungsi: fungsi yang akan terapkan pada setiap baris atau kolom (dapat berupa fungsi built-in atau fungsi buatan pengguna).

Di bawah ini disajikan beberapa penerapan fungsi apply untuk berbagai kondisi.

apply untuk setiap elemen

Pada contoh pertama, fungsi apply digunakan untuk mecari nilai akar kuadrat dari setiap elemen dataframe. Karena operasi akan dilakukan untuk setiap elemen, maka argumen dari parameter MARGIN kita isi dengan nilai c(1, 2). Fungsi apply akan mengembalikan nilai hasil akar kuadrat dalam bentuk tipe data matrix.

data <- data.frame(
  Nilai.1 = c(72, 65, 80, 77, 85, 61, 78, 73, 82, 56),
  Nilai.2 = c(87, 73, 69, 82, 88, 68, 70, 75, 84, 86),
  Nilai.3 = c(92, 85, 74, 98, 79, 90, 83, 77, 95, 84)
)

data
##    Nilai.1 Nilai.2 Nilai.3
## 1       72      87      92
## 2       65      73      85
## 3       80      69      74
## 4       77      82      98
## 5       85      88      79
## 6       61      68      90
## 7       78      70      83
## 8       73      75      77
## 9       82      84      95
## 10      56      86      84
# mengambil akar kuadrat setiap dengan fungsi apply
data.sqrt <- apply(data, MARGIN = c(1, 2), FUN = sqrt)

cat("\n Nilai Kuadrat:\n")
## 
##  Nilai Kuadrat:
data.sqrt
##        Nilai.1  Nilai.2  Nilai.3
##  [1,] 8.485281 9.327379 9.591663
##  [2,] 8.062258 8.544004 9.219544
##  [3,] 8.944272 8.306624 8.602325
##  [4,] 8.774964 9.055385 9.899495
##  [5,] 9.219544 9.380832 8.888194
##  [6,] 7.810250 8.246211 9.486833
##  [7,] 8.831761 8.366600 9.110434
##  [8,] 8.544004 8.660254 8.774964
##  [9,] 9.055385 9.165151 9.746794
## [10,] 7.483315 9.273618 9.165151
class(data.sqrt) 
## [1] "matrix" "array"

Contoh ke-2 di bawah ini, kita menggunakan fungsi apply untuk membuat matriks berisi label grade berdasarkan kriteria tertentu. Karena fungsi yang digunakan lebih rumit, maka dapat ditulis dalam fungsi tersendiri dan kemudian dikirimkan sebagai argumen pada fungsi apply. Pada bagian ini, operasi juga dilakukan untuk setiap elemen, sehingga parameter MARGIN diatur dengan nilai c(1, 2).

get.grade <- function(nilai) {
  if (nilai > 90) "A"
  else if (nilai > 70) "B"
  else if (nilai > 50) "C"
  else "D"
}

data.grade <- apply(data, c(1, 2), get.grade)

data.grade
##       Nilai.1 Nilai.2 Nilai.3
##  [1,] "B"     "B"     "A"    
##  [2,] "C"     "B"     "B"    
##  [3,] "B"     "C"     "B"    
##  [4,] "B"     "B"     "A"    
##  [5,] "B"     "B"     "B"    
##  [6,] "C"     "C"     "B"    
##  [7,] "B"     "C"     "B"    
##  [8,] "B"     "B"     "B"    
##  [9,] "B"     "B"     "A"    
## [10,] "C"     "B"     "B"

apply untuk baris dan kolom

Selain penerapannya untuk operasi elemen per elemen, fungsi apply juga dapat digunakan untuk melakukan operasi menurut baris dan kolom. Dengan mengatur nilai MARGIN=1, akan membuat operasi dilakukan baris-per-baris. Sementara nilai MARGIN=2 akan membuat operasi dilakukan kolom-per-kolom.

Pada contoh di bawah ini, variabel mean.per.baris menampung output dari fungsi apply yang dilakukan menurut baris. Berdasarkan output yang diperoleh, dapat dilihat bahwa variabel ini berisi nilai rata-rata (Nilai.1, Nilai.2 dan Nilai.3) untuk setiap barisnya. Begitu pula dengan variabel mean.per.kolom yang akan menyimpan output nilai rata-rata pada setiap kolomnya.

# Menghitung Rata-rata per Baris dan per Kolom

mean.per.baris <- apply(data, 1, mean)
mean.per.kolom <- apply(data, 2, mean)

cat("\n Rata-rata per baris:\n\n")
## 
##  Rata-rata per baris:
mean.per.baris
##  [1] 83.66667 74.33333 74.33333 85.66667 84.00000 73.00000 77.00000 75.00000
##  [9] 87.00000 75.33333
cat("\n Rata-rata per kolom:\n\n")
## 
##  Rata-rata per kolom:
mean.per.kolom
## Nilai.1 Nilai.2 Nilai.3 
##    72.9    78.2    85.7

Misal dari data sebelumnya, akan ditentukan nilai final yang dihitung dengan komposisi 50% Nilai.1 + 30% Nilai.2 + 20% Nilai.3. Kita dapat membuat kolom baru untuk menyimpan nilai final tersebut menggunakan fungsi apply. Karena ingin mencari nilai final untuk setiap baris, maka kita atur parameter MARGIN=1.

# Menghitung skor final dengan formula : 50%*Nilai.1 + 30%*Nilai.2 + 20%*Nilai.3

get.final <- function(nilai) {
    skor.final <- 0.5*nilai['Nilai.1'] + 0.3*nilai['Nilai.2'] + 0.2*nilai['Nilai.3']
    return(skor.final)
}

data["Skor.Final"] = apply(data, 1, get.final)

data
##    Nilai.1 Nilai.2 Nilai.3 Skor.Final
## 1       72      87      92       80.5
## 2       65      73      85       71.4
## 3       80      69      74       75.5
## 4       77      82      98       82.7
## 5       85      88      79       84.7
## 6       61      68      90       68.9
## 7       78      70      83       76.6
## 8       73      75      77       74.4
## 9       82      84      95       85.2
## 10      56      86      84       70.6

Misalkan ingin dilihat juga 3 nilai tertinggi pada masing-masing kolom. Kita dapat menggunakan fungsi apply dan menerapkannya pada kolom-per-kolom. Sebagai contoh, output yang diperoleh untuk kolom Nilai.1 adalah 85, 82, dan 80, kolom Nilai.2 adalah 88, 87, dan 86, san seterusnya sampai dengan kolom Skor.Final.

get.bigthree <- function(nilai.i) {
  return(sort(nilai.i, decreasing = TRUE)[1:3])
}

big.three.bycol <- apply(data, 2, get.bigthree)

cat("\nTiga Nilai Tertinggi untuk Setiap Kolom:\n\n")
## 
## Tiga Nilai Tertinggi untuk Setiap Kolom:
big.three.bycol
##      Nilai.1 Nilai.2 Nilai.3 Skor.Final
## [1,]      85      88      98       85.2
## [2,]      82      87      95       84.7
## [3,]      80      86      92       82.7

sapply

Fungsi sapply bisa dikatakan sebagai bentuk lebih sederhana dari fungsi apply. Di dalam fungsi sapply kita tidak perlu menentukan nilai parameter MARGIN karena secara umum sapply akan bekerja pada setiap elemen. Output yang dihasilkan oleh fungsi sapply juga sama seperti apply yaitu dengan tipe data matrix atau vector.

Pada contoh ke-6 berikut ini, disajikan sintaks penggunaan sapply untuk mendapatkan nilai akar kuadrat dari sekumpulan data. Contoh ini juga setara dengan sintaks pada contoh 1 yang menggunakan fungsi apply. Dengan cara yang sama, silahkan coba gunakan fungsi sapply untuk menghasilkan output seperti pada contoh 2.

data.sqrt.sapply <- sapply(data, sqrt)

cat("\n Nilai akar kuadrat dengan sapply:\n\n")
## 
##  Nilai akar kuadrat dengan sapply:
data.sqrt.sapply
##        Nilai.1  Nilai.2  Nilai.3 Skor.Final
##  [1,] 8.485281 9.327379 9.591663   8.972179
##  [2,] 8.062258 8.544004 9.219544   8.449852
##  [3,] 8.944272 8.306624 8.602325   8.689074
##  [4,] 8.774964 9.055385 9.899495   9.093954
##  [5,] 9.219544 9.380832 8.888194   9.203260
##  [6,] 7.810250 8.246211 9.486833   8.300602
##  [7,] 8.831761 8.366600 9.110434   8.752143
##  [8,] 8.544004 8.660254 8.774964   8.625543
##  [9,] 9.055385 9.165151 9.746794   9.230385
## [10,] 7.483315 9.273618 9.165151   8.402381

Contoh lainnya, fungsi sapply juga dapat digunakan untuk membuat kolom baru pada dataframe berdasarkan nilai kolom lainnya. Misalkan status kelulusan ditentukan dari skor final dengan ketentuan nilai > 80 dinyatakan lulus; nilai antara 70 - 80 lulus bersyarat; dan kurang dari sama dengan 60 dinyatakan tidak lulus.

status.lulus <- function(skor) {
  if (skor > 80) "LULUS"
  else if (skor > 70) "LULUS BERSYARAT"
  else "TIDAK LULUS"
}

data$Status <- sapply(data$Skor.Final, status.lulus)

data
##    Nilai.1 Nilai.2 Nilai.3 Skor.Final          Status
## 1       72      87      92       80.5           LULUS
## 2       65      73      85       71.4 LULUS BERSYARAT
## 3       80      69      74       75.5 LULUS BERSYARAT
## 4       77      82      98       82.7           LULUS
## 5       85      88      79       84.7           LULUS
## 6       61      68      90       68.9     TIDAK LULUS
## 7       78      70      83       76.6 LULUS BERSYARAT
## 8       73      75      77       74.4 LULUS BERSYARAT
## 9       82      84      95       85.2           LULUS
## 10      56      86      84       70.6 LULUS BERSYARAT

lapply

Fungsi lapply memiliki cara kerja yang sama dengan sapply. Perbedaan utamanya yaitu hanya pada tipe data dari output yang dihasilkan. Fungsi lapply akan menghasilkan output dengan tipe list.

Pada contoh berikut, ditampilkan penggunaan fungsi lapply untuk menghitung nilai rata-rata dan standar deviasi dari kolom-kolom numerik pada objek data.

mean.scores <- lapply(data[,-5], mean)
sd.scores <- lapply(data[,-5], sd)

cat("\nRata-rata skor:\n\n")
## 
## Rata-rata skor:
mean.scores
## $Nilai.1
## [1] 72.9
## 
## $Nilai.2
## [1] 78.2
## 
## $Nilai.3
## [1] 85.7
## 
## $Skor.Final
## [1] 77.05
cat("\n\nStandar deviasi skor:\n\n")
## 
## 
## Standar deviasi skor:
sd.scores
## $Nilai.1
## [1] 9.5038
## 
## $Nilai.2
## [1] 7.997222
## 
## $Nilai.3
## [1] 7.91693
## 
## $Skor.Final
## [1] 5.947408

Sebagai contoh terakhir, berikut adalah sintaks untuk mencari 3 nilai tertinggi pada masing-masing kolom numerik menggunakan lapply. Kita akan menggunakan fungsi get.bigthree yang sudah dibuat sebelumnya pada contoh 5. Output yang ditampilkan juga menunjukkan bagaimana perbedaan tipe data output saat menggunakan lapply dibandingkan dengan sapply pada Contoh 5.

big.three.lapply <- lapply(data[,-5], get.bigthree)

big.three.lapply
## $Nilai.1
## [1] 85 82 80
## 
## $Nilai.2
## [1] 88 87 86
## 
## $Nilai.3
## [1] 98 95 92
## 
## $Skor.Final
## [1] 85.2 84.7 82.7

tapply

Selain apply, sapply dan tapply terdapat satu fungsi lagi yang dapat digunakan untuk pemrosesan data pada bahasa R yaitu tapply. Fungsi ini memiliki cara kerja yang agak berbeda dari ketiga fungsi sebelumnya karena fungsi diterapkan menurut kelompok atau faktor tertentu di dalam data.

Pada contoh berikut, fungsi tapply diterapkan pada kolom Skor.Final untuk menghitung nilai rata-ratanya menurut kelompok status.

mean.by.group <- tapply(data$Skor.Final, data$Status, mean)

mean.by.group
##           LULUS LULUS BERSYARAT     TIDAK LULUS 
##          83.275          73.700          68.900

Contoh selanjutnya, kita dapat menerapkan fungsi yang lebih kompleks dan mengembalikan nilai yang kompleks pula. Misalkan untuk menghitung beberapa ringkasan statistik dari data menurut kelompok status.

get.summary <- function(nilai) {
  count <- length(nilai)
  min <- min(nilai)
  avg <- mean(nilai)
  med <- median(nilai)
  max <- max(nilai)
  return(list(count=count, min=min, avg=avg, med=med, max=max))
}

summary.by.group <- tapply(data$Skor.Final, data$Status, get.summary)

summary.by.group
## $LULUS
## $LULUS$count
## [1] 4
## 
## $LULUS$min
## [1] 80.5
## 
## $LULUS$avg
## [1] 83.275
## 
## $LULUS$med
## [1] 83.7
## 
## $LULUS$max
## [1] 85.2
## 
## 
## $`LULUS BERSYARAT`
## $`LULUS BERSYARAT`$count
## [1] 5
## 
## $`LULUS BERSYARAT`$min
## [1] 70.6
## 
## $`LULUS BERSYARAT`$avg
## [1] 73.7
## 
## $`LULUS BERSYARAT`$med
## [1] 74.4
## 
## $`LULUS BERSYARAT`$max
## [1] 76.6
## 
## 
## $`TIDAK LULUS`
## $`TIDAK LULUS`$count
## [1] 1
## 
## $`TIDAK LULUS`$min
## [1] 68.9
## 
## $`TIDAK LULUS`$avg
## [1] 68.9
## 
## $`TIDAK LULUS`$med
## [1] 68.9
## 
## $`TIDAK LULUS`$max
## [1] 68.9

Sumber: Menguasai Fungsi apply, sapply, lapply dan tapply pada Bahasa R - SAINSDATA.ID