Program

Pipe

prerequisites

library(magrittr)

“%>%” adalah sebuah operator yang telah sering kita pakai sebelumnya. Operator ini memiliki nama “foward pipe operator”, sebuah mekanisme untuk membuat rantai komando fungsi dari kiri ke kanan, sehingga kita tidak perlu membuat objek-objek intermediate.

“%>%” atau pipe, seperti namanya, memang bekerja seperti pipa. dia akan membawa value dari satu fungsi ke fungsi lainnya, dan hanya berhenti di tujuan akhir. Pipe ini membuat sebuah environment sementara untuk melakukan tiap fungsi yang berjalan di belakang layar, sehingga saat kita mencoba memanggil objek itu kembali di luar pipe, hasil yang dikeluarkan akan sama dengan sebelum objek itu memasuki pipe. Hal ini bisa kita akali dengan mengeksplisitkan environment yang ada.

x <- sum(10,10)
x
## [1] 20
x %>% sum(.,20)
## [1] 40
x
## [1] 20

Lihat? meski setelah x menggunakan operator %>% ditambahkan dengan 20 (dan menghasilkan 40), saat x dipanggil kembali di luar lingkungan sementara %>%, valuenya akan kembali menjadi 10.

Jangan menggunakan pipe ‘%>%’ saat : * Step yang kita jalankan terlalu panjang (lebih dari 10 step) * Melibatkan banyak input dan output * Untuk pembuatan fungsi kompleks diagram

Tool lain dari ‘magrittr’ :
* ‘%T>%’ atau ‘Tee’ pipe. Operator ini berfungsi untuk menghasilkan output sampingan. Ingat bahwa dalam ‘%>%’, aliran value tidak akan berhenti sampai tujuan akhir. Namun ada kalanya kita ingin menghasilkan satu objek sampingan selain apa yang kita cari dari hasil akhir. Untuk itu, proses yang bisa kita gunakan adalah operator ini.

# Contoh 1 
rnorm(100) %>% matrix(ncol =2) %>% plot() %>% str()

##  NULL

Kenapa NULL? Karena membingungkan. Lihat bagaimana value dari matrix yang kemudian di plot, dan dari plot, kemudian kita minta print str()? apa yang mau di summary dari output plot?

rnorm(100) %>% matrix(ncol = 2) %T>% plot() %>% str()

##  num [1:50, 1:2] -0.19 -0.263 -0.105 0.068 0.229 ...

Lihat? dengan menambahkan ‘%T>%’ sebelum step plot(), kita menjadikan step ini sebagai side-effect, dan menghasilkan plot. dan secara langsung membawa hasilnya, dari matrix, menuju str().

  • ‘%$%’ digunakan untuk langsung mengeksplorasi variabel dalam data frame.
mtcars %>% mean(mpg)
## Warning in mean.default(., mpg): argument is not numeric or logical: returning
## NA
## [1] NA
mtcars %$% mean(mpg)
## [1] 20.09062

Jika fungsi tersebut pada dasarnya tidak memiliki argumen dataframe seperti pada seluruh tool dplyr. Maka kita bisa menggunakan operator ini.

  • Assignment operator ‘%<>%’ ini akan membuat objek awal berubah mengikuti hasil dari environment baru.
x <- sum(10,10)
x
## [1] 20
x %>% sum(.,20)
## [1] 40
x
## [1] 20
x %<>% sum(.,20)
x
## [1] 40

Function

Fungsi adalah sebuah fitur dalam programming yang memampukan kita untuk melakukan otomasi serangkaian step perhitungan dengan variabel yang ada.

Untuk membuat fungsi, ada tiga kunci utama : * Nama -> nama fungsi menjadi penting untuk memperjelas tujuan fungsi tersebut * Argument -> input dari fungsi tersebut * Body -> berisi kode yang ingin kita jalankan dalam fungsi

Percobaan :

1.Coba buat fungsi dari tiga kode ini : * mean(is.na(x))

# Tujuan dari fungsi ini adalah untuk menghitung proporsi NA yang ada dalam satu vector
prop_na <- function(x){
  mean(is.na(x))
}

