2 Base R (I) & 輔助工具

(投影片 / 影片)

2.1 R Studio

2.1.1 自訂樣式

  • RStudio 預設有 4 個區塊 (Pane)。你可以自行決定這 4 個區塊的位置
    • Tools –> Global Options... –> (在左欄選擇) Pane Layout
    • Source, Console, 及 2 個自訂區塊
  • 除了區塊的相對位置,也可以設定 RStudio 整體的風格以及程式碼 Syntax Highlighting 的樣式:
    • Tools –> Global Options... –> (在左欄選擇) Appearance

2.1.2 編輯器設定

  • Source Pane 是撰寫程式碼的地方 (文字編輯器)
    • 縮排間距:建議使用 space (而非 tab) 作為縮排字元

      • Tools –> Global Options... –> (在左欄選擇) Code –> (在上方選擇) Editing –> 勾選 Insert spaces for tab
    • 文字編碼:由於中文字在各作業系統上會有編碼不一致的問題,請務必將編碼設定為 UTF-8

      • Tools –> Global Options... –> (在左欄選擇) Code –> (在上方選擇) Saving –> Default text encoding

2.1.3 工作目錄

  • 使用 RStudio 時,最好養成要馬上設置「工作目錄」的習慣。

  • RStudio 所在的「工作目錄」顯示於 Console Pane 的標籤下方 (e.g. ~/)

  • 工作目錄的設置方式

    • RStudio 功能選單: Sessions > Set Working Directory...

    • Console

      setwd('~/Desktop/week2')
      # setwd('<path/to/new_working_dir>')
      getwd()  # show current directory

2.2 函數

get_area <- function() {
    area <- 3.14 * 1 * 1
    return(area)
}
get_area()
#> [1] 3.14
# Function with a argument
get_area <- function(r) {
    area <- 3.14 * r * r
    return(area)
}
get_area(2)
#> [1] 12.56
# Function with a argument that has default value
get_area <- function(r = 1) {
    area <- 3.14 * r * r
    return(area)
}
get_area()
#> [1] 3.14
get_area <- function(r) {
    area <- 3.14 * r * r
    return(area)
}
area <- 100
area
get_area(1)
area
#> [1] 100
#> [1] 3.14
#> [1] 100

2.3 Function Arguments

vol <- function(r, height = 1) {
    volumn <- 3.14 * r * r * height
    return(volumn)
}
vol(1, 2)
#> [1] 6.28
vol(r = 1, height = 2)  # Be explicit
#> [1] 6.28
# If all args are named, order doesn't matter
vol(height = 2, r = 1)
#> [1] 6.28
# Mix named and unnamed args:
# named args will be assigned first, then
# unnamed args will be assigned 
# based on their positions
vol(height = 2, 1)
#> [1] 6.28

2.4 vector

  • 上週實習課使用 R 時,指令的回傳值多半只有「一個」。但 R 其實是一種以向量作為基本單位的程式語言,所以對於「一個回傳值」更精確的描述應該是「一個長度為 1 的向量」。

    x <- 2
    x
    #> [1] 2
    #> [1] TRUE
    #> [1] 1
  • 我們上週簡短提過以 : 製造數列的方式 (e.g. 1:10)。事實上,這個回傳的數列即是一個 vector。另外,由於這個 vector 的每個元素皆是整數,因此這個 vector 屬於 integer vector。我們可以使用 typeof() 確認 vector 的類別

    typeof(1:10)
    #> [1] "integer"
  • R 裡面的 vector 可以被分成 6 種類別,其中常見的 4 種分別為 integer, double, , character, logical

2.4.1 integer vector

  • integer vector 的元素由整數組成,它可以是零、正或負的。除了使用 : 製造數列,也可以使用 c() (稱為 concatenate) 組出任意序列的 vector。
    • 使用 c() 製造 integer vector 時,每個整數數字後面必須接 L,若沒有加上 L, R 會將製造出來的 vector 視為 double vector。
