Pemrograman Fungsi R dan OOP

Annebel Diestya Clarissa

3/17/2021

Membuat Fungsi Baru dalam R

Fungsi yang masih belum tersedia dalam R dapat kita buat sendiri sesuai dengan kebutuhan. Template nya adalah :

namafungsi <- function (argumen) { isifungsi return(value)}

  • Argumen

Karakteristik :
1. Bisa berisi satu atau lebih dan bisa tidak ada argumen
2. Argumen bisa juga diberikan suatu nilai default, misal function (x=10)
3. Didefinisikan berulang atau tidak dengan menggunakan “…”. Contoh : function(x=10,...)
4. Argumen dapat menerima fungsi R lain. misal : apply(x,1,mean)

  • Isi Fungsi

Karakteristik :
1. Isi fungsi merupakan satu objek data.
2. Jika membutuhkan beberapa baris, dapat dikelompokkan dengan {} dan diakhiri dengan satu objek data
3. Komentar dituliskan dengan awalan # dan tidak akan dieksekusi

  • Output

Karakteristik :

  1. Fungsi harus memiliki output yang dikembalikan

  2. Output merupakan suatu objek

  3. Dapat langsung dituliskan objeknya atau menggunakan return

  4. Jika memiliki mode berbeda, digunakan object list. Contoh:

    fungsi1 <- function (x) { … list (hasil1 , hasil2 ) } fungsi2 <- function (x) { … return ( list (hasil1 , hasil2 )) }


Untuk menggunakan fungsi yang telah dibuat dengan cara :

namafungsi (arg1, arg2,…)

Contoh Pembuatan dan Penggunaan Fungsi Baru

#membuat fungsi baru
angka_acak1=function(n,pw) {
  x=runif(n)
  y=runif(n)
  z=(x+y)^pw
return(z)
}

#menggunakan fungsi baru
angka_acak1(10,2)
##  [1] 0.4046073 1.2672073 2.5443188 1.0943652 0.8401729 0.6548883 1.4720642
##  [8] 0.9428687 0.8586727 0.7093297

Return menggunakan object list

#return menggunakan object list
angka_acak2=function(n,pw) {
  x=runif(n)
  y=runif(n)
  z=(x+y)^pw
return(list(x=x,y=y,z=z))
}

angka_acak2(10,2)
## $x
##  [1] 0.90951526 0.03459733 0.86592606 0.65723122 0.84838157 0.95331140
##  [7] 0.89185302 0.24328161 0.70367122 0.09065768
## 
## $y
##  [1] 0.8818494 0.2343555 0.5689263 0.5419852 0.1496842 0.5351268 0.2974807
##  [8] 0.2174779 0.1122006 0.6793006
## 
## $z
##  [1] 3.2089875 0.0723356 2.0588014 1.4381201 0.9961352 2.2154484 1.4145147
##  [8] 0.2122994 0.6656469 0.5928358

Argumen menggunakan nilai default

#argumen menggunakan nilai default
angka_acak3=function(n=10,pw=2) {
  x=runif(n)
  y=runif(n)
  z=(x+y)^pw
return(z)
}

angka_acak3()
##  [1] 1.0111672 0.8550076 1.7487855 1.7313907 0.2627943 2.0075324 0.4198806
##  [8] 0.3031140 0.8421742 0.9065769

Argumen didefinisikan terlebih dahulu sebelum memanggil fungsi baru

angka_acak4=function(){
  x=runif(n)
  y=runif(n)
  z=(x+y)^pw
return(z)
}

#argumen di definisikan terlebih dahulu sebelum memanggil fungsi baru
n <-5; pw <-3
angka_acak4()
## [1] 0.38820230 2.79573768 0.04647987 1.36769416 0.23816756

Latihan Pembuatan Fungsi

  1. Buatlah fungsi untuk mencari median dari suatu vektor
med<-function(vect) {
  n <-length(vect)
  vects<-sort(vect)
  if(n%%2 == 1) {m <-vects[(n+1)/2]}
  else{m <-(vects[n/2]+vects[(n/2)+1])/2}
return(m)
}

