基礎R語言教學

前言

  • 本講義為本人曾在國立中山大學財務管理系開設 3 小時之程式語言課程,若有錯誤請不吝嗇予以指正!
  • 本講義可免費使用,若要使用於其他公開用途,請寄信告知,感謝!
  • 教材下載:https://goo.gl/atztW1

基礎操作

Assignment

  1. <- (快捷鍵:Alt + -)(Alt + 注音符號ㄦ
  2. =
1
2
3
x <- 1
y <- 2
y = 9

註解

  • 加上#字號,輔助說明程式碼,在程式執行過程中不會被執行

基礎運算

  • +-*/
  • 整除%/%,餘數計算%%
  • 平方**``^,平方根sqrt(x)
  • 指數exp(x),對數log(x)
  • NA : 缺失值
  • NaN : Not a Number(無意義的數)
  • Inf: 正無窮大
1
2
3
4
5
6
(100+200)/(10+5)
(21-8)*(7-3)
10^4;10**4
sqrt(100);100^0.5
exp(2)
log(10)

邏輯運算

  • &&& (AND)
  • ||| (OR)
  • ! (NOT)
  • == (等於)
  • != (不等於)
  • 大於(>),小於(<)
  • 大於等於(>=),小於等於(<=)
  • %in% (包含於)

文字字串

  • 字串可由單引號('')或雙引號("")構成
  • paste():將字串與數字做黏合,字與字之間有間隔
  • paste0():將字串與數字做黏合,字與字之間沒有間隔
  • print():顯示變數結果
  • cat():將字串與數字做黏合,並且顯示出來,可作為進度條使用
  • 更多內容請詳閱:https://www.ptt.cc/bbs/Statistics/M.1277714037.A.2CC.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
paste('Allen', "Mark", "Peggy")  # with blanks
> "Allen Mark Peggy"
paste0("Allen", "Mark", "Peggy") # without blanks
> "AllenMarkPeggy"

paste0("MA_", 5)
> "MA_5"

# 可利用for迴圈與paste0()進行欄位命名
for(i in c(5, 10, 20, 60)){
cat("目前進行到:", i, "\t")
name <- paste0("MA_", i)
print(name)
}
> 目前進行到: 5 [1] "MA_5"
目前進行到: 10 [1] "MA_10"
目前進行到: 20 [1] "MA_20"
目前進行到: 60 [1] "MA_60"

資料類型

資料類型 辨別函數 轉換函數
character is.character() as.character()
complex is.complex() as.complex()
double is.double() as.double()
integer is.integer() as.integer()
logical is.logical() as.logical()
NA is.na() as.na()
numeric is.numeric() as.numeric()

資料結構

變數種類 說明 使用頻率
vector 儲存單一變數的觀察值 經常使用
matrix 用於矩陣運算,矩陣內僅能放入數值 經常使用
data-frame 儲存整個資料檔,內容可包含數值與字串等,像 Excel 那樣的表格 經常使用
list 可儲存多種物件(objects),向量、矩陣、data-frame、function 等等 偶爾
factor 儲存分類變數(性別、等第…) 偶爾
array 多維矩陣 很少
ts 儲存時間序列資料,通常會使用其他更好的套件 很少

向量與向量運算

  • 經常使用 c( )結合各種小元素,形成一個較大的物件
  • seq:seq(起始值, 結束值, by = 遞增值)
  • rep: rep(x, times = 重複次數, each = x 內的元素重複幾次)
  • length:計算向量中的元素個數
  • sum:將向量中的所有元素加總
  • prod:將向量中的所有元素相乘
  • cumsum:累積相加
  • cumprod:累積相乘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
aa=c(1,2,3,4,5);aa=c(1:5);aa=seq(from = 1, to = 5, by = 1)

bb=c(6:10)

name=c("Amy","Betty","Cindy","Dora","Emily","Frank","Grace","Hank","Ivy","John")

# What's the difference?
"name"
name

rep(bb, times = 2)
rep(bb, each = 2)
rep(bb, times = 2, each = 3)
length(aa)
sum(aa)
prod(bb)
cumsum(aa)
cumprod(bb)

# 抽樣
sample(name, size = 3, replace = F, prob = rep(0.1, 10))
sample(name, size = 3, replace = T, prob = c(0.2, 0.05, 0.05, 0.05, 0.05, rep(0.6/5, 5)))

排序函數

  • sort:數字由小到大排序(也可以由大到小排序)
  • rank:顯示每個元素在排序之後的「排序順位」
  • order:先將向量的元素由小到大排序,再將排好之後的元素在原來向量的數字指標回傳
1
2
3
4
5
6
7
c=c(1,10,5,22,6,19,20)
sort(c)
sort(c, decreasing = T)
rank(c)
order(c)
c[order(c)]
c[order(c, decreasing=T)]

向量指標用法 & which 篩選條件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x <- c(11, 12, 13)

x[2]
x[4]
x[c(1, 3)]
x[c(3)];x[3]
x[c(1,2,3)];x[1:3]

which(x > 11) # 回傳元素在第幾個位置
x[which(x > 11)] # 取出符合條件的元素

x <- c(11, 12, 13, NA)
# 取出非NA值
x[which(!(is.na(x)))]; x[which(is.na(x)==F)]

統計運算

1
2
3
4
5
6
7
8
y <- c(1, 12, 100)

mean(y)
var(y)
sd(y)
max(y)
min(y)
median(y)

客製化函式

  • 以標準化為例
1
2
3
4
5
6
standard <- function(x){
z <- (x-mean(x))/sd(x)
return(z)
}

stdd <- standard(aa)

矩陣

  • matrix(data = NA, nrow = 列數, ncol = 欄數, dimnames = 給定列和欄名稱, byrow = 排列元素是否按列排序,預設為FALSE)
  • t(A):轉置矩陣
  • solve(A):反矩陣
  • %*%:矩陣相乘
  • diag(A):回傳矩陣 A 的對角元素
  • diag(diag(A)):生成僅有對角元素的對角矩陣
  • diag(3):生成單位矩陣
1
2
3
4
5
6
7
8
9
10
11
12
A=matrix(1:20,nrow=5,ncol=4)
B=matrix(21:40,nrow=5,byrow=TRUE)
nrow(A)
ncol(B)
A*2
A-B
A*B #單純相乘,矩陣相乘是要用%*%
A %*% B #行列不符,無法相乘
t(A)
t(A) %*% B
C=matrix(rnorm(25), nrow=5,ncol=5) #rnorm是從一個平均數為0,標準差為1的常態分配中隨機選出25個數字
solve(C) #逆矩陣/反矩陣

rbind.cbind & 矩陣排序

  • matrix 與 data.frame 同樣適用
  • rbind
  • cbind

重要:合併時請注意資料長度是否相同

矩陣排序

1
2
3
4
5
6
xx<-c(1, 1, 3:1, 1:4, 3)
yy<-c(9, 9:1)
zz<-c(2, 1:9)
xyz<-rbind(xx,yy,zz)
xyz[, order(xyz[1, ])] #根據第一列去排序,下面的也會跟著排
xyz[order(xyz[ ,1]), ] #根據第一欄去排序,後面的也會跟著排

Data.Frame

基本應用

1
2
3
4
5
6
7
8
d=c("Amy","Betty","Cindy","Dora","Emily","Frank","Grace","Hank","Ivy","John")      #文字要加引號
e=c(1:10)

sheet <- data.frame(d,e)
colnames(sheet) <- c("name","number")
sheet1 <- data.frame(name = d, number = e)
str(sheet) #查詢變數種類
sheet$name <- as.character(sheet$name) #轉換變數種類

指標用法 & which 篩選資料

  • 以鳶尾花資料集(iris dataset)為例
    _ Sepal.length(花萼長度)
    _ Sepal.width(花萼寬度)
    _ Petal.length(花瓣長度)
    _ Petal.width(花瓣寬度) * Species(物種):山鳶尾(setosa)、變色鳶尾(versicolor)、維吉尼亞鳶尾(virginica)、
1
2
3
4
5
6
7
8
9
10
data("iris")

iris[60, ]
iris[, 3]
iris[60, 3]
iris[, "Species"];iris$Species

# 取出山鳶尾的資料
which(iris$Species == "setosa")
iris[which(iris$Species == "setosa"),]

List

1
2
3
rec <- list(name="Mark", age=28, scores=c(81, 79, 96))

rec$name;rec[[1]]

分配抽樣

Distribution

  • d:機率密度函數
  • p:累積機率密度函數
  • q:分位數
  • r:隨機抽樣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#從標準常態分配中隨機抽出25個數字
rnorm(25);rnorm(25, mean = 0, sd = 1);rnorm(25, 0, 1)

runif(25, min = 0, max = 1) # 均勻分配
rpois(25, 2) # poisson分配
rhyper(25, 2, 3, 10) # 超幾何分配
rexp(25, rate = 10) # exponential 分配
rgamma(25, shape = 2, rate = 10) # gamma分配
rbinom(25, size = 10, prob = 0.5) # 二項分配
rcauchy(25) # 柯西分配
rnbinom(25, 50, 0.2) # 負二項分配

x <- seq(-4, 4, 0.1)
dnorm(x) # pdf
pnorm(x) # cdf
qnorm(0.05);qnorm(0.95)

plot(x, dnorm(x), type="h", main="N(0,1)") # pdf, type="h"(histogram)
plot(x, pnorm(x), type="l", main="N(0,1)") # cdf, type="l"(line)

if else 條件判斷式

  • elseelse if可視為一種可拆式配件,有需要再用即可
  • else if的寫法必須在 else 之前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
A=-4

if(A>0){
B=1
}else if(A==0){
B=0
}else{
B=-1
}

# 寫法1
if(A>0){
B=1
}

# 寫法2
if(A>0){
B=1
}else{
B=-1
}

# 寫法3
if(A>0){
B=1
}else if(A==0){
B=0
}else if(...){
B=-1
}else if(...){
...
}

# 寫法4
iris$Species <- ifelse(iris$Species=="setosa", 1, 0)

迴圈

for-loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 計算 1+2+3+4...+100 的值是多少?
j <- 0

for(i in 1:100){
j <- j + i
print(j)
}

# 99乘法表
table <- matrix(NA, nrow=9, ncol=9)

# 巢狀迴圈
for(i in 1:9){
for(j in 1:9){
table[i, j] <- i * j
}
}

while-loop

1
2
3
4
5
6
7
8
9
10
11
12
# 計算 1+2+3+4...+100 的值是多少?
i <- 1
ww <- 0

while(i < 101){ # 當符合裡面的條件時,就會一直重複括號內的程式碼,直到不符合為止

# 迴圈內重複進行的動作
ww <- ww + i
i <- i + 1
}

ww

repeat-loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 計算 1+2+3+4...+100 的值是多少?
i <- 1
rr <- 0

repeat{ # repeat和while很像,差別在於條件可以寫在任何地方,並且使用break跳出迴圈

if(i > 100) break # 當i比100大時,用break跳出迴圈

# 迴圈內重複進行的動作
rr <- rr + i
i <- i + 1
}

rr

常見操作

套件安裝&讀取

  • install.packages:安裝套件
  • library:讀取套件
  • require:安裝+讀取套件
1
2
3
install.packages("openxlsx")
library(openxlsx)
require(openxlsx)

讀取資料

csv 檔

1
data <- read.csv("E:/R程式教學/10檔股票日頻報酬率.csv")

Excel 檔

1
close1 <- read.xlsx("E:\\R程式教學\\10檔股票日頻收盤價.xlsx",sheet=1)

txt 文字檔

1
close2 <- read.table(file = "10檔股票日頻收盤價.txt", sep = "\t", head = T, stringsAsFactor = F)

迴歸

  • lm:lm(formula = y~x, data=資料集)
1
2
3
4
5
6
7
#簡單迴歸
reg <- lm(data[,ncol(data)]~data[,2])
summary(reg)

#多元迴歸
reg2 <- lm(data[,ncol(data)]~data[,2]+data[,3]+data[,4])
summary(reg2)

綜合練習

  • 對大盤指數報酬率與每一檔股票做迴歸分析,並將迴歸係數儲存成一張表格
  • 提示:for-loop、if else、lm、cbind 或 rbind

$$
Ret_m=a_i+b_{i,m}Ret_i \ , \ i=1,2, …, 10
$$

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
for(i in 1:10){
reg <- lm(data[, ncol(data)]~data[,i+1])
coef <- reg$coefficient #迴歸的係數

if(i==1){
coef_table <- data.frame(coef)
}else{
coef_table <- cbind(coef_table,coef)
}
}

colnames(coef_table)=colnames(data)[c(-1, -ncol(data))]
rownames(coef_table)=c("intercept","slope")

補充

共變異數 covariance

1
cov.data <- cov(data[, 2:12])

相關係數 correlation

1
2
3
4
5
6
corr.data <- cor(data[, 2:12])

# 視覺化(correlation heatmap)
library(corrplot)
corrplot.mixed(corr.data, tl.col="black", tl.pos = "lt", tl.cex = par("cex"),
number.cex = 1)