x <- c(1:10,NA,NA,11:20)
prop_na(x)
## [1] 0.09090909
* x/sum(x, na.rm =TRUE)
# Fungsi ini mencoba menghitung proposi nilai sepanjang vector terhadap vector itu sendiri

prop_val <- function(x){
  x/sum(x, na.rm = TRUE)
}

y <- c(rnorm(20,10))
prop_val(y)
##  [1] 0.05026856 0.05573944 0.04541549 0.05219808 0.05425435 0.04622716
##  [7] 0.05746885 0.05333882 0.04576355 0.04532222 0.05138485 0.05551185
## [13] 0.04313052 0.05626319 0.04513273 0.04974099 0.05312237 0.04500816
## [19] 0.05475595 0.03995286
* sd(x, na.rm=T)/mean(x, na.rm=T)
# fungsi ini sama dengan rumus menghitung koefisien variasi
coef_var <- function(x, na.rm = TRUE) {
  sd(x, na.rm = TRUE)/mean(x, na.rm = TRUE)
}

z <- rnorm(30, 15)
coef_var(z)
## [1] 0.06821596
* Coba menulis fungsi untuk menghitung variance dan skewness
variance <- function(x, na.rm = TRUE){
  sum((x - mean(x))^2) / (length(x) - 1)
}

variance(z)
## [1] 1.040504
var(z)
## [1] 1.040504
variance(10)
## [1] NaN
var(10)
## [1] NA
skew <- function(x, na.rm = TRUE){
  (sum((x - mean(x))^3)/(length(x) - 2))/(variance(x)^(3/2))
}
library(moments)
skewness(z)
## [1] 0.1850345
skew(z)
## [1] 0.1884217
* Tulis fungsi bernama 'both_na()' yang punya dua argumen vector dengan panjang sama dan menghasilkan output berupa indeks posisi di mana ada NA di kedua vector.
both_na <- function(x,y){
  if(length(x) == length(y)) {
    na_x <- which(is.na(x))
    na_y <-which(is.na(y))
    na_both <- c(na_x,na_y)
    na_both
  }else{
    NULL
  }
}
a <- c(1,2,3,4,6,NA,8,9,10,11)
b <- c(21,32,15,65,46,86,NA,43,75,80)
both_na(a,b)
## [1] 6 7

checking function

both_na
## function(x,y){
##   if(length(x) == length(y)) {
##     na_x <- which(is.na(x))
##     na_y <-which(is.na(y))
##     na_both <- c(na_x,na_y)
##     na_both
##   }else{
##     NULL
##   }
## }

Dot-dot-dot (…)

Kita tahu bagaiman pembuatan sebuah fungsi mengharuskan kita untuk mendefinisikan berapa banyak input yang dipakai. Jika kita kurang, atau melibihi jumlah input yang ditentukan dalam fungsi, error akan terjadi. Namun dalam banyak kasus, fungsi tidak mengatur jumlah input yang dimasukkan; kita bebas memasukkan berapapun input yang kita inginkan. Contoh : sum(), dan seluruh fungsi str_*(). Bagaimana caranya? fungsi-fungsi seperti ini, menggunakan argumen spesial berupa tiga titik berderet (…) atau disebut dot-dot-dot. Dengan ini, kita bisa bebas memasukkan berapapun input. Argumen ini juga berguna karena juga membungkus fungsi lain, dan menggunakan algortima fungsi tersebut untuk fungsi kita sendiri.

contoh :

commas <- function(...) {
  stringr::str_c(..., collapse = ", ")
}

commas(letters[1:10])
## [1] "a, b, c, d, e, f, g, h, i, j"
rule <- function(..., pad = "-") {
  title <- paste0(...)
  width <- getOption("width") - nchar(title) - 5
  cat(title, " ", stringr::str_dup(pad,width), "\n", sep = "")
}

rule("important rule")
## important rule -------------------------------------------------------------

Yep, dengan argument dot-dot-dot, kita bisa menggunakan fungsi lain di dalam fungsi kita tanpa mengkhawatirkan perbedaan aturan input.

Percobaan

show_missing <- function(df) {
  n <- sum(is.na(df))
  cat("missing value : ", n, "\n", sep = "")
  
  invisible(df)
}

df_ab <- data.frame(a,b)
show_missing(df_ab)
## missing value : 2

