--- disqus: yueswater --- # R 語言與 tidyverse 套件 {%hackmd @themes/orangeheart %} <style> .likecoin-button { position: relative; width: 100%; max-width: 485px; max-height: 240px; margin: 0 auto; } .likecoin-button > div { padding-top: 49.48454%; } .likecoin-button > iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style> ###### tags: `R Language` <!-- 參考文件:https://statacumen.com/teach/ShortCourses/R_Programming/IntroTidyverse_ACASA_201802/Erhardt_RTidyverse_20180216.pdf --> ## 安裝 tidyverse 套件 首先我們需要安裝`tidyverse`套件,其中包含`ggplot2`、`tibble`、`dplyr`等重要的相依套件。 ```r install.packages("tidyverse") library(tidyverse) ## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ── ## ✔ ggplot2 3.3.6 ✔ purrr 0.3.4 ## ✔ tibble 3.1.8 ✔ dplyr 1.0.10 ## ✔ tidyr 1.2.1 ✔ stringr 1.4.1 ## ✔ readr 2.1.2 ✔ forcats 0.5.1 ## ── Conflicts ────────────────────────────────────────────tidyverse_conflicts() ── ## ✖ dplyr::filter() masks stats::filter() ## ✖ dplyr::lag() masks stats::lag() ``` 接著引用套件: ```r library(tidyverse) ``` `tidyverse`套件很可愛地提供了`tidyverse_logo()`這個函式,使用後就可以看到`tidyverse`的 logo。 ```r tidyverse_logo() ⬢ __ _ __ . ⬡ ⬢ . / /_(_)__/ /_ ___ _____ _______ ___ / __/ / _ / // / |/ / -_) __(_-</ -_) \__/_/\_,_/\_, /|___/\__/_/ /___/\__/ ⬢ . /___/ ⬡ . ⬢ ``` ## 開始使用 tidyverse:暖身操 在正式使用`tidyverse`之前,首先要來介紹一些好用的指令。相信如果有看過其他人使用`tidyverse`套件的程式碼的人,一定對`%>%`指令不陌生,但它代表什麼意思呢?這個指令叫做 **pipe**,中文可以翻譯成**通道**(但我不喜歡用這個翻譯,所以下面一律都會使用 pipe),這個指令提供我們能夠將兩個東西進行連接,有點類似合成函數的概念(但不完全是)。舉例來說 ``` x %>% f(y) ``` 會等於`f(x, y)`,而 ``` x %>% f(y) %>% g(z) ``` 會等於`g(f(x, y), z)`。我們使用`tidyverse`套件中的汽車資料`mpg`來做實例: :::info **小試身手:`%>%`的操作** 使用`%>%`找出`mpg`資料庫變數與觀察值數量 :::spoiler 查看參考答案 ```r ## 變數數量 mpg %>% colnames() %>% length() ## 觀察值數量 mpg %>% rownames() %>% length() ``` ::: ### tibble 的操作 `tibble`可以視為`data.frame`資料型別的進階版,基本上使用方式都相同,只是加上了一些額外的功能。如果我們要將原本的`data.frame`型別轉換成`tibble`,可以使用`as_tibble()`函式(`tibble 2.0.0.`版本已經將原本的`as.tibble()`換掉了,因此要使用文中的函式)。 ```r mpg <- as_tibble(mpg) head(mpg) # A tibble: 6 × 11 ## manufacturer model displ year cyl trans drv cty hwy fl class ## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr> ## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact ## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact ## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compact ## 4 audi a4 2 2008 4 auto(av) f 21 30 p compact ## 5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact ## 6 audi a4 2.8 1999 6 manual(m5) f 18 26 p compact class(mpg) ## [1] "tbl_df" "tbl" "data.frame" ``` 我們也可以用`glimpse()`或`str()`函式查看資料。 #### 手動創建 tibble 如同`data.frame`型別一般,我們也可以手動創建`tibble`: ```r tibble( x = 1 : 6, y = 2, z = log(x) + y ) # A tibble: 6 × 3 ## x y z ## <int> <dbl> <dbl> ## 1 1 2 2 ## 2 2 2 2.69 ## 3 3 2 3.10 ## 4 4 2 3.39 ## 5 5 2 3.61 ## 6 6 2 3.79 ``` 或是以轉置(transposed)的方式創建,我們使用`tribble`函式。 ```r tribble( ~x, ~y, ~z, "你好", 1, TRUE, "早安", 3.2, NA ) # A tibble: 2 × 3 ## x y z ## <chr> <dbl> <lgl> ## 1 你好 1 TRUE ## 2 早安 3.2 NA ``` #### 印出指定行、列數 如果我們想要指定`tibble`印出指定的行(column)、列(row)數,我們可以在`print()`函數中指定。 ```r mpg %>% print(n = 3, width = Inf) # A tibble: 234 × 11 ## manufacturer model displ year cyl trans drv cty hwy fl class ## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr> ## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact ## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact ## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compact ``` 上面的程式碼代表我們印出 3 行與所有欄位的`mpg`資料。 #### 取出特定行、欄 我們可以使用`$`或`[[]]`來查看資料。 ```r tbl <- tibble( x = runif(5), y = rnorm(5) ) ## check the x column tbl$x ## [1] 0.7007443 0.3922571 0.6044753 0.6750059 0.9717587 tbl[[1]] ## [1] 0.7007443 0.3922571 0.6044753 0.6750059 0.9717587 ## using pipe tbl %>% .$x ## [1] 0.7007443 0.3922571 0.6044753 0.6750059 0.9717587 tbl %>% .[[1]] ## [1] 0.7007443 0.3922571 0.6044753 0.6750059 0.9717587 ``` ## 讀取資料 `tidyverse`提供了使用者匯入資料的相依套件。以下我們就簡單介紹: - `readr`:可匯入`.csv`、`.tsv`、`.delim`、`.log`檔 - `readxl`:匯入`.xlsx`、`.xls`檔 - `haven`:匯入`.dta`、`.sas`、`.spss`、`.xpt`檔 - `jsonlite`:匯入`.json`檔 - `rvest`:提供使用者進行爬蟲 ### 安裝`readr`套件與匯入資料 如果在安裝`tidyverse`後仍沒有辦法使用`readr`,則可以使用以下方式安裝並使用套件: ```r install.packages("readr") library(readr) ``` 在[資料視覺化:使用 ggplot2](https://hackmd.io/@yueswater/ggplot2)這篇文章中,我們使用的是`read.csv()`函式,這是`R`原本就有的。既然已經有了讀取`.csv`檔的函式,為何還要使用新的呢?以下我們就沿用該篇文章中提到的`pizza.csv`進行舉例。首先,`read_csv()`與`read.csv()`使用方式相同,接下來我們就來看為何我們要使用新的函式。我們藉由`system.time()`這個函式計算系統的運行速度: ```r system.time(pizza_base <- read.csv("https://chris.userweb.mwn.de/book/pizza_delivery.csv")) ## user system elapsed ## 0.063 0.038 2.732 system.time(pizza_readr <- read_csv("https://chris.userweb.mwn.de/book/pizza_delivery.csv")) ## user system elapsed ## 0.144 0.026 2.599 ``` 可看到新函式的系統運算速度較原本的快,因此以後多多使用`read_csv()`!此外,我們可以指定當讀取文件時出現未預期的值時,若想要給予其`NA`的編碼,則在`read_csv()`後加上`na = c()`,其中`c()`為要取代的值。 ### 安裝`readxl`套件與匯入資料 同樣地,我們可以透過下面的方式安裝`readxl`套件。 ```r install.packages("readxl") library(readxl) ``` 如果我們想要讀取某個`.xlsx`檔,則使用下列方式: ```r dat_xlsx <- read_xlsx("xlsx_data.xlsx", sheet = "Sheet 1") ``` 可以看到我們利用`sheet = "Sheet 1"`指定應讀取哪些試算表。 <!-- parse_*()函數 --> ### 安裝`haven`套件與匯入資料 我們可以透過下面的方式安裝`haven`套件。 ```r install.packages("haven") library(haven) ``` 利用下面的方式讀取檔案: ```r library(haven) read_sas("SAS_data.sas7bdat") read_spss("SPSS_data.sav") read_stata("Stata_data.dta") ``` ### 使用`rvest`讀取網頁表格 我們可以透過下面的方式安裝`rvest`套件。 ```r install.packages("rvest") library(rvest) ``` 假設我們今天想要爬取[List of countries by GDP (nominal)](https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal))這個網站中的表格: ![](https://i.imgur.com/CleKYIV.png) 首先我們要知道,`rvest`這個套件之作用類似於爬蟲,因此我們如果想要爬取網頁的元素,就需要透過`html`程式碼或`xpath`、`css`selector 等方式獲取資料。以下我們使用`xpath` ```r gdp <- read_html("https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)") gdp_table <- gdp %>% html_node(xpath = '//*[@id="mw-content-text"]/div[1]/table[2]') %>% html_table() %>% as_tibble(.name_repair = "universal") ``` 而獲取`xpath`的方式參考如下:首先在網頁任意處點擊右鍵 ![](https://i.imgur.com/HA5hGQT.png) 點選檢查(或 inspect),接著就可以看到以下畫面 ![](https://i.imgur.com/JELqnpm.jpg) 接著使用網頁原始碼瀏覽器中的選擇器點選表格 ![](https://i.imgur.com/G2Scomf.jpg) ![](https://i.imgur.com/SNX9O5s.jpg) 接著在原始碼瀏覽器中表格的地方點擊右鍵,依序按下`Copy`、`Copy XPath`即可獲得`xpath`。 ![](https://i.imgur.com/vm7fR0g.jpg) 不過我們可以注意到,原始的表格是有部分欄位是合併的,因此跑出來的結果欄位名稱會有重複的情況,因而得到下面的報錯訊息: ```r Error: ! Column names `IMF[1]`, `World Bank[13]`, and `United Nations[14]` must not be duplicated. Use .name_repair to specify repair. Caused by error in `repaired_names()`: ! Names must be unique. ✖ These names are duplicated: * "IMF[1]" at locations 3 and 4. * "World Bank[13]" at locations 5 and 6. * "United Nations[14]" at locations 7 and 8. ``` 因此我們需要在`as_tibble()`中加上`.name_repair = "universal"`,讓系統自動幫我們設定新的欄位名稱。 <div class="likecoin-embed likecoin-button"> <div></div> <iframe scrolling="no" frameborder="0" src="https://button.like.co/in/embed/xiaolong70701/button?referrer=hackmd.io"></iframe> </div>