Bagian 8 Pengembangan Fungsi
Fungsi (function) adalah kode-kode yang disusun untuk melakukan tugas tertentu, seperti perhitungan matematis, pembacaan data, analisis statistik, dan lainnya
8.1 Membuat Fungsi
Struktur fungsi adalah
myfunction <- function(arg1, arg2, … ){
  statements
  return(object)
}Fungsi 1 dengan output hanya nilai z saja.
angka_acak1 = function(n,pw) {
  x=runif(n)
  y=runif(n)
  z=(x+y)^pw
  return(z)
}
# menggunakan fungsi  
angka_acak1(10,2)##  [1] 3.2322800 0.6242086 0.3326876 0.5492360 1.0590209 1.1219177 0.7870891
##  [8] 1.3319721 1.4719276 0.0555511
Fungsi 2 dengan output berupa nilai x, y, dan z.
# Membuat fungsi
angka_acak2 = function(n,pw) {
  x = runif(n)
  y = runif(n)
  z = (x+y)^pw
  return(list(x=x,y=y,z=z))
}
# Menggunakan fungsi
angka_acak2(10,2)## $x
##  [1] 0.13004849 0.97871535 0.06772972 0.65846763 0.82405551 0.28659556
##  [7] 0.25492677 0.69414124 0.02902345 0.52910248
## 
## $y
##  [1] 0.9110802 0.9665378 0.3187146 0.4496721 0.9357783 0.4232877 0.5029422
##  [8] 0.1356157 0.3556640 0.5645224
## 
## $z
##  [1] 1.0839489 3.7840098 0.1493392 1.2279736 3.0970152 0.5039343 0.5743654
##  [8] 0.6884966 0.1479844 1.1960153
Fungsi 3 dengan memberikan nilai default pada argumen berupa n = 1 dan pw = 2, sehingga ketika fungsi tersebut dipanggil tanpa menuliskan argumen, akan dijalankan fungsi defaultnya.
angka_acak3 = function(n=10,pw=2) {
  x = runif(n)
  y = runif(n)
  z = (x+y)^pw
  return(z)
}
angka_acak3()##  [1] 3.1055386 1.0626201 0.2837552 0.4773961 0.2354465 0.6206851 2.8971498
##  [8] 1.2952584 2.3422619 0.4302200
Fungsi 4 dituliskan tanpa menggunakan argumen. Ketika fungsi tersebut akan digunakan maka dilakukan assign nilai yang diperlukan di dalam fungsi tersebut.
angka_acak4 = function() {
  x = runif(n)
  y = runif(n)
  z = (x+y)^pw
  return(z)
}
n <- 5; pw <- 3
angka_acak4()## [1] 0.544510060 1.069862964 0.339701179 3.082262400 0.007045662
Latihan 1 Menghitung 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)
med(x1)## [1] 3.5
Latihan 2 Menghitung 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
Latihan 3 menduga parameter pada regresi berganda
# Membuat fungsi
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)
}
# Memasukkan data
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)## $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
8.2 Object Oriented Programming
Pemrograman berorientasi objek merupakan sebuah paradigma dalam pembuatan sebuah program. OOP menitikberatkan pada identifikasi objek-objek yang terlibat dalam sebuah program dan bagaimana objek-objek tersebut berinterakasi. Pada OOP, program yang dibangun akan dibagi-bagi menjadi objek-objek. OOP menyediakan class dan object sebagai alat dasar untuk meminimalisir dan mengatur kompleksitas dari program.
8.2.1 Class (kelas)
Merupakan definisi statik (kerangka dasar) dari objek yang akan diciptakan. Suatu class dibagi menjadi:
- Property : data atau state yang dimiliki oleh class. Contoh pada class Mobil, memiliki property: warna, Model, Produsen.
 - Method : behavior (perilaku) sebuah class. Bisa dikatakan sebagai aksi atau tindakan yang bisa dilakukan oleh suatu class. Contoh pada class Mobil, memiliki method: Start, Stop, Change Gear, Turn.
 
8.2.2 Object
Objek adalah komponen yang diciptakan dari class (instance of class). Satu class bisa menghasilkan banyak objek. Proses untuk membuat sebuah objek disebut instantiation. Setiap objek memiliki karakteristik dan fitur masing masing. Objek memiliki siklus creation, manipulation, dan destruction.
Prinsip dasar dari OOP adalah abstraksi, enkapsulasi, inherintance (pewarisan), dan polymorphism.
8.2.3 OOP in R
R telah mengimplementasikan pemrograman berorientasi objek. Semua dalam R adalah objek. Pengembangan awal objek di R menggunakan Class System S3 yang tidak terlalu ketat. Pendefinisian yang ketat secara formal, R menggunakan Class System S4.
Ilustrasi:
Sebuah class coords dirancang untuk digunakan dengan menyimpan data koordinat titik pada dua buah vektor X dan Y. Metode pada class ini terdiri dari metode print, length, bbox, dan plot. Class lain dirancang sebagai turunan dari class coords dengan menambahkan data nilai untuk setiap titik pada koordinat X dan Y. Metode pada class vcoords merupakan pewarisan dari class coords dan operasi-operasi aritmetik terhadap nilainya.
8.3 Object : Class System S3
Contoh
# List creation with its attributes x and y.
pts <- list(x = round(rnorm(5),2),
            y = round(rnorm(5),2))