Fungsi di atas menggunakan invisible() yang membuat input dri df tidak di tampilkan.

Environment

R menggunakan lexical scoop yang membuatnya dapat mengambil refrensi dari lingkungan lain saat ada objek yg tidak atau belum didefinisikan.

# Contoh penulisan fungsi pada bahasa pemrogaman pada umumnya.
blabla <- function(x) {
  y <- 100
  x + y
}

blabla(200)
## [1] 300
# R Mengijinkan kita untuk tidak menspesifikasikan variabel y di dalam fungsi. 
blabla2 <- function(x) {
  x + y
}

y <- 100
blabla2(200)
## [1] 300

Vector

Vector adalah salah satu tipe struktur data dalam R bersama dengan factor, list, matrix, dataframe. Secara definisi, vector adalah tipe data satu dimensi yang berisi value dengan kelas sama (all character, all number, atau all double, dll). Jika kita sebelumnya sudah mempelajari soal tibble, perlu kita ketahui bahwa vector adalah dasar dari tibble, karena hampir seluruh fungsi di R dibangun dalam vector. Pembelajaran soal vector menjadi semakin penting karena kita akan berkembang dengan menulis fungsi kita sendiri.

pada dasarnya, untuk memulai materi ini kita tidak perlu load package apapun. Namun untuk mempermudah pemahaman lebih lanjut, sudah tersedia package berisi fungsi-fungsi penting terkait dengan vector di dalam ‘purrr’, yang juga sudah tersedia dalam ‘tidyverse’

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 tidyr::extract()   masks magrittr::extract()
## x dplyr::filter()    masks stats::filter()
## x dplyr::lag()       masks stats::lag()
## x purrr::set_names() masks magrittr::set_names()

Jenis Vector

Ada dua (2) jenis vector, yaitu : 1. Atomic Vector : terdiri dari 6 tipe data seperti logical, integer, double, character, complex, dan raw. Integer dan double termasuk dalam vector numeric. 2. List : disebut juga recursive vector, karena (mungkin kita sudah tahu) berbentuk seperti vector dalam vector.

Perbedaan dari atomic dan list adalah : atomic vector bersifat homogenic, sementara list bersifat heterogenic. Adapun objek lainnya yang berdampingan dengan vector adalah NULL, yaitu sebuah representasi ketiadaan vector. (NA representasi ketiadaan nilai dalam vector). Pada dasarnya, NULL adalah vector denga length 0.

Setiap vector memiliki dua properti kunci : 1. type –> yg bisa kita cek dengan menuliskan fungsi typeof() 2. Panjang (length) – > yang bisa kita cek dengan length()

Catatan lain soal vector adalah : bahwa setiap struktur data yang dibangun di R, merupakan pengembangan dari vector atau pengembangan dari struktur data berpondasi vector.

  • Factor (struktur data kategorikal), dibangun diatas integer vector
  • Dates and Times dibangun di atas vector numeric
  • Data frame dan tibble dibangun di atas list

Atomic Vector

Atomic vector, disebut atomic karena ini adalah tipe data paling rendah berdimensi satu dalam program R. Keenamnya (logical, double, integer, character, complex, dan raw) termasuk dalam struktur vector. Raw dan Complex jarang digunakan dalam analisa data, sehingga kita hanya akan membahas empat diantaranya.

Logical

Logical vector data type adalah jenis data paling mudah dan sederhana karena hanya memiliki 3 rentang nilai; TRUE, FALSE, dan NA. Biasanya logical menjadi sangat mudah digunakan bersama dengan komparator.

Numeric

Seperti yang disebutkan sebelumnya, tipe data integral dan double termasuk dalam vector numeric. Secara default, seluruh vector angka di R tersimpan dalam bentuk double.

typeof(1213)
## [1] "double"
typeof(43.54)
## [1] "double"

Untuk membuat data integer, tambahkan “L” setelah angka.

intA <- 1.2483L
intB <-32L
intA
## [1] 1.2483
intB
## [1] 32
typeof(intA)
## [1] "double"
typeof(intB)
## [1] "integer"