int_vec <- c(-1L, 5L, 2L)
dbl_vec <- c(-1, 5, 2)
int_vec
#> [1] -1  5  2
dbl_vec
#> [1] -1  5  2
typeof(int_vec)
#> [1] "integer"
typeof(dbl_vec)
#> [1] "double"

2.4.2 double vector

  • double vector 儲存的是浮點數,亦即含有小數點的數字 (e.g 1.2, -0.75)

  • 在 R 裡面,integer vector 與 double vector 合稱為 numeric vector,兩者之間的區隔通常也不太重要,因為 R 在運算時,通常會將這兩種資料類型自動轉換成合適的類型

    typeof(2L)
    #> [1] "integer"
    typeof(2.0)
    #> [1] "double"
    #> [1] TRUE
    #> [1] TRUE
    typeof(1L + 1.0)
    #> [1] "double"
    typeof(1L / 2L)
    #> [1] "double"
  • Special values:

    • Inf: 代表無限大

    • NaN: “Not a Number”,常見於數字運算不符數學定義時,例如:

      0 / 0
      #> [1] NaN
      Inf / Inf
      #> [1] NaN
      log(-1)
      #> Warning in log(-1): NaNs produced
      #> [1] NaN

2.4.3 character vector

  • 除了數字以外,R 也可以儲存字串 (string)。character vector 的每個元素皆由一個字串所組成。在 R 裡面,只要是被引號 (quote, '" 皆可) 包裹的東西就是字串,放在引號內的可以是任何字元 (e.g. 空白、數字、中文字、英文字母)

    "1.1"  # This is a string (character vector of length 1), not double
    #> [1] "1.1"
    "你好!"
    #> [1] "你好!"
    c("1.1", "你好!")
    #> [1] "1.1"    "你好!"
  • 如果字串內含有引號 ",需在字串內的引號前使用跳脫字元 \,以表示此引號是字串的一部分而非字串的開頭或結尾

    • 或是,你可以使用「不同的」引號。例如以「單引號」表示字串的開頭與結尾時,字串內就可以直接使用「雙引號」,反之亦然
    "\""  # escape a double quote
    '\''  # escape a single quote
    '"'   # a double quote as string without escaping
    "'"   # a single quote as string without escaping
    #> [1] "\""
    #> [1] "'"
    #> [1] "\""
    #> [1] "'"

2.4.4 logical vector

  • logical vector 的每個元素由 TRUEFALSE 組成。

  • 可以使用 c() 一項項手動輸入製造 logical vector

  • logical vector 的另一個來源則是 logical test 的回傳值:

    vec1 <- c(1, 1, 1)
    vec2 <- c(2, 0, 2)
    # logical tests
    vec1 > vec2
    #> [1] FALSE  TRUE FALSE
    vec1 < vec2
    #> [1]  TRUE FALSE  TRUE
    vec1 == vec2
    #> [1] FALSE FALSE FALSE
  • boolean operators (&, |, !, any(), all()) 可以整合多個 logical tests

    TRUE & TRUE
    #> [1] TRUE
    TRUE & FALSE
    #> [1] FALSE
    TRUE | FALSE
    #> [1] TRUE
    !TRUE
    #> [1] FALSE
    (1 == 1) & (2 == 2)
    #> [1] TRUE

2.4.5 NA

  • NA 代表的是「缺失值」,可以作為任何一種 vector 裡面的元素。當 NA 出現在 vector 中,函數對於 vector 的運算常會出現令人意外的結果:

    10 > NA
    #> [1] NA
    NA == NA
    #> [1] NA
    vec <- c(1, NA, 2, 3)
    mean(vec)
    #> [1] NA
    mean(vec, na.rm = TRUE)
    #> [1] 2

2.5 Recycling

  • 兩個或兩個以上的 vector 進行運算時,通常是以 element-wise 的方式進行。此時,若進行運算的 vector 長度不相同,例如,c(1, 2, 3) + 2, R 會自動將長度較短 vector (2) 「回收 (recycle)」,亦即,重複此向量內的元素使其「拉長」到與另一個 vector 等長;接著再將兩個一樣長的 vector 進行 element-wise 的向量運算。
x <- c(1, 1, 2, 2)

# Arithmetic operation
x + 2  # equivalent to...
#> [1] 3 3 4 4
x + c(2, 2, 2, 2)
#> [1] 3 3 4 4
x <- c(1, 1, 2, 2)

# Logical operation
x == 2  # equivalent to...
#> [1] FALSE FALSE  TRUE  TRUE
x == c(2, 2, 2, 2)
#> [1] FALSE FALSE  TRUE  TRUE
# String operation
long <- c("a", "b", "c")
short <- "1"
paste0("a", "1")
#> [1] "a1"
paste0(long, short)
#> [1] "a1" "b1" "c1"

2.6 Coercion

  • vector 內的每個元素,其資料類型 (data type) 必須相同。資料類型即是前面提到的 integer, double, character, logical

  • 若發生資料類型不一致的情形 (e.g. 將不同資料類型的元素放入 c()),R 會根據某些規則自動進行資料類型的轉換。這個過程在 R 裡面稱為 Coercion

    c(TRUE, FALSE, 3)      # logical & numeric
    #> [1] 1 0 3
    c(-1, "aa")            # numeric & character
    #> [1] "-1" "aa"
    c(FALSE, TRUE, "hi!")  # logical & character
    #> [1] "FALSE" "TRUE"  "hi!"
    c(TRUE, 0, "hi!")      # logical & numeric & character
    #> [1] "TRUE" "0"    "hi!"
Rules of Coercion

Figure 2.1: Rules of Coercion

sum(c(T, T, T, F))
#> [1] 3
gender <- c("male", "female", "male", "female")
sum(gender == "male")  # num of male
#> [1] 2
mean(gender == "male")  # proportion of male
#> [1] 0.5

2.7 Subsetting a vector

  • 有 3 種方法可用於取出 vector 裡面的元素 (回傳一個新的 vector)
    1. 透過提供 vector 中元素的位置次序 (index)
    2. 透過一個與此 vector 等長的 logical vector。在 logical vector 中的相對應位置,以 TRUEFALSE 表示是否保留該位置的元素
    3. 透過提供元素的「名字」(i.e. names 屬性)

2.7.1 index subsetting

# z[<integer_vector>]
LETTERS  # R 內建變數: 包含所有大寫英文字母的 character vector
#>  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
#> [20] "T" "U" "V" "W" "X" "Y" "Z"
LETTERS[1]
#> [1] "A"
LETTERS[1:5]
#> [1] "A" "B" "C" "D" "E"
LETTERS[c(1, 3, 5)]
#> [1] "A" "C" "E"
LETTERS[-(1:5)]  # Exclude the first 5 elements
#>  [1] "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X"
#> [20] "Y" "Z"

2.7.2 Logical subsetting

# z[<logical_vector of length(z)>]
age <- c(21, 20, 18, 19)
age[c(FALSE, TRUE, FALSE, TRUE)]
#> [1] 20 19
## Creating logical vectors
age[1] < 20  # returns a logical vector of length 1
#> [1] FALSE
age < 20     # returns a logical vector of length(x)
#> [1] FALSE FALSE  TRUE  TRUE
# Subset a vector using a logical test
age[age < 20]
#> [1] 18 19

2.7.3 Subsetting with names

age <- c(40, 20, 18, 19)
names(age) <- c("kai", "pooh", "tiger", "piglet")
# age <- c(kai = 40, pooh = 20, tiger = 18, piglet = 19)  # another way of setting names

age
#>    kai   pooh  tiger piglet 
#>     40     20     18     19
age['kai'] + 9
#> kai 
#>  49
age[c('pooh', 'kai')]
#> pooh  kai 
#>   20   40

2.7.4 Modifying Values in vector

a2z <- LETTERS
a2z[1:3] <- c("a", "b", "c")
a2z
#>  [1] "a" "b" "c" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
#> [20] "T" "U" "V" "W" "X" "Y" "Z"
gender <- c("m", "m", "f", "f")
gender[gender == "m"] <- "male"
gender
#> [1] "male" "male" "f"    "f"
gender[gender == "f"] <- "female"
gender
#> [1] "male"   "male"   "female" "female"
names(gender) <- c("john", "jenny", "jane", "kate")
gender
#>     john    jenny     jane     kate 
#>   "male"   "male" "female" "female"
gender["john"] <- "male"
gender
#>     john    jenny     jane     kate 
#>   "male"   "male" "female" "female"
gender[c("jenny", "jane", "kate")] <- "female"
gender
#>     john    jenny     jane     kate 
#>   "male" "female" "female" "female"

2.8 if else

  • 一般而言,R 是由上至下一行一行地執行程式碼。有時候我們會希望能跳過某些程式碼或是依據不同的狀況執行不同的程式碼,這時候我們就需要使用條件式
x <- 1

if (x > 0) {
    print('x is positive')
} else {
    print('x is not positive')
}
#> [1] "x is positive"
x <- -1

if (x > 0) {
    print('x is positive')
} else if (x < 0) {
    print('x is negative')
} else {
    print('x is zero')
}

print('This is always printed')
#> [1] "x is negative"
#> [1] "This is always printed"
  • if-else if-else 的結構中,只有其中一個區塊 (被大括弧 {} 包裹的程式碼) 會被執行。執行完該區塊後,就會忽略剩下的條件控制區塊,執行條件式之後的程式碼。

  • 可以在 if 之後使用多個 else if.

  • 條件式的結構:

    # 只有 if
    if (<條件>) {
        <Some Code>  # 條件成立時執行
    }
    
    # if, else
    if (<條件>) {
        <Some Code>  # <條件>成立時執行
    } else {
        <Some Code>  # <條件>不成立時執行
    }
    
    # if, else if, else
    if (<條件1>) {
        <Some Code>          # <條件1>成立時執行
    } else if ( <條件2> ) {
        <Some Code>          # <條件1>不成立、<條件2>成立時執行
    } else {
        <Some Code>          # <條件1>、<條件2>皆不成立時執行
    }

2.9 Wrap up: 句子產生器

# Data
name <- c("kai", "pooh", "tiger", "piglet")
age <- c(40, 20, 18, 19)

# Randomly draw 2 subjects
who <- sample(1:4, size = 2)

# Find out who is older
age1 <- age[who[1]]
age2 <- age[who[2]]
if (age1 > age2) {
    comparitive <- ' is older than '
} else if (age1 < age2) {
    comparitive <- ' is younger than '
} else {
    comparitive <- ' is as old as '
}

# Construct sentence
paste0(name[who[1]], comparitive, name[who[2]])
#> [1] "piglet is younger than kai"

2.10 R Markdown

  • 使用前需先安裝 rmarkdown:

    install.packages('rmarkdown')
  • R Markdown (.Rmd) 就像之前同學用來寫自我介紹的 Markdown 文件 (.md) 一樣是一種純文字格式。R Markdown 的語法其實只是 Markdown 的一種擴充:它新增了一些特殊的語法,讓使用者可以直接在 R Markdown 裡面撰寫程式碼,並透過 R 將這些程式碼的運算結果插入 R Markdown 的輸出文件當中。

  • knitr Code Chunk

    • 執行:由上至下執行
    • 後面的 chunk 可以讀取之前的 chunks 產生的變數

(在 RStudio 使用 R Markdown)

  • 使用 RStudio 開啟 R Markdown (.Rmd) 時,Rmd 檔會出現在 Source Pane 讓使用者編輯

  • 將 R Markdown (.Rmd) 輸出 (knit )成 HTML 檔 (.html):

R Markdown document in RStudio^[Figure from https://bookdown.org/yihui/rmarkdown/images/hello-rmd.png].

Figure 2.2: R Markdown document in RStudio10.

參考資源

  1. Grolemund, G. (2014). Hands-on programming with R
    R Objects (https://rstudio-education.github.io/hopr/r-objects)
    Modifying Values (https://rstudio-education.github.io/hopr/modify)

  2. Xie, Y., Allaire, J., & Grolemund, G. (2019). R Markdown: The Definitive Guide