x1<-c(1,5,3,7,3,4,2,7) #input vektor yang akan dicari mediannya
med(x1)
## [1] 3.5
  1. Buatlah fungsi untuk mencari modus dari suatu vektor
modus <-function(vect) {
  v <-unique(vect)
  f <-NULL
  for(i in v) {
    byk<-sum(vect==i)
    f <-c(f,byk)
  }
  fmax<-max(f)
  vf<-cbind(v,f)
  mode <-vf[f==fmax,]
return(mode)
}

modus(x1)
##      v f
## [1,] 3 2
## [2,] 7 2
  1. Buatlah fungsi untuk menduga parameter pada regresi berganda
p.est<-function(A){
  if(!is.matrix(A))
  stop("input must be on matrix")
  x1<-A[,-1]
  y <-A[,1]
  one<-rep(1,nrow(A))
  x <-cbind(one,x1)
  colnames(x)<-paste("x",1:ncol(x),sep="")
  b.est<-as.vector(solve(t(x) %*% x) %*% (t(x) %*% y))
  names(b.est)<-paste("b",0:(length(b.est)-1),sep="")
  fitted.value<-as.vector(x%*%b.est)
  error<-as.vector(y-fitted.value)
  names(fitted.value)<-names(error)<-1:nrow(A)
list(beta.est=b.est,fit.val=fitted.value,error=error)
}

Pendapatan<-c(3.5,3.2,3.0,2.9,4.0,2.5,2.3)
Biaya.Iklan<-c(3.1,3.4,3.0,3.2,3.9,2.8,2.2)
Jumlah.Warung<-c(30,25,20,30,40,25,30)

X<-cbind(Pendapatan,Biaya.Iklan,Jumlah.Warung)

p.est(X) #memanggil fungsi
## $beta.est
##          b0          b1          b2 
## -0.21381852  0.89843390  0.01745279 
## 
## $fit.val
##        1        2        3        4        5        6        7 
## 3.094910 3.277176 2.830539 3.184754 3.988185 2.738116 2.286320 
## 
## $error
##           1           2           3           4           5           6 
##  0.40508982 -0.07717642  0.16946108 -0.28475357  0.01181483 -0.23811608 
##           7 
##  0.01368033

Jika dibandingkan hasilnya dengan fungsi lm yang sudah ada

#membandingkan dengan fungsi lm

Pendapatan<-c(3.5,3.2,3.0,2.9,4.0,2.5,2.3)
Biaya.Iklan<-c(3.1,3.4,3.0,3.2,3.9,2.8,2.2)
Jumlah.Warung<-c(30,25,20,30,40,25,30)

model<-lm(Pendapatan~Biaya.Iklan+Jumlah.Warung)
model$coefficients
##   (Intercept)   Biaya.Iklan Jumlah.Warung 
##   -0.21381852    0.89843390    0.01745279
model$fitted.values
##        1        2        3        4        5        6        7 
## 3.094910 3.277176 2.830539 3.184754 3.988185 2.738116 2.286320
model$residuals
##           1           2           3           4           5           6 
##  0.40508982 -0.07717642  0.16946108 -0.28475357  0.01181483 -0.23811608 
##           7 
##  0.01368033

Object Oriented Programming

R adalah bahasa pemrograman yang berbasis objek (PBO). PBO menitikberatkan pada identifikasi objek-objek yang terlibat dalam sebuah program dan bagaimana objek-objek tersebut berinteraksi. Pada PBO, program yang dibangun akan dibagi-bagi menjadi objek-objek.

