這份檔案主要教學基礎的R程式碼,郭兆翊助教會教學igraph package的實際應用。
另外,請先執行以下程式碼:
system.file(package='rmarkdown')
system.file(package='knitr')
# 如果你在執行上面兩行沒有顯示像這份檔案一樣的路徑,請接著執行下面的程式碼
install.packages('rmarkdown')
install.packages("knitr")
注意,以上程式碼執行完一次後就不用在執行。
R 語言大多被用於統計分析、數值模擬,也是在計量經濟學界中最常被使用的統計程式語言之一。本此課程中會教大家最基本的程式觀念。
另外,除了於統計分析、數值模擬外,作為一個程式語言,他也有架設網頁、建立資料庫或科學運算的功能。由於 R 是開源、免費的特性,使得他有廣大的使用社群、豐富的套件等等,不過也有些缺點是套件可能缺乏維護因此無法使用,同學後續在使用 R 的時候可以去看一下每個套件的原始碼或是 Github 上的程式碼,這邊提供一個R的詳細教學
上週我們有請同學先下載R,還沒下載的同學可以點此下載,另外也需要安裝R的IDE, Rstudio,可以點此下載。
可能有許多同學對寫程式會有「感覺很難的」、「不容易達成」的印象因而卻步。不過事實上,R 語言作為一個高階程式語言,其實程式碼相對簡單、易讀的,不會像 C 或 C++ 等低階語言不容易上手。因此,當你遇到不會的地方時,大膽 google 就是了,此外,也可以多對 ChatGPT 下 prompt 來快速完成程式碼。
?install.packages() # 查詢函式的參數、用途等
sessionInfo() # 可用來查看你的R版本
## R version 4.2.2 (2022-10-31)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur ... 10.16
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## loaded via a namespace (and not attached):
## [1] digest_0.6.31 R6_2.5.1 lifecycle_1.0.3 jsonlite_1.8.4
## [5] magrittr_2.0.3 evaluate_0.20 stringi_1.7.12 rlang_1.1.0
## [9] cli_3.6.0 rstudioapi_0.13 jquerylib_0.1.4 bslib_0.3.1
## [13] vctrs_0.5.1 rmarkdown_2.14 tools_4.2.2 stringr_1.5.0
## [17] glue_1.6.2 xfun_0.36 yaml_2.3.6 fastmap_1.1.0
## [21] compiler_4.2.2 htmltools_0.5.2 knitr_1.41 sass_0.4.1
R在運作時預設一個臨時的工作目錄(你可以想像成工作的地方)。因此,我們可以先利用getwd()來顯示目前的工作目錄:
getwd() # 查詢工作路徑
## [1] "/Users/deankuo/Desktop/R"
接下來,當我們要設定新的工作目錄時,則可以用setwd()的指令進行更改。注意到路徑的名稱要利用"或'包起來。
setwd("/Users/deankuo/Desktop/R") #設定工作目錄
# 如要執行,請自行更改工作目錄
R 與 Python 等高階程式語言都是以物件導向為主的程式語言(Object-Oriented Programming Language),儲存的資料或是函式(function)都被稱為物件。特別需要注意的是,物件名稱起始位置必須要是英文字母,也不能以保留字作為物件名稱。
# TRUE <- 3 使用保留字作為物件名稱
true <- 3
假設我們的環境裡面有多個變數。如果此時想要刪除環境所有變數(或物件),則可以用rm(list = ls())的指令。若只要刪除特定變數,則使用rm()即可。以下舉兩個例子,
a <- 1 # 創造一個變數 a = 1
b <- 2 # 創造一個變數 b = 2
rm(list = ls()) # 刪除環境所有變數
a <- 1 # 創造一個變數 a = 1
b <- 2 # 創造一個變數 b = 2
rm(b) # 刪除 b
R有以下的資料屬性:
TRUE與FALSE。亦可寫成T與F最後,我們可以使用mode()來看特定資料的屬性為何。
b <- "bravo"
c <- T
mode(a)
## [1] "numeric"
class(b)
## [1] "character"
is.logical(c)
## [1] TRUE
在R中,我們的資料可以被儲存成以下四種格式
| 維度/儲存型態 | 只能存1種屬性資料 | 能存多種屬性資料 |
|---|---|---|
| 1 dimension | Vector(向量) | List |
| 2 dimension | Matrix(矩陣) | Dataframe |
就向量而言,我們會用c()這個指令來建立一個向量。
x <- c(1, 2, 3)
x
## [1] 1 2 3
x <- c(1:5)
x
## [1] 1 2 3 4 5
矩陣的部分可能比較複雜。我們會先寫一個向量,然後在用matrix()來令其為矩陣。
X <- matrix(c(1, 2, 3, 4), nrow = 2, ncol = 2) # nrow, ncol分別代表這個向量有幾個row跟column
X
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
><==!>=<=!=|&7 > 4
## [1] TRUE
x < 2
## [1] TRUE FALSE FALSE FALSE FALSE
x == 2
## [1] FALSE TRUE FALSE FALSE FALSE
z <- (x > 2)
z
## [1] FALSE FALSE TRUE TRUE TRUE
+、-、*、/%/%^或**mean()sqrt()abs()d <- 48
e <- -9
d / e # 除法
## [1] -5.333333
d %/% e # 整除
## [1] -6
e ^ 2 # e的平方
## [1] 81
x
## [1] 1 2 3 4 5
mean(x) # 向量x的平均數
## [1] 3
sqrt(d) # d的開根號
## [1] 6.928203
abs(e) # e的絕對值
## [1] 9
請創造一個向量,裡面包含有\(4, 5, 6, 7\)三個元素。再請計算該向量元素的平均數
# 練習 6.1.a:
+、-%*%Y <- matrix(c(5, 6, 7, 8), nrow = 2, ncol = 2)
v <- c(1, 2)
X
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
Y
## [,1] [,2]
## [1,] 5 7
## [2,] 6 8
v
## [1] 1 2
X + Y # 矩陣加法
## [,1] [,2]
## [1,] 6 10
## [2,] 8 12
X - Y # 矩陣減法
## [,1] [,2]
## [1,] -4 -4
## [2,] -4 -4
X %*% Y # 矩陣乘法
## [,1] [,2]
## [1,] 23 31
## [2,] 34 46
dimnames()分別給矩陣命名rownames() 與
colnames()dim()X.mat <- matrix((1:6), nrow = 2, ncol = 3, byrow = T, dimnames = NULL) # 設置一個名為X.mat的矩陣
dimnames(X.mat) <- list(c("A1", "A2"), # 替X.mat的列資料和行資料命名
c("B1", "B2", "B3"))
X.mat
## B1 B2 B3
## A1 1 2 3
## A2 4 5 6
dimnames(X.mat) # 顯示矩陣的每個欄位名稱
## [[1]]
## [1] "A1" "A2"
##
## [[2]]
## [1] "B1" "B2" "B3"
rownames(X.mat) # 顯示列名稱
## [1] "A1" "A2"
colnames(X.mat) # 顯示行名稱
## [1] "B1" "B2" "B3"
dim(X.mat) # 顯示矩陣維度
## [1] 2 3
向量和矩陣的合併,使用rbind(),
cbind()。在R中向量可以視為 \(1 ×
k\) 的向量/矩陣,因此可進行合併,不過需要注意維度是否正確。
v1 <- c(1:3)
v2 <- c(2:4)
rbind(v1, v2) # 從row方向合併
## [,1] [,2] [,3]
## v1 1 2 3
## v2 2 3 4
cbind(v1, v2) # 從column方向合併
## v1 v2
## [1,] 1 2
## [2,] 2 3
## [3,] 3 4
請創造矩陣 M 與向量 u。且 M 與 u 等於以下:
\[ M = \begin{bmatrix} 5 & 3 & 4\\ 2 & 1 & 7 \end{bmatrix} \]
\[ u = \begin{bmatrix} 4 \\ 1 \end{bmatrix} \]
然後將兩者合併,並替這個新的矩陣命名,欄名稱為A1, A2, A3, A4,列名稱為B1, B2。
# 練習 6.2.a:
Array 是一種多維數組,可以包含多個維度的數據。Array 和 Matrix 很像,但是可以包含多個維度。例如,可以使用 Array 存儲多個距離矩陣,其中每個矩陣代表不同的時間段或不同的參數設置。
A <- array(1, dim = c(2, 2, 2)) # 創建一個 2x2x2 的 Array,元素都是 1
A[1, 2, 1] <- 2 # 設置第一個平面第一行第二列的元素為 2
A
## , , 1
##
## [,1] [,2]
## [1,] 1 2
## [2,] 1 1
##
## , , 2
##
## [,1] [,2]
## [1,] 1 1
## [2,] 1 1
mode(A)
## [1] "numeric"
dim(A)
## [1] 2 2 2
List 是一種可以包含不同類型元素的數據結構,例如數字、字串、向量、矩陣、函數等等。List 常用於存儲和處理各種不同類型的數據。
# 創建一個 List,包含一個向量和一個矩陣
L <- list(
a = c(1, 2, 3),
b = matrix(1:4, nrow = 2))
# 在 R 語言中,"$" 符號用於訪問 R 對象中的特定元素,通常用於訪問一個 Dataframe 中的某個欄位。"$" 符號的左側是一個 R對象,通常是一個 Dataframe,右側是要訪問的欄位名稱,以字符形式給出
L$a[2] <- 4 # 設置第一個元素的第二個值為 4
L
## $a
## [1] 1 4 3
##
## $b
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
Dataframe 是一種類似於表格的數據結構,可以存儲多種類型的數據。Dataframe 中的每列可以是不同類型的數據,例如數字、字串、日期等等。Dataframe 是 R 語言中最常用的數據結構之一,可以方便地對數據進行選擇、過濾、排序、合併等操作。
# 創建一個 Dataframe,包含三列數字和一列字符
df <- data.frame(
x = c(1, 2, 3),
y = c(4, 5, 6),
z = c(7, 8, 9),
name = c("Alice", "Bob", "Charlie")
)
df
## x y z name
## 1 1 4 7 Alice
## 2 2 5 8 Bob
## 3 3 6 9 Charlie
請創建一個 dataframe,當中存取個人的名字、年紀以及出生地,隨機創建六筆資料(這應該是一個 \(3 × 6\) 的 dataframe),並依序將欄位名稱儲存為:name, age, birth
# 練習 6.2.a:
資料框架的下標或 引 (index) 操作, 如同矩陣的下標與索引操作, 可以輸入正整數, 負數, 整數向量, 欄位名等等. 矩陣具有 2-維度下標向量, 例如, 可以使用中括號 dataframe.name[i, j] 可存取資料框中的第 [i,j] 元素; dataframe.name[i, ]可存取資料框中的第i列 (\(i\) th row), dataframe.name[ , j] 可存取資料框中的第j欄 (\(j\) th column).
請呈現第三個人的個人資料。
# 練習6.5.b
本堂課只針對igraph這個套件進行解說,因此我們不另外講解其他的套件功能,只簡單提供另外一個R常見且強大的套件,tidyverse,其餘的套件有興趣的同學可以自行上網搜尋。
首先,我們必須先安裝幾個套件。
install.packages("igraph")
install.packages("tidyverse") # 功能強大的套件集合,包含ggplot2, dplyr, tidyr等套件
# install.packages(c("igraph", "tidyvserse")) # 不同寫法
另外,如果以安裝過套件則不需再執行以上程式碼。
如果要載入特定的套件到現在運行的程式檔案中,我們會使用library()這個函數
library(igraph)
##
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.3.6 ✔ purrr 1.0.1
## ✔ tibble 3.1.8 ✔ dplyr 1.0.10
## ✔ tidyr 1.2.1 ✔ stringr 1.5.0
## ✔ readr 2.1.2 ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::as_data_frame() masks tibble::as_data_frame(), igraph::as_data_frame()
## ✖ purrr::compose() masks igraph::compose()
## ✖ tidyr::crossing() masks igraph::crossing()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ purrr::simplify() masks igraph::simplify()
首先我們必須匯入檔案,注意到的是匯入檔案的函式會依照資料格式而有所變動,以下舉一個匯入csv檔的例子。
注意到我現在的工作目錄內已經有資料檔了。
incursion_df <- read.csv("/Users/deankuo/Desktop/R/incursion_dataset.csv") # 匯入檔案
data("mtcars")
mtcars <- mtcars
colnames(mtcars) # 列出所有變數名稱
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
head(mtcars, 5) # 列出前5個觀察值
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
summary(mtcars)
## mpg cyl disp hp
## Min. :10.40 Min. :4.000 Min. : 71.1 Min. : 52.0
## 1st Qu.:15.43 1st Qu.:4.000 1st Qu.:120.8 1st Qu.: 96.5
## Median :19.20 Median :6.000 Median :196.3 Median :123.0
## Mean :20.09 Mean :6.188 Mean :230.7 Mean :146.7
## 3rd Qu.:22.80 3rd Qu.:8.000 3rd Qu.:326.0 3rd Qu.:180.0
## Max. :33.90 Max. :8.000 Max. :472.0 Max. :335.0
## drat wt qsec vs
## Min. :2.760 Min. :1.513 Min. :14.50 Min. :0.0000
## 1st Qu.:3.080 1st Qu.:2.581 1st Qu.:16.89 1st Qu.:0.0000
## Median :3.695 Median :3.325 Median :17.71 Median :0.0000
## Mean :3.597 Mean :3.217 Mean :17.85 Mean :0.4375
## 3rd Qu.:3.920 3rd Qu.:3.610 3rd Qu.:18.90 3rd Qu.:1.0000
## Max. :4.930 Max. :5.424 Max. :22.90 Max. :1.0000
## am gear carb
## Min. :0.0000 Min. :3.000 Min. :1.000
## 1st Qu.:0.0000 1st Qu.:3.000 1st Qu.:2.000
## Median :0.0000 Median :4.000 Median :2.000
## Mean :0.4062 Mean :3.688 Mean :2.812
## 3rd Qu.:1.0000 3rd Qu.:4.000 3rd Qu.:4.000
## Max. :1.0000 Max. :5.000 Max. :8.000
如果想要選擇馬力大於120的汽車hp >= 120,則:
mtcars2 <- filter(mtcars, hp > 120) # 使用 filter 這個函式來取得符合條件的子集
mtcars2
## mpg cyl disp hp drat wt qsec vs am gear carb
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
mtcars2 <- filter(mtcars, hp > 120 & mpg < 18)
mtcars2
## mpg cyl disp hp drat wt qsec vs am gear carb
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
接下來,我們只想選擇「每加侖英里數」mpg、「汽缸數量」cyl
與「馬力」hp
mtcars2 <- select(mtcars2, mpg, cyl, hp)
mtcars2
## mpg cyl hp
## Duster 360 14.3 8 245
## Merc 280C 17.8 6 123
## Merc 450SE 16.4 8 180
## Merc 450SL 17.3 8 180
## Merc 450SLC 15.2 8 180
## Cadillac Fleetwood 10.4 8 205
## Lincoln Continental 10.4 8 215
## Chrysler Imperial 14.7 8 230
## Dodge Challenger 15.5 8 150
## AMC Javelin 15.2 8 150
## Camaro Z28 13.3 8 245
## Ford Pantera L 15.8 8 264
## Maserati Bora 15.0 8 335
利用這個機會,我們來介紹tidyverse最好用的技能:pipe
%>%。在上述的範例中,如果我有3個步驟,我就要執行3行。而pipe的功用其實就可以讓我們將許多步驟一次就做完,而且更容易閱讀。
為了方便示範,我們創建新的 Dataframe 叫 mtcars3。大家用這個來跟剛剛 mtcars2 的處理過程做比較。
mtcars3 <- mtcars %>%
filter(hp >= 120 & mpg < 18) %>%
select(mpg, cyl, hp)
head(mtcars3, 5)
## mpg cyl hp
## Duster 360 14.3 8 245
## Merc 280C 17.8 6 123
## Merc 450SE 16.4 8 180
## Merc 450SL 17.3 8 180
## Merc 450SLC 15.2 8 180
if-else 是一種控制結構,用於在條件成立或不成立時執行不同的操作。if-else 構造如下:
# if (condition) {
# condition 為 TRUE 時執行這裡的程式碼
# } else {
# condition 為 FALSE 時執行這裡的程式碼
# }
score <- 49
if (score >= 60) {
print("及格")
} else {
print("不及格")
}
## [1] "不及格"
if (score >= 60) {
print("及格")
} else if (score > 50 & score < 60) {
print("不及格")
} else {
print("非常不及格")
}
## [1] "非常不及格"
另一種非常相似的函式ifelse()結構如下:
# ifelse (test_expression, yes_expression, no_expression)
mtcars3 %>%
mutate(mpg_type = ifelse(mpg > 20, "high mpg", "low mpg")) %>%
select(mpg_type, mpg, cyl, hp)
## mpg_type mpg cyl hp
## Duster 360 low mpg 14.3 8 245
## Merc 280C low mpg 17.8 6 123
## Merc 450SE low mpg 16.4 8 180
## Merc 450SL low mpg 17.3 8 180
## Merc 450SLC low mpg 15.2 8 180
## Cadillac Fleetwood low mpg 10.4 8 205
## Lincoln Continental low mpg 10.4 8 215
## Chrysler Imperial low mpg 14.7 8 230
## Dodge Challenger low mpg 15.5 8 150
## AMC Javelin low mpg 15.2 8 150
## Camaro Z28 low mpg 13.3 8 245
## Ford Pantera L low mpg 15.8 8 264
## Maserati Bora low mpg 15.0 8 335
R 有許多函式(function),函式是一種物件,是指令的集合,執行特定功能或運算工作的指令,資料整理, 資料分析等,透過函式,擴展了 R 在程式語言的功能性與便利性。函式內通常需輸入引數 (argument)。
R 基本系統(base) 提供了一部分常用函式,而更多不同類型的函式,則由許多不同的學者貢獻到 R 系統中, 這些函數都是用 R 程式語言寫成的。例如統計常用函式 mean(), var(), sd(), log() 等。
一個函式內通常需輸入引數。引數可以是一個以上,有些引數一定要輸入,稱為必要引數 (required argument), 有些引數可以不用輸入,稱為自選引數 (optional argument),另外一種引數則為省略引數 (ellipsis argument) 這三種引可以同時存在一個函式內, 引數可以是數值, 文字, 資料框架或 R 的任何物件。
x.vec <- c(1:5)
x.vec
## [1] 1 2 3 4 5
M1 <- matrix(c(5, 3, 2, 1))
M2 <- matrix(c(5, 3, 2, 1), nrow = 2, ncol = 2, byrow = TRUE, dimnames = NULL)
M1
## [,1]
## [1,] 5
## [2,] 3
## [3,] 2
## [4,] 1
M2
## [,1] [,2]
## [1,] 5 3
## [2,] 2 1
請計算 mtcars 資料集中每個汽車的英里每加侖(mpg)轉換為公升每百公里(kpl),將轉換後的資料新增一個欄位到mtcars當中。 - 提示一:英里每加侖(mpg)轉換為公升每百公里(kpl)的公式是 \(kpl = 235.214 / mpg\) - 提示二:使用mutate()來新增欄位
# 練習 9.1.a