1 什麼是R

  • R 是物件導向的語言。R可以指定一個物件(object)或者值(value)給一個名稱(name),不同名稱可以指向同一個物件。例如:
  • a <- c(1, 3, 5); a
    ## [1] 1 3 5
    b <- a; b
    ## [1] 1 3 5
    b[[3]] <- 10; b
    ## [1]  1  3 10

    1.1 物件(object)

  • a, b是兩個名稱,同時等於c(1,2,3),也就是b複製(copy)a。但是後來把b的第三個元素改成(modify)為10,所以新的b複製了舊的值,但是改變其中一個值。
  • 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] "heads" "heads" "heads" "heads" "tails" "heads"

    1.2 函數

  • 使用者可以用R寫函數(function),這裡的函數指的是由語法所構成的計算過程。例如我們想用z這個函數來表示a這一個向量:
  • f <- function(a) {
      a
    }
    x <- c(1, 2, 3)
    x
    ## [1] 1 2 3
    z <- f(x)
    z
    ## [1] 1 2 3
  • 可以看出x, z都指向同一個向量,但是z是函數,所以可以代入其他的值:
  • z <- f(`_YB`) ; z
    ##  [1]  1  2  3  4  5  6  7  8  9 10

    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
  • 請試試以下的語法:
  • 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.5 文字(character)

  • 向量可以容納文字的資料,例如:
  • x <- c('a', 'a', 'abc', 'd')
    x
    ## [1] "a"   "a"   "abc" "d"
  • 文字向量包含的是字串(string),而不是個別的字母。在R裡面有一個字串的大水庫,R的文字向量只是納入其中一部分。
  • 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 流感併發重症     2003        2 新北市 永和區    M             否  10-14
    ## 2 流感併發重症     2003        3 台北市 中正區    M             否      3
    ## 3 流感併發重症     2003        4 台北市 大同區    F             否      3
    ## 4 流感併發重症     2003       46 彰化縣 埔心鄉    M             否  45-49
    ## 5 流感併發重症     2003       47 新北市 新莊區    F             否      3
    ## 6 流感併發重症     2003        5 新北市 汐止區    M             否      0
    ##   確定病例數
    ## 1          1
    ## 2          1
    ## 3          1
    ## 4          1
    ## 5          1
    ## 6          1
    • 如果想要抓現成的網頁表格,例如選研中心網站上面公布的總統選舉結果,可以這樣做:
    #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     7 [新聞] 心結?指南宮大典侯柯同台獨缺賴清德    https://www.ptt.cc… Mesen…
    ## 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/22/2024