Meski muncul warning, ini tidak mengubah input. Lalu apa perbedaan diantara keduanya? Dalam praktik, perbedaan integer dan double tidak terlalu penting, namun bagaimanapun terdapat beberapa hal yang perlu dipahami tentang double dan integer yang mungkin akan mempengaruhi pemahaman kita dalam mengintrepertasi angka.

Double adalah sebuh estimasi atau aproksimasi. Dengan kata lain, angka yang muncul sebagai double bukanlah angka absolut dari nilai variabel. Double merepresentasikan nilai desimal yang tidak bisa ditampilkan secara keseluruhan karena keterbatasan memori. Jadi, kita harus melihat seluruh nilai double sebagai sebuah estimasi.

Contoh :

doubA <- sqrt(2) ^2
doubA 
## [1] 2
doubA-2
## [1] 4.440892e-16
doubA == 2
## [1] FALSE
near(doubA,2)
## [1] TRUE

Lihat, padahal akar kuadrat 2 hasilnya adalah 2, jika kita kurangi dengan 2, harusnya hasilnya adalah 0, bukan? namun tidak begitu. Output ini muncul karena nilai 2 dalam x, merupakan aproksimasi terdekat dari akar dua kuadrat.

Oleh karena itu, jika kita melakukan komparasi dengan nilai double, lebih baik menggunakan fungsi near(), daripada “==” (seperti tampak pada contoh di atas)

Hal yang perlu dicatat soal double dan integer adalah : *Integer hanya memiliki satu value khusus (NA), sedangkan double punya empat (NA, NaN, Inf, dan -Inf). Khusus untuk Nan, Inf, dan -Inf muncul dari operasi pembagian.

  • NaN –> berasal dari undefined, muncul akibat pembagian yg menghasilkan nilai yang tidak terdefinisi atau tidak mungkin (seperti 0/0)
  • Inf dan -Inf –> artinya infinit, muncul saat kita membagi angka apapun dengan 0.

Kita tidak bisa menggunakan “==” untuk mengecek ketiga hasil khusus ini. Gantinya kita hanya bisa menggunakan : * is.finite() —> cek angka 0 dan seterusnya * is.infinite() –> cek Inf dan -Inf * is.na() – > cek NA dan NaN * is.nan() –> cek NaN

Character

Jenis vector paling kompleks, namun sudah kita bahas pada bagian string. Sedikit catatan tambahan untuk ini adalah setiap string akan disimpan sekali. Duplikasi atau pemanggilan string berikutnya tidak akan mengonsumsi memori lebih, melainkan hanya menciptakan pointer untuk representasi memori tersebut.

Missing Value

Masing-masing tipe data, memiliki tipe missing value yang berbeda : * logical –> NA * integer –> NA_integer_ * double –> NA_real_ * character –> NA_character_

Kenapa kita perlu tahu soal ini? ke depan, kita akan menemui beberapa fungsi yang lumayan ketat dalam pengelolaan missing value tipe yang berbeda. Jadi mengetahui bahwa ada tipe NA yang berbeda akan membantu.

Exercise 1. Apakah is.finite(x) dan !is.infinite(x) berbeda?

jawab :

finitA <- 100/0
finitB <- 0/0
is.finite(finitA)
## [1] FALSE
!is.infinite(finitA)
## [1] FALSE
is.finite(finitB)
## [1] FALSE
!is.infinite(finitB)
## [1] TRUE

Jawabannya, berbeda. Meski hasil keduanya terlihat sama. Namun negasi dari infinit bukanlah finit. Yang unik dari ini adalah… R tidak benar-benar menerapkan hukum matematika murni di sini. Kenapa? karena seluruh angka yang dibagi 0 seharusnya menghasilkan ‘undefined’ atau tidak terdefinisi, yang berarti seharusnya warning yang muncul adalah ‘NaN’. Hal ini terjadi karena program R dibangun berdasarkan standart tertentu.

  1. Baca source code dari near()

Jawab :

near
## function (x, y, tol = .Machine$double.eps^0.5) 
## {
##     abs(x - y) < tol
## }
## <bytecode: 0x000000001b3d2ca0>
## <environment: namespace:dplyr>

fungsi near() adalah dengan mendapatkan nilai absolut dari selisih dua variabel (x dan y), lalu membandingkannya dengan tol. Jika selisih nya lebih kecil dari tol (batas toleransi komparasi), maka kedua variabel masih bisa dianggap ekuivalen.

  1. Berapa banyak value yg bisa vector logical ambil : 3 value, untuk double : 264 value, dan untuk integer 232