Prinsip dari PBO adalah :

  1. Abstraksi adalah suatu cara melihat suatu objek dalam bentuk yang sederhana. Sebagai contoh jika kita melihat sepeda motor. Kita tidak perlu melihat susunan komponen mesin dan dukungan elektriknya yang cukup kompleks dan rumit, namun kita bisa melihat sepeda motor itu sebagai sebuah entitas / satuan tunggal (single entity) yang merupakan sebuah objek yang mempunyai sifat dan karakteristik tersendiri.

  2. Enkapsulasi adalah konsep tentang pengikatan data atau metode yang berbeda yang disatukan atau “dikapsulkan” menjadi satu unit data. Enkapsulasi dapat mempermudah dalam pembacaan code karena informasi yang disajikan tidak perlu dibaca secara rinci dan sudah merupakan satu kesatuan.

  3. Inheritance adalah konsep OOP di mana kita dapat membentuk class baru yang “mewarisi” atau memiliki bagian-bagian dari class yang sudah ada sebelumnya. Konsep ini menggunakan sistem hirarki atau bertingkat. Semakin spesifik subclassnya, semakin sedikit pula komponen yang dapat diwarisi class tersebut.

  4. Polymorphism adalah konsep di mana suatu objek yang berbeda-beda dapat diakses melalui interface yang sama. Sebuah objek yang polymorphic dapat beradaptasi dengan metode apapun yang diimplementasikan pada objek tersebut, dan setiap class memiliki interpretasinya tersendiri terhadap interfacenya. Dalam pemrograman, polimorfisme dapat diartikan sebagai modul yang memiliki nama sama, namun memiliki behaviour (tingkah laku) yang berbeda sehingga listing code implementasinya juga berbeda.

Class

Class adalah cetak biru atau blueprint dari object. Class digunakan hanya untuk membuat kerangka dasar. Yang akan kita pakai nantinya adalah hasil cetakan dari class, yakni object.

Suatu class dibagi menjadi property dan method

Property

Property (atau disebut juga dengan atribut) adalah data yang terdapat dalam sebuah class.

Method

Method adalah tindakan yang bisa dilakukan di dalam class. Method pada dasarnya adalah function yang berada di dalam class. Seluruh fungsi dan sifat function bisa diterapkan ke dalam method, seperti argumen/parameter, mengembalikan nilai (dengan keyword return), dan lain-lain.

Object

Pada bahasa pemrograman, object adalah komponen yang diciptakan dari class (instance of class).

Object Oriented Programming dalam R

Seperti sudah dijelaskan sebelumnya, R adalah bahasa pemrograman yang berbasis objek. Semua yang ada dalam R akan dianggap sebagai objek. Pengembangan awal objek di R menggunakan Class System S3 yang tidak terlalu ketat. Untuk pendefinisian yang ketat secara formal, R menggunakan Class System S4.

Object : Class System S3

Suatu Class dalam System S3 tidak didefinisikan dengan ketat. Fungsi class digunakan untuk menjadikan sebuah objek menjadi class yang diinginkan. Berikut adalah contoh class system S3

Class Integer

A1 <-c(1:10)
class(A1)
## [1] "integer"

Class Matrix dan Array

A1 <-c(1:10)
A2 <-matrix(A1,2,5)
class(A2)
## [1] "matrix" "array"

Class Data Frame

A3 <-1:12
A4 <-letters[1:12]
B1 <-data.frame(A3,A4)
class(B1)
## [1] "data.frame"
B1$A4
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"

Class Model Linier

A3 <-1:12
A5 <-10+A3+rnorm(12)
B2 <-lm(A5~A3) #membuatmodel linear
class(B2) 
## [1] "lm"
methods(class=class(B2))
##  [1] add1           alias          anova          case.names     coerce        
##  [6] confint        cooks.distance deviance       dfbeta         dfbetas       
## [11] drop1          dummy.coef     effects        extractAIC     family        
## [16] formula        hatvalues      influence      initialize     kappa         
## [21] labels         logLik         model.frame    model.matrix   nobs          
## [26] plot           predict        print          proj           qr            
## [31] residuals      rstandard      rstudent       show           simulate      
## [36] slotsFromS3    summary        variable.names vcov          
## see '?methods' for accessing help and source code
summary(B2)
## 
## Call:
## lm(formula = A5 ~ A3)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.1599 -0.2743 -0.1014  0.2922  1.3014 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 10.34646    0.46829   22.09 8.09e-10 ***
## A3           0.95067    0.06363   14.94 3.63e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.7609 on 10 degrees of freedom
## Multiple R-squared:  0.9571, Adjusted R-squared:  0.9528 
## F-statistic: 223.2 on 1 and 10 DF,  p-value: 3.631e-08
names(B2)
##  [1] "coefficients"  "residuals"     "effects"       "rank"         
##  [5] "fitted.values" "assign"        "qr"            "df.residual"  
##  [9] "xlevels"       "call"          "terms"         "model"
B2$coefficients
## (Intercept)          A3 
##  10.3464623   0.9506728