class(pts)## [1] "list"
Menjadikan pts sebagai class baru:
class(pts) <- "coords"
class(pts)## [1] "coords"
pts## $x
## [1] -1.06 -0.70  0.93  0.07  1.64
## 
## $y
## [1] -0.43 -0.45  1.30 -0.28 -0.09
## 
## attr(,"class")
## [1] "coords"
8.3.1 Konstruktor
Fungsi Konstruktor untuk Membuat class coords
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))
pts## $x
## [1] -0.84 -0.63  0.25 -0.91  0.97
## 
## $y
## [1] -1.20  0.71  1.09  1.53 -1.06
## 
## attr(,"class")
## [1] "coords"
Fungsi Konstruktor untuk Membuat class mobil
# Membuat list Mobil1
Mobil1 <- list(Nama="Toyota",
               Panjang=3.5,
               Lebar=2,
               Kecepatan=180)
class(Mobil1)## [1] "list"
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)
Mobil3## $Nama
## [1] "Daihatsu"
## 
## $Panjang
## [1] 2.1
## 
## $Lebar
## [1] 1.9
## 
## $Kecepatan
## [1] 120
## 
## attr(,"class")
## [1] "mobil"
8.3.2 Aksesor
Akses pada class coord dengan menggunakan 2 fungsi
xcoords <- function(obj) obj$x
ycoords <- function(obj) obj$y
xcoords(pts)## [1] -0.84 -0.63  0.25 -0.91  0.97
ycoords(pts)## [1] -1.20  0.71  1.09  1.53 -1.06
Akses pada class mobil menggunakan fungsi aksesor
nama <- function(objek) objek$Nama
kecepatan <- function(objek) objek$Kecepatan
panjang <- function(objek) objek$Panjang
lebar<- function(objek) objek$Lebar
nama(Mobil1)## [1] "Toyota"
kecepatan(Mobil3)## [1] 120
panjang(Mobil3)## [1] 2.1
8.3.3 Fungsi Generik
Fungsi generik bertindak untuk beralih memilih fungsi tertentu atau metode tertentu yang dijalankan sesuai dengan class-nya. Untuk mendefinisi ulang suatu fungsi generik digunakan syntax
method.class <-function() ekspresibaru8.3.3.1 Print
Untuk class coords
print.coords <- function(obj) {
    print(paste("(", format(xcoords(obj)), ", ", format(ycoords(obj)),
        ")", sep = ""), quote = FALSE)
}
pts## [1] (-0.84, -1.20) (-0.63,  0.71) ( 0.25,  1.09) (-0.91,  1.53) ( 0.97, -1.06)
Untuk class mobil
print.mobil <- function(objek) {
  print(cat("Nama : ", nama(objek),
            "\n",
            "Kecepatan : ", kecepatan(objek),
            sep="",
            "\n",
            "Panjang:", panjang(objek),
            "\n",
            "Lebar:", lebar(objek),
            "\n") )
  }
print.mobil(Mobil1)## Nama : Toyota
## Kecepatan : 180
## Panjang:3.5
## Lebar:2
## NULL
8.3.3.2 Length
length(pts)## [1] 2
Definisi ulang
length.coords <- function(obj) length(xcoords(obj))
length(pts)## [1] 5
8.3.4 Membuat Fungsi Generik Baru
Misal ingin membuat method bbox yang 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:")))
  }
bbox(pts)##        x:    y:
## min -0.91 -1.20
## max  0.97  1.53
Plot khusus untuk class coords
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")
8.3.5 Pewarisan class
Sebagai ilustrasi jika diinginkan sebuah objek yang berisi lokasi (coords) dan terdapat nilai pada lokasi tersebut maka diperlukan class baru vcoords sebagai turunan dari coords
Konstruktor untuk 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$vvpts <- vcoords(x = round(rnorm(5), 2), 
                y = round(rnorm(5), 2), 
                v = round(runif(5, 0, 100)))