Menggunakan atomic vector

Setelah mempelajari dasar dan mengenal 6 kelas atomic vector, saatnya kita belajar bagaimana cara menggunakan keenam vector tersebut.

Cara konversi

Ada 2 cara konversi tipe vector : * Explisit – > dengan menggunakan ‘as.integer()’, ‘as.double’, ‘as.character’, dll. * Implisit – > Melalui penggunaannya dalam fungsi aritmatika

contoh :

d <- sample(30,100, replace = TRUE)
e <- d > 10
sum(e) # Menghitung jumlah sample d yang lebih besar dari pada 10.
## [1] 70
mean(e) # Menghitung jumlah proporsi / mean dari sample d yang lebih dari 10
## [1] 0.7

Saat kita mencoba cek type vector yang berisi dua kelas yang berbeda, vector yg lebih rumit akan selalu menang. Meski tes ini tidak banyak berguna, karena vector adalah struktur data yang berisi kelas yang sama.

Scalar dan Aturan recycling

Apa yang terjadi saat kita mengoperasikan dua vector dengan panjang yang berbeda? ada 2 kemungkinan kondisi. Pertama, kita lihat dulu pada contoh di bawah ini

vec_1 <- 1:10
vec_2 <- 1:2

vec_1 + vec_2 # Hasilnya berupa vector
##  [1]  2  4  4  6  6  8  8 10 10 12
sum(vec_1,vec_2) # hasilnya berupa satu angka (kenapa? Karena sum() menjadikan dua vector menjadi satu vector)
## [1] 58
sample(10) + 100
##  [1] 110 108 101 109 104 107 103 105 106 102
runif(10) > 0.5
##  [1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE
data.frame(vec_1,vec_2)
##    vec_1 vec_2
## 1      1     1
## 2      2     2
## 3      3     1
## 4      4     2
## 5      5     1
## 6      6     2
## 7      7     1
## 8      8     2
## 9      9     1
## 10    10     2

Kita bisa lihat di atas, saat ada dua vector yg berbeda panjag, vector yang lebih pendek akan di ‘daur ulang’ hingga panjangnya sama dengan vector yang lebih panjang. Ini terlihat intuitiv dalam kasus pembuatan data frame. Semua ini berjalan otomatis

Namun bagaimana dengan operasi arimatik? Seperti contoh di atas, dan diilustrasikan dengan dataframe, operasi matematika akan dijalankan per elemen dalam vector. Proses perulangan vector pendek menjadi lebih panjang disebut recycling

Nah sekarang beralih ke kondisi kedua. dalam tibble, proses recycling harus ditulis secara eksplisit.

#ini akan menghasilkan error
tibble(vec_1, vec_2)

Catatan : error ini hanya akan muncul jika vector lainnya bukan scalar

tibble(vec_1,2)
## # A tibble: 10 x 2
##    vec_1   `2`
##    <int> <dbl>
##  1     1     2
##  2     2     2
##  3     3     2
##  4     4     2
##  5     5     2
##  6     6     2
##  7     7     2
##  8     8     2
##  9     9     2
## 10    10     2

Jika kita ingin membuat tibble dengan vector berbeda panjang non-scalar, kita harus mendeskripsikan sendiri dengan fungsi ‘rep()’

tibble(x = vec_1, y = rep(vec_2, each = 5))
## # A tibble: 10 x 2
##        x     y
##    <int> <int>
##  1     1     1
##  2     2     1
##  3     3     1
##  4     4     1
##  5     5     1
##  6     6     2
##  7     7     2
##  8     8     2
##  9     9     2
## 10    10     2

Sedikit rumit karena kita harus menghitung berapa kali vec_2 perlu diulang agar sama dengan vec_1. Sisi positifnya, kita bisa mengatur bagaimana vec_2 atau vector pendek diulang.

Subsetting dan Naming Vector