Class list

pts <- list (x= round ( rnorm (5) ,2) , y= round ( rnorm (5) ,2))
class (pts)
## [1] "list"
pts
## $x
## [1] -1.74 -0.99 -1.62 -2.37  2.56
## 
## $y
## [1] -0.24  0.93  0.57 -1.54 -0.55

Mengubah Menjadi class

class(obj) <- “class.name”

Contoh :

Mobil1 <-list(Nama="Toyota", Panjang=3.5, Lebar=2, Kecepatan=180)
class(Mobil1)
## [1] "list"
class(Mobil1) <-"mobil"

Mobil2 <-list(Nama="Suzuki", Panjang=1, Lebar=1.8, Kecepatan=150)
class(Mobil2) <-"mobil"

Selanjutnya class pts akan dijadikan sebagai class baru

class (pts) <- "coords"
class (pts)
## [1] "coords"
pts
## $x
## [1] -1.74 -0.99 -1.62 -2.37  2.56
## 
## $y
## [1] -0.24  0.93  0.57 -1.54 -0.55
## 
## attr(,"class")
## [1] "coords"

Fungsi konstruktor

Langkah untuk mengubah menjadi class diatas tidak disarankan karena nilai-nilai instan-nya mungkin tidak tepat. Untuk mengubah menjadi class, lebih disarankan dengan fungsi konstruktor karena fungsi ini menambahkan screening sebelum menambahkan class. Screening tersebut meliputi :

  • x dan y harus berupa numerik
  • vektor tidak boleh NA, NaN, Inf
  • vektor harus memiliki panjang yang sama

Contoh :

Mobil <-function(Nama,Panjang,Lebar,Kecepatan){
    if(Panjang<2 || Lebar<1.5 || Kecepatan<80)
    stop("atribut tidak sesuai")
  Mobil <-list(Nama=Nama, Panjang=Panjang,
  Lebar=Lebar, Kecepatan=Kecepatan)
  class(Mobil) <-"mobil"
  Mobil
}

Mobil3 <-Mobil("Daihatsu", 2.1, 1.9, 120)

Jika dijalankan syntax :

Mobil4 <-Mobil(“Proton”, 2, 1.8, 70)

Mobil Proton tidak lolos screening karena atribut tidak sesuai dengan yang diinginkan.

Contoh lain :

coords <- function (x, y) {
    if (!is.numeric (x) || !is.numeric (y) || !all(is.finite(x)) || !all(is.finite(y)))
    stop (" Titik koordinat tidak tepat !")
    if ( length (x) != length (y))
    stop (" Panjang koordinat berbeda ")
  pts <- list (x=x, y=y)
  class (pts) = " coords "
  pts
}


pts <- coords (x = round ( rnorm (5) , 2) ,
y = round ( rnorm (5) , 2))

Fungsi Aksesor

Untuk mengakses data dalam class, dapat menggunakan akses objek awalnya (list). Misal :

Mobil2$Nama
## [1] "Suzuki"
Mobil3$Panjang
## [1] 2.1

Namun cara ini tidak dianjurkan, diperlukan suatu fungsi aksesor untuk mengakses data dalam class.

nama <-function(objek) objek$Nama
kecepatan <-function(objek) objek$Kecepatan

nama(Mobil1)
## [1] "Toyota"
kecepatan(Mobil3)
## [1] 120

Contoh lain :

xcoords = function (obj) obj $x
ycoords = function (obj) obj $y

xcoords (pts)
## [1] -0.59 -0.96 -0.13  0.61 -0.83
ycoords (pts)
## [1]  1.14  0.99 -1.09 -1.46  0.44

Fungsi Generik

Fungsi generik merupakan suatu method dari suatu class objek dalam R. Fungsi generik bertindak untuk beralih memilih fungsi tertentu atau metode tertentu yang dijalankan sesuai dengan classnya

Terdapat beberapa fungsi generik yang sudah ada: print, plot, dll. Untuk mendefinisi ulang suatu fungsi generik digunakan syntax:

method.class <- function () ekspresibaru

Method Print