vpts## [1] (-0.94, -0.65) ( 0.68,  1.52) ( 0.77, -1.20) ( 0.14, -1.02) ( 0.74, -1.14)
xcoords(vpts)## [1] -0.94  0.68  0.77  0.14  0.74
ycoords(vpts)## [1] -0.65  1.52 -1.20 -1.02 -1.14
bbox(vpts)##        x:    y:
## min -0.94 -1.20
## max  0.77  1.52
Pendefinisian ulang method print
print.vcoords <- function(obj) {
    print(paste("(", format(xcoords(obj)), ", ", format(ycoords(obj)),
        "; ", format(nilai(obj)), ")", sep = ""), quote = FALSE)
}
vpts## [1] (-0.94, -0.65; 98) ( 0.68,  1.52; 57) ( 0.77, -1.20; 11) ( 0.14, -1.02; 40)
## [5] ( 0.74, -1.14; 33)
Pendefinisian ulang method plot
plot.vcoords <- function(obj, txt = FALSE, bbox = FALSE, ...) {
    if (bbox) {
        if (!txt) {
            plot(xcoords(obj), ycoords(obj), ...)
        } else {
            plot(xcoords(obj), ycoords(obj), type = "n", ...)
            text(xcoords(obj), ycoords(obj), nilai(obj), ...)
        }
        x <- c(bbox(pts)[1], bbox(pts)[2], bbox(pts)[2], bbox(pts)[1])
        y <- c(bbox(pts)[3], bbox(pts)[3], bbox(pts)[4], bbox(pts)[4])
        polygon(x, y)
    } else {
        if (!txt) {
            plot(xcoords(obj), ycoords(obj), ...)
        } else {
            plot(xcoords(obj), ycoords(obj), type = "n", ...)
            text(xcoords(obj), ycoords(obj), nilai(obj), ...)
        }
    }
}Menampilkan plot
plot(vpts)
plot(vpts, txt = T, bbox = T, col = "red")
Subseting
`[.vcoords` <- function(x, i) {
    vcoords(xcoords(x)[i], ycoords(x)[i], nilai(x)[i])
}
vpts[1:3]## [1] (-0.94, -0.65; 98) ( 0.68,  1.52; 57) ( 0.77, -1.20; 11)
8.3.6 Pemeriksaan suatu class objek
inherits(pts, " coords ")## [1] FALSE
inherits(pts, " vcoords ")## [1] FALSE
inherits(vpts, " coords ")## [1] FALSE
inherits(vpts, " vcoords ")## [1] FALSE
model <- list(1:10)
class(model) <- "lm"
model## 
## Call:
## NULL
## 
## No coefficients
8.4 Object : Class System S4
Class System S4 mengatasi masalah dalam Class System S3 dengan sistem objek lebih formal. Sebuah class terdiri dari slot dengan tipe atau class spesifik.
8.4.1 Deklarasi
Class dideklarasikan dengan fungsi setClass
Contoh 1, mendefinisikan ulang class coords ke class system S4
setClass("coords",
         representation(x="numeric",
                        y="numeric"))Contoh 2, deklarasi class car
setClass("car",
         representation(Nama="character",
                        Panjang="numeric",
                        Lebar="numeric",
                        Kecepatan="numeric"))
Car1 <- new("car",
            Nama="Toyota",
            Panjang=3.5, Lebar=2,
            Kecepatan=180)8.4.2 Konstruktor
Membuat objek coords
coords <- function(x, y) {
  if (length(x) != length(y))
    stop("length x dan y harus bernilai sama")
  if (!is.numeric(x) || !is.numeric(y))
    stop("x dan y harus vektor numeric")
  new("coords", x = as.vector(x), y = as.vector(y))
}set.seed(123)
pts <- coords(round(rnorm(5), 2), round(rnorm(5), 2))
pts## An object of class "coords"
## Slot "x":
## [1] -0.56 -0.23  1.56  0.07  0.13
## 
## Slot "y":
## [1]  1.72  0.46 -1.27 -0.69 -0.45
Membuat object car menggunakan 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] "list"
8.4.3 Aksesor
Akses terhadap slot menggunakan operator @
slot(pts, "x")## [1] -0.56 -0.23  1.56  0.07  0.13
pts@x## [1] -0.56 -0.23  1.56  0.07  0.13
slot(pts, "y")## [1]  1.72  0.46 -1.27 -0.69 -0.45
pts@y## [1]  1.72  0.46 -1.27 -0.69 -0.45
Disarankan menggunakan fungsi
xcoords <- function(obj) obj@x
ycoords <- function(obj) obj@y
xcoords(pts)## [1] -0.56 -0.23  1.56  0.07  0.13
Akses terhadap slot pada objek car
Car1@Nama## [1] "Toyota"
Car2@Kecepatan## [1] 150
Akses terhadap slot pada objek car dengan fungsi aksesor
nama1 <- function(objek) objek@Nama
kecepatan1 <- function(objek) objek@Kecepatan
nama1(Car1)## [1] "Toyota"
kecepatan1(Car2)## [1] 150
8.4.4 Fungsi generik
Penciptaan fungsi generik menggunakan fungsi setMethod. Argumen didefinisikan dalam signature
Contoj: show (setara dengan print pada S3)
setMethod(show, signature(object = "coords"), 
          function(object) print(paste("(",
                                       format(xcoords(object)), 
                                       ", ", format(ycoords(object)),
                                       ")", sep = ""), 
                                 quote = FALSE))