Kita sudah familiar dengan penggunaan fungsi filter() dari package dplyr untuk menyaring data berdasarkan logika tertentu. Tapi yang perlu kita catat, bahwa fungsi filter hanya bisa digunakan untuk menyaring data pada dataframe dan tibble. Untuk vector sendiri, kita akan menggunakan []. Ada beberapa cara menggunakan [] untuk subset vector : * Menggunakan integer positif – > Integer positif di sini representasi dari posisi value vector yang ingin dipanggil * Menggunakan integer negatif – > Integer negatif berarti membuang value vector yang tidak ingin dipanggil * Menggunakan operasi logika – > kurang lebih sama seperti pada filter.

vec_1[vec_1 > 2] 
## [1]  3  4  5  6  7  8  9 10
vec_2[vec_2 == 3]
## integer(0)
  • Menggunakan nama vector. Untuk memberi nama pada vector, kita bisa melakukannya saat pembuatan vector itu sendiri; baik dengan fungsi set_names() atau menulisnya secara langsung dalam c(). Setelah penamaan, kita bisa memanggil vector terkait dengan vector namanya.
jkl <- c(j = 12, k = 33, l = 39)
greeting <- set_names(40:45, c("hai","halo","thanks", "doumo", "gracias","love"))

jkl[c("l","l","k")]
##  l  l  k 
## 39 39 33
greeting[c("gracias","love","love","thanks")]
## gracias    love    love  thanks 
##      44      45      45      42

Recursive Vector (list)

List adalah bentuk struktur data pengembangan dari vector. Disebut juga recursive vector karena struktur di dalam list berbentuk seperti hierarki; di mana ada vector di dalam vector.

list(1,2,3)
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3

Bisa kita perhatikan, terdapat struktur [[]] dan []. [[]] menandakan subvector pertama, dan [] sub-sub vector pertama.

Kenapa harus berbentuk seperti ini?

Jawaban logis mungkin adalah karena kemampuan list untuk mengandung beragam atomic class yang berbeda. Benar, berbeda dengan vector yang hanya bisa mengandung satu jenis atomic class, list mampu memiliki seluruh atomic class, bahkan termasuk function, dan list itu sendiri.

list2 <- list(1:10, "string", 21L, TRUE, list(1:3))
list2
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## [[2]]
## [1] "string"
## 
## [[3]]
## [1] 21
## 
## [[4]]
## [1] TRUE
## 
## [[5]]
## [[5]][[1]]
## [1] 1 2 3

Lihat betapa membingungkannya data diatas. Jadi memang definisi vector di dalam vector salah untuk mendeskripsikan vector, namun itu bahasa terbaik untuk memudahkan pemahaman saat ini.

Bagaimana cara subsetting list? sama seperti vector, kita bisa menggunakan []; tambahannya, kita bisa menggunakan [[]] dan []. Apa bedanya?

Perbedaan utamanya adalah : dengan [], kita memanggil konten list, dan membungkusnya dalam list baru. Sedangkan dengan [[]], kita memanggil dengan mengeluarkan isinya.

list2[1]
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
list2[4]
## [[1]]
## [1] TRUE
list2[5][1]
## [[1]]
## [[1]][[1]]
## [1] 1 2 3
list2[[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
list2[[5]][1]
## [[1]]
## [1] 1 2 3
list2[[5]][[1]]
## [1] 1 2 3

Mulai paham, kan?

Attributes

Seluruh objek dalam R bisa memiliki attribute tertentu yang berisi metadata dari objek tersebut. Kita bisa membayangkan attribute seperti list dari vector-vector. Kita bisa menggunakan attr() untuk mensetting attribute sebuah objek atau attributes() untuk melihat attribute yang dimiliki.

Ada tiga atribut penting yang digunakan untuk mengimplementasikan bagian mendasar dari R. * Names : digunakan untuk memberi nama vector * Dimensions : atau dims, membuat vector seperti array dan matrix * Class : digunakan untuk mengimplementasikan S3 object oriented system

Kita tidak akan membahas ini terlalu dalam untuk sekarang.

Percobaan :

x1 <- list(
  c(0.27,0.37,0.57,0.91,0.20),
  c(0.90,0.94,0.66,0.63,0.06)
)

x1
## [[1]]
## [1] 0.27 0.37 0.57 0.91 0.20
## 
## [[2]]
## [1] 0.90 0.94 0.66 0.63 0.06