Method print merupakan cara menampilkan data pada suatu objek Class System S3

function(…){…}

Contoh :

print.mobil <-function(objek) {
print(cat("Nama : ",nama(objek),"\n", "Kecepatan : ", kecepatan(objek), sep=""))
}

Mobil1
## Nama : Toyota
## Kecepatan : 180NULL

Contoh lain :

print.coords <- function (obj) {
print(paste("(", format ( xcoords (obj )), ", ", format (ycoords (obj )),")", sep=""),
quote = FALSE )
}

pts
## $x
## [1] -0.59 -0.96 -0.13  0.61 -0.83
## 
## $y
## [1]  1.14  0.99 -1.09 -1.46  0.44
## 
## attr(,"class")
## [1] " coords "

Method Length

Fungsi length menghitung banyaknya anggota dari objek

length(Mobil1)
## [1] 4

Class pts adalah suatu list, sehingga untuk menghitung length nya kurang tepat. Maka akan didefinisikan ulang class pts

length(pts)
## [1] 2
length.coords = function(obj) 
length(xcoords(obj))

length(pts)
## [1] 2

Membuat Fungsi Generik Baru

Untuk membuat suatu method yang dapat diwariskan, maka method tersebut harus dijadikan fungsi generik

fungsibaru<-function (objek) UseMethod(“fungsibaru”)

Misal akan dibuatkan method bbox: merupakan boundary box.

bbox <- function(obj) 
UseMethod("bbox") # menjadikan bbox sebagai fungsi generik

bbox.coords <- function(obj) {
  matrix (c(range( xcoords (obj)),
  range(ycoords(obj))),
  nc = 2, dimnames = list (
  c(" min", "max"),
  c("x:","y:")))
}

Method Plot

plot.coords <- function (obj , bbox =FALSE , ...) {
  if ( bbox ) {
    plot ( xcoords (obj),ycoords ( obj), ...) ;
    x <- c( bbox (obj )[1] , bbox (obj)[2] , bbox (obj)[2] , bbox
    (obj) [1]) ;
    y <- c( bbox (obj )[3] , bbox (obj)[3] , bbox (obj)[4] , bbox
    (obj) [4]) ;
    polygon (x,y)
    } else {
    plot ( xcoords (obj),ycoords ( obj), ...)
  }
}

plot(pts)

plot (pts , bbox =T, pch =19 , col ="red")

### Pewarisan Class

Misalkan diinginkan sebuah objek yang berisi lokasi (coords) dan terdapat nilai pada lokasi tersebut. Diperlukan menciptakan class baru vcoords sebagai turunan dari coords

Fungsi konstruktor dari class vcoords:

vcoords <- function (x, y, v) {
  if (!is.numeric (x) || !is.numeric (y) || !is.numeric (v) || !all(is.finite (x)) || !all(is.finite (y)))
  stop (" Titik koordinat tidak tepat !")
  if ( length (x) != length (y) || length (x) != length (v) )
  stop (" Panjang koordinat berbeda ")
  pts <- list (x=x, y=y, v=v)
  class (pts) = c(" vcoords ", " coords ")
  pts
}


nilai <- function (obj) obj$v

Perhatikan fungsi xcoords dan ycoords dan method bbox dari kelas coords masih sama sehingga tidak perlu didefinisi ulang

vpts <- vcoords (x = round ( rnorm (5) , 2) ,
  y = round ( rnorm (5) , 2) ,
  v = round ( runif (5 ,0 ,100)))

vpts
## $x
## [1]  0.91  0.14 -1.92  0.74 -0.49
## 
## $y
## [1] -1.62 -0.50  0.30 -1.11 -0.37
## 
## $v
## [1]  6 80 89 24 31
## 
## attr(,"class")
## [1] " vcoords " " coords "
xcoords (vpts)
## [1]  0.91  0.14 -1.92  0.74 -0.49
ycoords (vpts)
## [1] -1.62 -0.50  0.30 -1.11 -0.37

Method print juga masih diwariskan dari class coords tetapi perlu didefinisi ulang

print.vcoords <- function (obj ) {
print ( paste ("(",
format ( xcoords (obj )),", ",
format ( ycoords (obj )),"; ", format ( nilai ( obj)),")",sep=""),
quote = FALSE )
}