pts## [1] (-0.56,  1.72) (-0.23,  0.46) ( 1.56, -1.27) ( 0.07, -0.69) ( 0.13, -0.45)
setMethod(show, "car",
          function(object) {
            print(cat("Nama : ", nama1(object), "\n",
                      "Kecepatan : ", kecepatan1(object),
                      sep="")
                  )}
          )
Car2## Nama : Suzuki
## Kecepatan : 150NULL
8.4.5 Definisi fungsi generik baru
setGeneric("bbox", function(obj) standardGeneric("bbox"))## [1] "bbox"
setMethod("bbox", signature(obj = "coords"), 
          function(obj) 
            matrix(c(range(xcoords(obj)),
                     range(ycoords(obj))), 
                   nc = 2, 
                   dimnames = list(c("min","max"), 
                                   c("x:", "y:")
                                   )
                   ))
bbox(pts)##        x:    y:
## min -0.56 -1.27
## max  1.56  1.72
8.4.5.1 Fungsi generik plot
setMethod("plot", signature(x = "coords"),
          function(x, bbox = FALSE, ...) {
            if (bbox) {
              plot(xcoords(x), ycoords(x), ...)
              x.1 <- c(bbox(x)[1], bbox(x)[2], bbox(x)[2], bbox(x)[1])
              y.1 <- c(bbox(x)[3], bbox(x)[3], bbox(x)[4], bbox(x)[4])
              polygon(x.1, y.1)
              
              } else {
                plot(xcoords(x), ycoords(x), ...) 
              }
            })
plot(pts)
plot(pts, bbox = T, pch = 19, col = "red", xlab = "x",
     ylab = "y")
8.4.6 Pewarisan class
Akan dibuat class baru yang diturunkan dari coords dengan menambahkan slot nilai
setClass("vcoords", representation(nilai = "numeric"),
         contains = "coords")
vcoords <- function(x, y, nilai) {
  if ((length(x) != length(y)) || (length(x) != length(nilai)))
    stop("length x, y, dan nilai harus bernilai sama")
  if (!is.numeric(x) || !is.numeric(y) || !is.numeric(nilai))
    stop("x, y, dan nilai harus vektor numeric")
  new("vcoords", x = as.vector(x), y = as.vector(y),
      nilai = as.vector(nilai))
}nilai <- function(obj) obj@nilaivpts <- vcoords(xcoords(pts), ycoords(pts), round(100*runif(5)))
vpts## [1] (-0.56,  1.72) (-0.23,  0.46) ( 1.56, -1.27) ( 0.07, -0.69) ( 0.13, -0.45)
Definisi ulang method show
setMethod(show, signature(object = "vcoords"), 
          function(object) 
            print(paste("(",
                        format(xcoords(object)), 
                        ", ", 
                        format(ycoords(object)),
                        "; ", 
                        format(nilai(object)), 
                        ")", sep = ""), 
                  quote = FALSE))
vpts## [1] (-0.56,  1.72; 89) (-0.23,  0.46; 69) ( 1.56, -1.27; 64) ( 0.07, -0.69; 99)
## [5] ( 0.13, -0.45; 66)
Definisi ulang method plot
setMethod("plot", signature(x = "vcoords"), 
          function(x, txt = FALSE, bbox = FALSE, ...) {
            if (bbox) {
              if (!txt) {
                plot(xcoords(x), ycoords(x), ...)
                
              } else {
                plot(xcoords(x), ycoords(x), type = "n", ...)
                text(xcoords(x), ycoords(x), nilai(x), ...)
              }
              
              x.1 <- c(bbox(x)[1], bbox(x)[2], bbox(x)[2], bbox(x)[1])
              y.1 <- c(bbox(x)[3], bbox(x)[3], bbox(x)[4], bbox(x)[4])
              polygon(x.1, y.1)
              
            } else {
              
              if (!txt) {
                plot(xcoords(x), ycoords(x), ...)
                
              } else {
                plot(xcoords(x), ycoords(x), type = "n", ...)
                text(xcoords(x), ycoords(x), nilai(x), ...)
              }
            }
          })plot(vpts)
