1 R的特性

setClass("Shape")
setClass("Polygon", representation(sides = "integer"), contains = "Shape")
setClass("Triangle", contains = "Polygon")
setClass("Square", contains = "Polygon")
setClass("Circle", contains = "Shape")
pentagon <- new("Polygon", sides = 5L)
pentagon
## An object of class "Polygon"
## Slot "sides":
## [1] 5

1.1 不同的物件

  • R 是物件導向(object-oriented)的語言。物件導向的意思是可以包裹資料或者函數在一個物件。例如指定一個數字性質的向量物件:
  • # Create a vector
    my_vector <- c(1, 2, 3, 4, 5)
    
    # Check its class (shows the type of object)
    class(my_vector)
    ## [1] "numeric"
  • 可以告訴R這個物件的性質,例如:
  • # Add an attribute to the vector object
    attr(my_vector, "description") <- "This is a numeric vector"
    
    # Check the attributes of the object
    attributes(my_vector)
    ## $description
    ## [1] "This is a numeric vector"
  • 可以設定一個函數的物件,例如:
  • # Create a function and assign it to an object
    greet <- function(name) {
      paste("Hello,", name)
    }
    
    # Use the function object
    greet("Alice")
    ## [1] "Hello, Alice"
    greet("Mr. President")
    ## [1] "Hello, Mr. President"
  • R可以指定一個物件或者值(value)給一個名稱(name),不同名稱可以指向同一個物件。例如:
  • a <- c(1, 3, 5); a
    ## [1] 1 3 5
  • 假設a, b是兩個名稱,同時等於c(1,2,3),也就是b複製(copy)a。但是後來把b的第三個元素改成(modify)為10,所以新的b複製了舊的值,但是改變其中一個值。
  • b <- a; b
    ## [1] 1 3 5
    b[[3]] <- 10; b
    ## [1]  1  3 10
  • R的名稱不可以有特殊符號或者是數字在第一個字母,例如無法執行以下的語法:
  • &a <- c(2, 1)
    _b <- c(0, 2, 1)
    1c <- c(1000)
  • 但是「.」可以在第一個字母,名稱也可以加上「``」:
  • .c <- c(10); .c
    ## [1] 10
    `_YB` <- c(1:10); `_YB`
    ##  [1]  1  2  3  4  5  6  7  8  9 10
  • 每一個名稱必須是獨特的,如果出現新的值,R會把名稱指向新的值,舊的值被取代,例如:
  • U <- c(5, 6, 7); U
    ## [1] 5 6 7
    U <- c(9, 10, 11); U
    ## [1]  9 10 11
    • 物件有數字、函數、字串、類別等特性,我們可以自創物件的特性,例如我們先規定一個向量coin:
    coin <- c("heads", "tails")
    • 然後我們告訴R有一個物件coins的特性是coin:
    # object coin via structure()
    coins <- structure(c("heads", "tails"), class = "coin") 
    coins
    ## [1] "heads" "tails"
    ## attr(,"class")
    ## [1] "coin"
    • 我們可以應用這個物件在一個擲銅板的函數。首先應用sample()這個隨機抽樣的函數模擬擲硬幣:
    toss <- function(x, times = 1, p = prob) {
      sample(x, size = times, replace = TRUE, prob = p)
    }
    • 然後測試擲硬幣6次,看看會擲出人頭或者反面:
    # tossing a coin 5 times
    toss(coins, times = 6, p = c(0.55,0.45))
    ## [1] "tails" "heads" "tails" "tails" "tails" "heads"
    • 請問下列語法正確嗎?
    g(x) <- c(1)
    g(x)
    • 請問下列語法正確嗎?
    g <- c(2d)
    g

    1.2 函式

  • 使用者可以用R寫函式(function),由語法構成一連串過程。例如我們想用f這個函式來表示a這一個向量:
  • f <- function(a) {
      a
    }
    f
    ## function(a) {
    ##   a
    ## }
  • 假設有一個向量x,裡面有三個元素:
  • x <- c(1, 2, 3)
    x
    ## [1] 1 2 3
  • 把x放到f函式,得到x。可以用另一個物件z代表f函式:
  • f(x)
    ## [1] 1 2 3
    z <- f(x)
    z
    ## [1] 1 2 3
  • 可以看出x, z都指向同一個向量,但是z是函數,所以可以代入其他的值:
  • z <- f(10-1) ; z
    ## [1] 9
    • 請問以下這個函式會得到什麼?
    h <- function(r){
         pi * r^2
    }
    r <- c(1, 2, 3)
    h(r)

    1.3 列表

  • 列表(list)是另外一種物件,可以儲存值以及值的參照(reference),例如:
  • l1 <- c(1, 2, 3) ; l1
    ## [1] 1 2 3
  • 我們也可以創造一個新的變數,不去變動舊的變數:
  • l1 <- c(1, 2, 3) 
    l2 <- l1; l2
    ## [1] 1 2 3
    l2[[3]] <- 20; l2
    ## [1]  1  2 20
    • R的講義有提到列表的特性之一是可以允許不同長度的變數,例如:
    A.l <- list(a=c(1,2,3), b = c('D', 'E', 'F', 'G'),
                c = c(1L, 2L, 3L, 4L, 5L))
    A.l
    ## $a
    ## [1] 1 2 3
    ## 
    ## $b
    ## [1] "D" "E" "F" "G"
    ## 
    ## $c
    ## [1] 1 2 3 4 5
  • 利用list儲存計算結果:
  • # Function 1: Calculates the sum and product of two numbers
    calculate_sum_product <- function(a, b) {
      sum_result <- a + b
      product_result <- a * b
      return(list(a=a, b=b, sum = sum_result, product = product_result))
    }
    A <- calculate_sum_product(c(1, 2, 3), 2)
    A
    ## $a
    ## [1] 1 2 3
    ## 
    ## $b
    ## [1] 2
    ## 
    ## $sum
    ## [1] 3 4 5
    ## 
    ## $product
    ## [1] 2 4 6
  • 請試試以下的語法:
  • x1 <- list(y = 1:10)
    x2 <- x1
    x1; x2
    x2[[1]]

    1.4 資料框

  • 列表可以構成資料框(data frame),例如:
  • d1 <- data.frame(x = c(1, 5, 6), y = c(2, 6, 7))
    d1
    ##   x y
    ## 1 1 2
    ## 2 5 6
    ## 3 6 7
  • 我們可以複製另外一個資料框d2,然後對第2欄乘以2,得到新的資料:
  • d2 <- d1; d2
    ##   x y
    ## 1 1 2
    ## 2 5 6
    ## 3 6 7
    d2[, 2] <- d2[, 2] * 2; d2
    ##   x  y
    ## 1 1  4
    ## 2 5 12
    ## 3 6 14

    1.4.1 tibble

  • 另外一種比較現代的資料框是\(\texttt{tibble()}\)創造,例如
  • # Install if you haven't already: install.packages("tibble")
    library(tibble)
    
    df_tibble <- tibble(
      Name = c("Alice", "Bob", "Charlie", "Mario"),
      Age = c(25, 30, 28, 40),
      City = c("New York", "London", "Paris", "Florence"),
      Nation =c("US")
    )
    
    print(df_tibble)
    ## # A tibble: 4 × 4
    ##   Name      Age City     Nation
    ##   <chr>   <dbl> <chr>    <chr> 
    ## 1 Alice      25 New York US    
    ## 2 Bob        30 London   US    
    ## 3 Charlie    28 Paris    US    
    ## 4 Mario      40 Florence US
    • 注意到最後一欄原本只輸入一個’US’,系統自動填滿其他沒有資料的空格。

    1.5 文字(character)

  • 向量可以容納文字的資料,例如:
  • x <- c('a', 'a', 'abc', 'd')
    class(x)
    ## [1] "character"
  • 字串(string)則指的是文字資料,而不像是character,是一種類別。
  • 有一個套件叫做
    stringr
    ,有很多跟字串有關的功能,例如\(\texttt{str_trim}()\)刪除字串內前後多餘的空白:
  • library(stringr)
    x <- c("  a   ", "b   ",  "   c", "d e  ff")
    x
    ## [1] "  a   "  "b   "    "   c"    "d e  ff"
    str_trim(x)
    ## [1] "a"       "b"       "c"       "d e  ff"

    1.6 環境(environment)

  • 環境的功能是連接一組的名稱(names)與一組的值(values)。想像有一個袋子,裡面裝了一些名稱,沒有特定的順序。我們目前所在的環境稱為Global environment:
  • rlang::current_env()
    ## <environment: R_GlobalEnv>
  • 我們可以創造一個新的環境:
  • e1 <- rlang::env(
      a = FALSE,
      b = "a",
      c = 2.3,
      d = 1:3,
      e = 3L,
    ); rlang::env_names(e1)
    ## [1] "a" "b" "c" "d" "e"
  • 在e1這個環境中有一個a,這個a不同於在Global Environment裡面的a。也就是說,我們可以在不同環境,指定同一名稱給不同的值:
  • e1$a
    ## [1] FALSE
    a
    ## [1] 1 3 5
    identical(e1$b, b)
    ## [1] FALSE
  • 一個環境中可以容納另一個環境:
  • e1$d <- e1
    rlang::env_names(e1)
    ## [1] "a" "b" "c" "d" "e"
  • 可以複製一個環境到一個新的環境,舊的環境會被新環境取代:
  • e2 <- rlang::as_environment(e1)
    rlang::env_names(e2)
    ## [1] "a" "b" "c" "d" "e"

    1.7 套件(package)

    • 套件指的是包含函式或者資料,以及相應說明的一個有結構的物件。
    • 例如在base這個套件中,有一個函式typeof,它可以回傳我們想知道的物件的性質:
    x <- 8; 
    base::typeof(x)
    ## [1] "double"
    base::typeof('a')
    ## [1] "character"
    • 我們用函數來舉例:
    hello <- function() {
      print('Hello, world!')
    }
    class(hello)
    ## [1] "function"
    typeof(hello)
    ## [1] "closure"
    • R顯示closure,意思為這個函數所用到的指令以及變數都已經在所處的環境之中。

    • 藉由套件,我們可以使用各種現有的語法、資料。當R不斷一直擴充,而且是免費使用,我們就不斷有新的工具。

    1.7.1 Namespace

  • 由於R有許多套件,不同套件裡面的函數可能有同樣的命名。R的套件(package)有一個介面稱為套件環境,我們可以告訴R要用哪一個套件裡面的功能,以免R需要搜尋所有的套件。例如cardplyr有同樣的recode()功能;
  • J <- c(1, 2, 3, 3, 4, 4, 5, 5, 5, 95, 97, 98)
    J1 <- car::recode(J, "1:2=1; 3=2; 4:5=3; 95:98=NA"); J1
    ##  [1]  1  1  2  2  3  3  3  3  3 NA NA NA
    J2 <- dplyr::recode(J, `1`='1', `2`='1', `3`='2', `4`='3', `5`='3', .default = NA_character_); J2 <- as.numeric(J2); J2
    ##  [1]  1  1  2  2  3  3  3  3  3 NA NA NA
    • 函數的名稱一樣,但是寫法不一樣,如果沒有告訴R要用哪一個套件底下的語法,R會去使用已經載入的套件,但是這不一定是使用者想要的套件。

    • 未來上課時我們會盡量寫namespace,以免混淆。

    2 功能

    2.1 統計

    • R有許多統計的套件,從描述統計到多變量分析都有,還有抽樣、加權等等跟調查相關的套件。

    2.2 機器學習

    • R有機器學習的套件,可以給它資料、隨機分派之後估計模型,然後應用在沒有被訓練的資料,比較預測值以及觀察值的差距。

    2.3 爬網路資料

    • R可以結合善於儲存樹狀結構資料的JSON,下載網路上的資料:
    library(httr)
    library(jsonlite)
    options(stringsAsFactors = F)
    
    url_sc_flu <- "https://od.cdc.gov.tw/eic/Weekly_Age_County_Gender_487a.json"
    
    df <- fromJSON(content(GET(url_sc_flu), "text", encoding = "utf-8"))
    head(df)
    ##   確定病名 發病年份 發病週別   縣市   鄉鎮 性別 是否為境外移入 年齡層
    ## 1     487a     2003        2 新北市 永和區    M              0  10~14
    ## 2     487a     2003        3 台北市 中正區    M              0      3
    ## 3     487a     2003        3 新北市 永和區    F              0      4
    ## 4     487a     2003        4 台北市 大同區    F              0      3
    ## 5     487a     2003        5 新北市 汐止區    M              0      0
    ## 6     487a     2003        5 新北市 汐止區    M              0      2
    ##   確定病例數 縣市別代碼 鄉鎮別代碼
    ## 1          1      65000   65000040
    ## 2          1      63000   63000050
    ## 3          1      65000   65000040
    ## 4          1      63000   63000060
    ## 5          1      65000   65000110
    ## 6          1      65000   65000110
    • 如果想要抓現成的網頁表格,例如選研中心網站上面公布的總統選舉結果,可以這樣做:
    #load package
    library(rvest); library(tidyverse); library(rLTP)
    
    #webpage
    webp2020 <-"http://vote.nccu.edu.tw/cec/vote312.asp?pass1=I:8:8IAA8888888888"
    
    #list
    presd2020 <- list()
    
    #read html in a list with correct encoding
    presd2020 <-read_html(webp2020, encoding = "BIG5") %>%
      html_nodes(xpath='//table') %>%
      html_table()
    
    #data frame
    presd2020.dt <- presd2020[[1]]
    
    #rename the column names as the first row and delete the first row
    rownames(presd2020.dt) <-NULL
    colnames(presd2020.dt) <- presd2020.dt[1, ]
    presd2020.dt <- presd2020.dt[-1, ]
    
    #Done!
    head(presd2020.dt)
    ## # A tibble: 6 × 5
    ##   地區   姓名   號次  得票數 得票率  
    ##   <chr>  <chr>  <chr> <chr>  <chr>   
    ## 1 宜蘭縣 宋楚瑜 01    10739  3.9135% 
    ## 2 宜蘭縣 韓國瑜 02    90010  32.8018%
    ## 3 宜蘭縣 蔡英文 03    173657 63.2847%
    ## 4 新竹縣 宋楚瑜 01    18435  5.6716% 
    ## 5 新竹縣 韓國瑜 02    154224 47.4478%
    ## 6 新竹縣 蔡英文 03    152380 46.8805%
    • 遇到新聞網站、論壇、PTT等等HTML網頁,透過CSS規則找出連結的位置,就能寫R全部下載所有連結,然後把每個連結後面的發言存到自己的電腦。參考台大新聞所謝吉隆教授撰寫的語法:
    query = "指南宮"
    pre <- "https://www.ptt.cc"
    url <- str_c("https://www.ptt.cc/bbs/gossiping/search?page=", 1, "&q=", query)
    post.df <- data_frame()
    for(page in 1:8){
        url <- str_c("https://www.ptt.cc/bbs/gossiping/search?page=", page, "&q=", query)
        print(url)
        doc <- GET(url, config = set_cookies("over18" = "1")) %>%
            content("text") %>%
            read_html()
        nodes <- doc %>% html_nodes(".r-ent")
        nrec <- nodes %>% html_node(".nrec span") %>% html_text() %>% as.numeric()
        title <- nodes %>% html_node(".title a") %>% html_text()
        link <- nodes %>% html_node(".title a") %>%  html_attr("href") %>%
            str_c(pre, .)
        author <- nodes %>% html_node(".meta .author") %>% html_text()
        page.df <- data_frame(nrec, title, link, author)
        
        post.df <- bind_rows(post.df, page.df)
        #print(nrow(post.df))
    }
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=1&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=2&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=3&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=4&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=5&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=6&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=7&q=指南宮"
    ## [1] "https://www.ptt.cc/bbs/gossiping/search?page=8&q=指南宮"
    
    #View data
    head(post.df)
    ## # A tibble: 2 × 4
    ##    nrec title                                         link                author
    ##   <dbl> <chr>                                         <chr>               <chr> 
    ## 1     2 [新聞] 赴指南宮參拜祈福 蕭美琴:盼正能量遍全  https://www.ptt.cc… seiya…
    ## 2     2 Re: 有哪些是情侶不能去的觀光地啊→關於指南宮? https://www.ptt.cc… ck517

    2.4 繪圖

    • R可以根據統計模型或者數學模型繪圖,也可以結合地理資訊繪圖。

    2.4.1 地理資訊繪圖

    #install.packages(c("maps", "mapdata", "ggplot2"))
    # Load necessary libraries
    library(ggplot2)
    library(maps)
    library(mapdata)
    
    # Extract Taiwan map data
    taiwan <- map_data("world", region = "Taiwan")
    
    # Define the coordinates of six metropolitan cities
    metropolitan_cities <- data.frame(
      city = c("Taipei", "New Taipei", "Taichung", "Tainan", "Kaohsiung", "Taoyuan"),
      lon = c(121.5654, 121.4619, 120.6700, 120.2790, 120.3120, 121.2168),
      lat = c(25.0320, 25.0160, 24.1477, 22.9997, 22.6273, 24.9936)
    )
    
    # Plot the map of Taiwan
    ggplot() +
      geom_polygon(data = taiwan, aes(x = long, y = lat, group = group), fill = "grey80", color = "black") +
      geom_point(data = metropolitan_cities, aes(x = lon, y = lat), size = 3, color = "red") +
      geom_text(data = metropolitan_cities, aes(x = lon, y = lat, label = city), vjust = -0.5, size = 3, color = "black") +
      labs(title = "Map of Taiwan with Six Metropolitan Cities") +
      theme_minimal() +
      theme(plot.title = element_text(hjust = 0.5))

    2.4.2 數學函數繪圖

    • 如果有一個數學函數\(2x^2+1\)R可以畫出某個X範圍的圖形:
    # Load necessary libraries
    library(ggplot2)
    
    # Define the function
    f <- function(x) 2*x^2 + 1
    
    # Generate x values
    x <- seq(-5, 5, length.out = 100)
    
    # Generate y values
    y <- f(x)
    
    # Create a data frame with x and y values
    df <- data.frame(x = x, y = y)
    
    # Plot the function
    ggplot(df, aes(x, y)) +
      geom_line(color = "blue") +
      labs(title = "Plot of f(x) = 2x^2 + 1") +
      xlab("x") +
      ylab("f(x)") +
      theme_minimal()

    2.5 數學

    • R 可以處理最簡單的數學到微積分,只要給它正確的函數,它就能計算微積分的結果。例如:
    #install.packages("Deriv")
    library(Deriv)
    
    # Define the function
    f <- expression(x^3 + 2*x^2 + 9*x)
    
    # Differentiate the function with respect to x
    df_dx <- Deriv(f, "x")
    
    # Print the result
    print(df_dx)
    ## expression(9 + x * (3 * x + 4))

    2.6 文件

    • 可以用R做html, LaTex等文件,並且結合來自統計模型的圖形以及表格。

    3 R and ChatGPT

    4 更新內容日期

    ## 最後更新日期 02/08/2025