vpts
## $x
## [1]  0.91  0.14 -1.92  0.74 -0.49
## 
## $y
## [1] -1.62 -0.50  0.30 -1.11 -0.37
## 
## $v
## [1]  6 80 89 24 31
## 
## attr(,"class")
## [1] " vcoords " " coords "

Method Subset

Diinginkan untuk memiliki akses terhadap metode subset

Ekspresi berikut misal diinginkan:
vpts [ xcoords ( vpts ) < 0 & ycoords ( vpts ) < 0]

'[. vcoords ' <- function (x, i) {
vcoords ( xcoords (x)[i], ycoords (x)[i],
nilai (x)[i])
}

vpts [1:3]
## $x
## [1]  0.91  0.14 -1.92
## 
## $y
## [1] -1.62 -0.50  0.30
## 
## $v
## [1]  6 80 89
## 
## attr(,"class")
## [1] " vcoords " " coords "

Pemeriksaan Suatu Class Objek

Untuk mengecek apakah suatu objek merupakan suatu class digunakan fungsi inherits

inherits (pts ," coords ")
## [1] TRUE
inherits (pts ," vcoords ")
## [1] FALSE
inherits (vpts ," coords ")
## [1] TRUE
inherits (vpts ," vcoords ")
## [1] TRUE

Sehingga dapat disimpulkan dari Class System S3 bahwa :

  • Class System S3 memberikan fasilitas object-oriented, tetapi terlalu longgar

  • Ekspresi berikut diperbolehkan dalam R, padahal class “lm” merupakan class untuk pemodelan linier

model <- 1:10; class ( model ) <- “lm”

  • Masih banyak technical issue dalam Class System S3

Object : Class System S4

Class System S4: Mengatasi masalah dalam Class System S3 dengan sistem objek lebih formal. Dalam sistem objek formal, setiap objek didefinisikan secara formal dalam suatu class.

Keuntungan dari class system s4 adalah sistem penurunan dari class/objek.

Sebuah class terdiri dari slot dengan tipe atau class spesifik.

Mendefinisikanclass baru

setClass(“class.name”, representation(x=“type”), prototype(x=“…”))

setClass ("coords",representation (x = "numeric", y ="numeric"))

Medefinisikan objek baru dari kelas tertentu

new(class.name,…)

setClass("car", representation(Nama="character",
Panjang="numeric",Lebar="numeric",Kecepatan="numeric"))

Car1 <-new("car", Nama="Toyota",Panjang=3.5, Lebar=2, Kecepatan=180)

Fungsi Konstruktor

Car <-function(Nama,Panjang,Lebar,Kecepatan){
  if(Panjang<2 || Lebar<1.5 || Kecepatan<80)
  stop("atribut tidak sesuai")
  new("car", Nama=Nama, Panjang=Panjang, Lebar=Lebar, Kecepatan=Kecepatan)
}

Car2 <-Car("Suzuki", 2.4, 1.8, 150)
class(Car2)
## [1] "car"
## attr(,"package")
## [1] ".GlobalEnv"
class(Mobil1)
## [1] "mobil"

Fungsi Aksesor

Akses terhadap slot menggunakan fungsi slot atau operator @

Car1@Nama
## [1] "Toyota"
Car2@Kecepatan
## [1] 150

Namun disarankan dengan fungsi aksesor

nama1 <-function(objek) objek@Nama
kecepatan1 <-function(objek) objek@Kecepatan

nama1(Car1)
## [1] "Toyota"
kecepatan1(Car2)
## [1] 150

Fungsi Generik

Fungsi generik show setara dengan fungsi generik print pada class System S3

Penciptaan fungsi generik menggunakan fungsi setMethod

setMethod(“method”,“class.name”,function(…){…})

setMethod(show, "car", function(object) {
  print(cat("Nama: ", nama1(object), "\n", "Kecepatan: ", kecepatan1(object), sep=""))}
)

Car2
## Nama: Suzuki
## Kecepatan: 150NULL

Menciptakan fungsi generik di Object Class S4

setGeneric(“fungsibaru”, function(objek) standardGeneric(“fungsibaru”))