plot(vpts, txt = T, bbox = T, pch = 19, col = "red")
8.4.7 Operasi Aritmetika
Menggunakan perintah
setMethod("Arith", ...sameloc <- function(e1, e2) (
  length(nilai(e1)) == length(nilai(e2)) ||
    any(xcoords(e1) == xcoords(e2)) || 
    any(ycoords(e1) == ycoords(e2))
  )
setMethod("Arith", signature(e1 = "vcoords", 
                             e2 = "vcoords"),
          function(e1, e2) {
            if (!sameloc(e1, e2))
              stop("Dibutuhkan titik identik")
            vcoords(xcoords(e1), ycoords(e2), callGeneric(nilai(e1),
                                                          nilai(e2)))
          })
vpts + vpts## [1] (-0.56,  1.72; 178) (-0.23,  0.46; 138) ( 1.56, -1.27; 128)
## [4] ( 0.07, -0.69; 198) ( 0.13, -0.45; 132)
2+vpts## Error in 2 + vpts: non-numeric argument to binary operator
setMethod("Arith", signature(e1 = "numeric", 
                             e2 = "vcoords"),
          function(e1, e2) {
            if (length(e1) > length(nilai(e2)))
              stop("length yang tidak benar")
            vcoords(xcoords(e2), ycoords(e2), callGeneric(as.vector(e1),
                                                          nilai(e2)))
          })
2*vpts## [1] (-0.56,  1.72; 178) (-0.23,  0.46; 138) ( 1.56, -1.27; 128)
## [4] ( 0.07, -0.69; 198) ( 0.13, -0.45; 132)
vpts*vpts## [1] (-0.56,  1.72; 7921) (-0.23,  0.46; 4761) ( 1.56, -1.27; 4096)
## [4] ( 0.07, -0.69; 9801) ( 0.13, -0.45; 4356)
8.4.8 Subset
setMethod("[", signature(x = "vcoords", 
                         i = "ANY",
                         j = "missing", 
                         drop = "missing"), 
          function(x,i, j) 
            vcoords(xcoords(x)[i], 
                    ycoords(x)[i], 
                    nilai(x)[i]))
vpts[1:3]## [1] (-0.56,  1.72; 89) (-0.23,  0.46; 69) ( 1.56, -1.27; 64)
8.4.9 Pemeriksaan Suatu Class Objek
is(pts ,"coords")## [1] TRUE
is(pts ,"vcoords")## [1] FALSE
is(vpts ,"coords")## [1] TRUE
is(vpts ,"vcoords")## [1] TRUE
8.4.10 Coerce
vpts2 <- as(vpts, "coords")
vpts2## [1] (-0.56,  1.72) (-0.23,  0.46) ( 1.56, -1.27) ( 0.07, -0.69) ( 0.13, -0.45)
is(vpts2, "coords")## [1] TRUE
pts2 <- as(pts , "vcoords")
pts2## [1] (-0.56,  1.72; ) (-0.23,  0.46; ) ( 1.56, -1.27; ) ( 0.07, -0.69; )
## [5] ( 0.13, -0.45; )
is(pts2, "vcoords")## [1] TRUE
ob <- list(x = round(rnorm(5), 2), y = round(rnorm(5), 2))
ob## $x
## [1]  0.55  0.24 -1.05  1.29  0.83
## 
## $y
## [1] -0.06 -0.78 -0.73 -0.22 -0.33
as(ob , "vcoords")## Error in as(ob, "vcoords"): no method or default for coercing "list" to "vcoords"
mdl <- list(123)
class(mdl) <- "lm"
mdl## 
## Call:
## NULL
## 
## No coefficients
8.4.10.1 Latihan
Buat fungsi bernama three.M yang digunakan untuk menghitung mean, median, modus dari suatu vector (tanpa menggunakan fungsi mean, quantile atau pun fungsi “instan” lain yang sudah tersedia sebelumnya di R).
Hitung mean, median, dan modus dari suatu data rbinom(100,10, 0.5) dengan seed(123).
three.M <- function(vect) {
  n <- length(vect) # banyak data 
  
  # rataan 
  jumlah <- sum(vect)
  rataan <- jumlah/n
  
  # median
  vects <- sort(vect) # urutkan
  if(n%%2 == 1) {m <- vects[(n+1)/2]}
  else {m <- (vects[n/2]+vects[(n/2)+1])/2} 
  
  # modus
  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,]
  
  # output
  my_list <- list("mean" = rataan, "median" = m, "modus" = mode)
  class(my_list) <- "threeM"
  
  return(my_list)
}Fungsi generik print
print.threeM <- function(obj){
  cat("three.M Statitic\n")
  cat("\nMean: ", obj$mean)
  cat("\nMedian: ", obj$median)
  cat("\nModus:\n")
  print(obj$modus)
}
set.seed(123)
x1 <- rbinom(100,10,0.5)
three.M(x1)## three.M Statitic
## 
## Mean:  4.99
## Median:  5
## Modus:
##      v  f
## [1,] 6 24
## [2,] 5 24
Latihan, membuat fungsi Regresi Komponen Utama
AKU <- function(X){
  
  # transform X into matrix
  X <- as.matrix(X)
  
  # transform all var into z-score
  X <- scale(X, center = TRUE, scale = TRUE)
  x.bar <- attr(X, "scaled:center")
  x.stdev <- attr(X, "scaled:scale")
  
  # compute singular-value decomposition
  SVD <- La.svd(X)
  D  <- SVD$d
  
  # compute principal component
  pc.score <- SVD$u %*% diag(D, nrow = ncol(X))
  
  # get eigenvector from SVD
  eigenvector <- SVD$vt
  
  # compute eigenvalues and PC contributions
  pc.score.stdev <- D / sqrt(max(1, nrow(X) - 1))
  eigenvalue <- pc.score.stdev^2
  eigenvalue.proportion <- eigenvalue/sum(eigenvalue)
  eigenvalue.cum.proportion <- cumsum(eigenvalue.proportion)
  eigenanalysis <-  rbind(eigenvalue, eigenvalue.proportion, eigenvalue.cum.proportion)
  
  # assign names
  pc.name <- paste0('PC', seq(ncol(X)))
  colnames(pc.score) <- rownames(eigenvector) <- colnames(eigenanalysis) <- names(pc.score.stdev) <- pc.name
  rownames(pc.score) <- rownames(X)
  colnames(eigenvector) <- colnames(X)
  rownames(eigenanalysis) <- c("Eigenvalue", "Proportion", "Cumulative")
  
  # wrap output into list
  out <- list(
    n.col = ncol(X),
    n.row = nrow(X),
    x.bar = x.bar, x.stdev = x.stdev,
    pc.score = pc.score, 
    pc.score.stdev = pc.score.stdev, 
    eigenvalue = eigenanalysis, eigenvector = t(eigenvector)
  )
  
  # asign a class
  class(out) <- "AKU"
  return(out)
  
}Metode generik print.AKU
print.AKU <- function(obj) {
  cat("PRINCIPAL COMPONENT ANALYSIS\n")
  cat("Input: ", obj$n.row, "rows X", obj$n.col, "columns\n")
  cat("\nEigenanalysis of Correlation Matrix:\n")
  print(obj$eigenvalue)
  cat("\nEigenvectors:\n")
  print(obj$eigenvector)
  cat("\nScore of Principal Component (Preview):\n")
  print(rbind(head(obj$pc.score)))
  if(nrow(obj$pc.score) > 6) cat("...")
}Contoh penggunaan
url <- "https://raw.githubusercontent.com/nurandi/sta561-uts/main/data/pca-data.csv"
dta <- read.csv(url)
y <- dta[1]
X <- dta[-1]aku <- AKU(X)aku## PRINCIPAL COMPONENT ANALYSIS
## Input:  15 rows X 4 columns
## 
## Eigenanalysis of Correlation Matrix:
##                  PC1        PC2        PC3         PC4
## Eigenvalue 3.7693710 0.16253376 0.04423637 0.023858911
## Proportion 0.9423427 0.04063344 0.01105909 0.005964728
## Cumulative 0.9423427 0.98297618 0.99403527 1.000000000
## 
## Eigenvectors:
##          PC1        PC2         PC3        PC4
## X1 0.5056158 -0.3398479  0.35682315  0.7081902
## X2 0.4940545  0.6392714  0.50650265 -0.3011600
## X3 0.5035406  0.3178941 -0.78135788  0.1867354
## X4 0.4966988 -0.6121919 -0.07491445 -0.6106547
## 
## Score of Principal Component (Preview):
##             PC1         PC2         PC3         PC4
## [1,] -3.2417574 -1.03926963 -0.21320529  0.18559324
## [2,] -1.8486832  0.01142542  0.22832852 -0.10777842
## [3,] -0.7795219  0.46096143  0.04824186 -0.14517167
## [4,] -0.1361711  0.04200545 -0.08603160  0.01717014
## [5,] -1.0044094 -0.07221540  0.24797726  0.02243639
## [6,]  1.8019258 -0.23968031 -0.11141042 -0.03474123
## ...
print(aku)## PRINCIPAL COMPONENT ANALYSIS
## Input:  15 rows X 4 columns
## 
## Eigenanalysis of Correlation Matrix:
##                  PC1        PC2        PC3         PC4
## Eigenvalue 3.7693710 0.16253376 0.04423637 0.023858911
## Proportion 0.9423427 0.04063344 0.01105909 0.005964728
## Cumulative 0.9423427 0.98297618 0.99403527 1.000000000
## 
## Eigenvectors:
##          PC1        PC2         PC3        PC4
## X1 0.5056158 -0.3398479  0.35682315  0.7081902
## X2 0.4940545  0.6392714  0.50650265 -0.3011600
## X3 0.5035406  0.3178941 -0.78135788  0.1867354
## X4 0.4966988 -0.6121919 -0.07491445 -0.6106547
## 
## Score of Principal Component (Preview):
##             PC1         PC2         PC3         PC4
## [1,] -3.2417574 -1.03926963 -0.21320529  0.18559324
## [2,] -1.8486832  0.01142542  0.22832852 -0.10777842
## [3,] -0.7795219  0.46096143  0.04824186 -0.14517167
## [4,] -0.1361711  0.04200545 -0.08603160  0.01717014
## [5,] -1.0044094 -0.07221540  0.24797726  0.02243639
## [6,]  1.8019258 -0.23968031 -0.11141042 -0.03474123
## ...
aku$eigenvalue##                  PC1        PC2        PC3         PC4
## Eigenvalue 3.7693710 0.16253376 0.04423637 0.023858911
## Proportion 0.9423427 0.04063344 0.01105909 0.005964728
## Cumulative 0.9423427 0.98297618 0.99403527 1.000000000
head(aku$pc.score)##             PC1         PC2         PC3         PC4
## [1,] -3.2417574 -1.03926963 -0.21320529  0.18559324
## [2,] -1.8486832  0.01142542  0.22832852 -0.10777842
## [3,] -0.7795219  0.46096143  0.04824186 -0.14517167
## [4,] -0.1361711  0.04200545 -0.08603160  0.01717014
## [5,] -1.0044094 -0.07221540  0.24797726  0.02243639
## [6,]  1.8019258 -0.23968031 -0.11141042 -0.03474123
Fungsi regresi komponen utama
RKU <- function(y, X, k){
  
  if(is.null(colnames(X))) colnames(X) <- paste0("V", seq(ncol(X)))
  
  aku <- AKU(X)
  
  if(is.null(k)){
    k <- ncol(X)
  } else if(k < 1){
    k <- sum(aku$eigenvalue[3,] < k) + 1
  }
    
  pc.score <-  aku$pc.score[,1:k]
  pcr.data <- as.data.frame(cbind(y, pc.score))
  pc.name <- colnames(aku$pc.score)[1:k]
  colnames(pcr.data) <- c("y", pc.name)
  
  pcr.lm <- lm(y ~ ., data = pcr.data)
  pcr.summary <- summary.lm(pcr.lm)[c("coefficients", "sigma", 
                                      "r.squared", "adj.r.squared",
                                      "fstatistic", "df")]
  
  beta.pcr <- as.matrix(pcr.lm$coefficients) 
  
  beta.z.score1 <- (aku$eigenvector)[,1:k] %*% as.matrix(beta.pcr[-1])
  beta.z.score <- rbind(beta.pcr[1], beta.z.score1)
  beta.x <- rbind(beta.pcr[1] - (aku$x.bar/aku$x.stdev) %*% beta.z.score1,
                  beta.z.score1/aku$x.stdev)
  
  # asign name
  colnames(beta.pcr) <- colnames(beta.z.score) <- colnames(beta.x) <- "Estimates"
  rownames(beta.z.score) <- c("(Intercept)", paste0("Z_", colnames(X)))
  rownames(beta.x) <- c("(Intercept)", colnames(X))
  
  out <- list(pca = aku,
              k = k,
              pcr.lm = pcr.lm,
              pcr.summary = pcr.summary,
              pcr.coefficient = summary.lm(pcr.lm)$coefficients,
              beta.z.score = beta.z.score,
              beta.x = beta.x)
  out <- c(aku, out)
  class(out) <- "RKU"
  return(out)
} print.RKU <- function(obj, mode = "simple") {
  
  if(mode == "ext"){
    print(obj$pca)
    cat("\n\n")
  }
  
  cat("PRINCIPAL COMPONENT REGRESSION\n")
  cat("With", obj$k, "Principal Component(s)\n")
  
  cat("\nFormula: y ~ Principal Component Score\n\n")
  print(obj$pcr.coefficient)
  
  cat("\nR-squared: ", obj$pcr.summary$r.squared)
  cat(",  Adjusted R-squared: ", obj$pcr.summary$adj.r.squared,
      "\nF Statistics:", obj$pcr.summary$fstatistic[1])
  cat(",  DF1:", obj$pcr.summary$fstatistic[2])
  cat(",  DF2:", obj$pcr.summary$fstatistic[3])
  cat(",  p-value:", format.pval(pf(obj$pcr.summary$fstatistic[1], 
                                    obj$pcr.summary$fstatistic[2],
                                    obj$pcr.summary$fstatistic[3], 
                                    lower.tail = FALSE)))
  
  if(mode == "simple"){
    cat("\n\nNote: use print(obj, 'ext') to print extended output\n")}
  
  if(mode == "ext"){
    cat("\n\nInverse Transform into Z Score\n")
    print(obj$beta.z.score)
    cat("\nInverse Transform into X\n")
    print(obj$beta.x)
  }
  
}rku <- RKU(y = y, X = X, k = 1)rku## PRINCIPAL COMPONENT REGRESSION
## With 1 Principal Component(s)
## 
## Formula: y ~ Principal Component Score
## 
##              Estimate Std. Error   t value                       Pr(>|t|)
## (Intercept) 76.273333  0.5588331 136.48679 0.0000000000000000000006595387
## PC1          3.755193  0.2979403  12.60384 0.0000000115720528926616900058
## 
## R-squared:  0.9243556,  Adjusted R-squared:  0.9185368 
## F Statistics: 158.8568,  DF1: 1,  DF2: 13,  p-value: 0.000000011572
## 
## Note: use print(obj, 'ext') to print extended output
print(rku)## PRINCIPAL COMPONENT REGRESSION
## With 1 Principal Component(s)
## 
## Formula: y ~ Principal Component Score
## 
##              Estimate Std. Error   t value                       Pr(>|t|)
## (Intercept) 76.273333  0.5588331 136.48679 0.0000000000000000000006595387
## PC1          3.755193  0.2979403  12.60384 0.0000000115720528926616900058
## 
## R-squared:  0.9243556,  Adjusted R-squared:  0.9185368 
## F Statistics: 158.8568,  DF1: 1,  DF2: 13,  p-value: 0.000000011572
## 
## Note: use print(obj, 'ext') to print extended output
print(rku, mode = "ext")## PRINCIPAL COMPONENT ANALYSIS
## Input:  15 rows X 4 columns
## 
## Eigenanalysis of Correlation Matrix:
##                  PC1        PC2        PC3         PC4
## Eigenvalue 3.7693710 0.16253376 0.04423637 0.023858911
## Proportion 0.9423427 0.04063344 0.01105909 0.005964728
## Cumulative 0.9423427 0.98297618 0.99403527 1.000000000
## 
## Eigenvectors:
##          PC1        PC2         PC3        PC4
## X1 0.5056158 -0.3398479  0.35682315  0.7081902
## X2 0.4940545  0.6392714  0.50650265 -0.3011600
## X3 0.5035406  0.3178941 -0.78135788  0.1867354
## X4 0.4966988 -0.6121919 -0.07491445 -0.6106547
## 
## Score of Principal Component (Preview):
##             PC1         PC2         PC3         PC4
## [1,] -3.2417574 -1.03926963 -0.21320529  0.18559324
## [2,] -1.8486832  0.01142542  0.22832852 -0.10777842
## [3,] -0.7795219  0.46096143  0.04824186 -0.14517167
## [4,] -0.1361711  0.04200545 -0.08603160  0.01717014
## [5,] -1.0044094 -0.07221540  0.24797726  0.02243639
## [6,]  1.8019258 -0.23968031 -0.11141042 -0.03474123
## ...
## 
## PRINCIPAL COMPONENT REGRESSION
## With 1 Principal Component(s)
## 
## Formula: y ~ Principal Component Score
## 
##              Estimate Std. Error   t value                       Pr(>|t|)
## (Intercept) 76.273333  0.5588331 136.48679 0.0000000000000000000006595387
## PC1          3.755193  0.2979403  12.60384 0.0000000115720528926616900058
## 
## R-squared:  0.9243556,  Adjusted R-squared:  0.9185368 
## F Statistics: 158.8568,  DF1: 1,  DF2: 13,  p-value: 0.000000011572
## 
## Inverse Transform into Z Score
##             Estimates
## (Intercept) 76.273333
## Z_X1         1.898685
## Z_X2         1.855270
## Z_X3         1.890892
## Z_X4         1.865200
## 
## Inverse Transform into X
##              Estimates
## (Intercept) 44.0669992
## X1           0.7520572
## X2           0.8271652
## X3           3.0821554
## X4           3.6330905
rku$pcr.coefficient##              Estimate Std. Error   t value                       Pr(>|t|)
## (Intercept) 76.273333  0.5588331 136.48679 0.0000000000000000000006595387
## PC1          3.755193  0.2979403  12.60384 0.0000000115720528926616900058
# print class lm
summary(rku$pcr.lm)## 
## Call:
## lm(formula = y ~ ., data = pcr.data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.6187 -1.4432 -0.4312  1.5546  3.4001 
## 
## Coefficients:
##             Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)  76.2733     0.5588   136.5 < 0.0000000000000002 ***
## PC1           3.7552     0.2979    12.6         0.0000000116 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.164 on 13 degrees of freedom
## Multiple R-squared:  0.9244, Adjusted R-squared:  0.9185 
## F-statistic: 158.9 on 1 and 13 DF,  p-value: 0.00000001157
Ref (Raharjo 2021b) (Soleh 2021b) (Rahmi 2021b)