外界在提到 R 軟體時,在褒獎之餘,總是人云亦云地會順便提到「R 軟體的學習曲線頗陡峭」。我思考了幾個可能原因,想到以前我在學 Perl 程式語言的經驗。當時我買了好幾本 Perl 的書,但後來放棄的原因,是我看到網路上有經驗的人寫的 Perl 程式時,經常會在書上找不到他們用的特殊奇怪語法,這讓我非常氣餒。
關於「R 很難學」的迷思,可能的原因之一,或許就是這種「初學者看不懂程式」的挫折使然。所以這裡我列出一些 R 軟體有別於其他程式語言的常見特殊寫法,或許能幫忙一些初學者度過第一關。
R 軟體有別於其他程式語言的特殊語法:
1. 「=」, 「<-」, 與「<<-」三個運算符號
(1) 「=」跟「<-」是一樣的。R 語言是源自於 AT&T 的 S 語言。在 S 語言中,「<-」的意義就是「=」。從 R-1.4.0 版之後,R 軟體開始導入「=」號,目前兩者皆可使用。
(2) 「<<-」只在 funciton 中使用,可以從 function 內部改變 function 外面的全域變數(Global Variable) 的值。若在函數內只有使用「=」或「<-」,則函數之外的全域變數值不會被改變。例如:
x1 = 100 ; x2 = 100
f2 = function(y)
{
x1 <<- y + 10
x2 <- y + 10
w = y + 20
return(w)
}
f2(6)
[1] 26 # w = 6 + 20 = 26
x1
[1] 16 # x1 <<- 6 + 10
x2
[1] 100 # x2 未被改變
2. 使用指標時,到底要不要加 c( …. ) ?
原則:只要用到 2 個或 2 個以上指標時,都必須用 c(….) 把這些指標包起來,唯一的例外是 「:」,例如 1:3 外面就不用加 c(….),但加了也不會出錯, 如 c(1:3)
x = 11:20
names(x) = paste0("k",11:20) # 為每個元素加上名稱
x
k11 k12 k13 k14 k15 k16 k17 k18 k19 k20
11 12 13 14 15 16 17 18 19 20
x[3]
k13
13
x[1:3]
k11 k12 k13
11 12 13
x[c(2,4,9)]
k12 k14 k19
12 14 19
x["k13"]
k13
13
x[c("k12","k14","k19")]
k12 k14 k19
12 14 19
3. 指標外面該用 [ … ] 還是 [[ … ]] ?
[ … ] 傳回的資訊多,[[ … ]] 傳回的資訊少
[[ … ]] 雙重方刮號有 2 個原則:
(1) 傳回比較精簡濃縮的資訊
(2) 只能放一個數字指標或名稱指標,不能放兩個以上
some.dataFrame[3] # 傳回第 3 個變數,但被包在新的 data-frame 中
some.dataFrame[[3]] # 傳回第 3 個變數 (vector 或 factor)
some.List[3] # 傳回第 3 個元素,但被包在一個新的 list 變數裡面
some.List[[3]] # 傳回第 3 個元素,沒有被 list 結構包起來
x = 1:10
x[1]
[1] 1
x[[1]] # 與 x[1] 相同
[1] 1
names(x) = letters[1:10] # 幫 x 的元素加上名稱
x
a b c d e f g h i j
1 2 3 4 5 6 7 8 9 10
x[1] # 多出了元素名稱 "a"
a
1
x[[1]]
[1] 1
4. 向量/矩陣之間的向量化(Vetorized)加減乘除運算
x = c(1,2,3,4,5)
y = c(10,20,30,40,50)
x + y
[1] 11 22 33 44 55
x - y
[1] -9 -18 -27 -36 -45
x * y
[1] 10 40 90 160 250
y ^ x
[1] 10 400 27000 2560000 312500000
x + 100
[1] 101 102 103 104 105
5. 在指標區域用邏輯條件做快速的資料(元素/橫列(rows))篩選
score = c(43,56,74,61,61,55)
sex = c("男","男","女","女","女","男")
blood = c("A","O","A","O","O","A")
score[score <= 60]
[1] 43 56 55
score[sex == "女"]
[1] 74 61 61
mean(score[sex == "女"])
[1] 65.33333
mean(score[sex == "男"])
[1] 51.33333
# 所有 A 型男性的平均成績
mean(score[sex == "男" & blood == "A"])
[1] 49
# 找出所有 Sepal.Length > 4.0 的橫列(rows), 並儲存在 iris2
iris2 = iris[iris$Sepal.Length > 4.0, ]
6. 矩陣/資料框架行列指標的省略
M = matrix(c(1,2,3,4,5,6),nrow=2,ncol=3,byrow=TRUE)
M
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
M[1,2] # 取出單一元素值
[1] 2
M[1,] # 取出第 1 列(row)
[1] 1 2 3
M[2,] # 取出第 2 列(row)
[1] 4 5 6
M[,1] # 取出第 1 行(column)
[1] 1 4
M[,3] # 取出第 3 行(column)
[1] 3 6
7.「$」符號是什麼東東?
「$」是 R 軟體中的 List (串列) 變數跟 Data Frame (資料框架) 變數在抓取個別內部元素或變數時所用的運算元。例如:
friend = list(fname="林大旺",age=25,child=c("林小華","林小珍"))
names(friend)
[1] "
fname" "age" "child"
friend$fname
[1] "林大旺"
friend$age
[1] 25
friend$child
[1] "林小華" "林小珍"
friend$child[2]
[1] "林小珍"
# 或
childs = friend$child
childs[2]
[1] "林小珍"
List 變數是很多 R 的大型計算函數傳回的慣用變數型態,因為 List 變數內可以包山包海,什麼資料都可以放進去。例如
result = lm(Sepal.Length ~ Petal.Length,data=iris)
names(result)
[1] "coefficients" "residuals" "effects" "rank"
[5] .........
result$coefficients
(Intercept) Petal.Length
4.3066034 0.4089223
SL = iris$Sepal.Length # 取出 iris 資料框架內的 Sepal.Length 變數
8. 那些奇怪的「%>%」符號是什麼東東?
「%>%」是 dplyr 套件常用的「向前(其實是向右)管道」(forward pipe) 運算子,可以把原本分作好幾行的運算結合在一起。例如
iris %>% subset(select=Sepal.Length) %>% summary
Sepal.Length
Min. :4.300
1st Qu.:5.100
Median :5.800
Mean :5.843
3rd Qu.:6.400
Max. :7.900
上面的程式相當於以下這一行程式「由內而外」的運算順序改成「由左而右」:
summary(subset(iris, select=Sepal.Length))
其實原本分開寫成兩行運算,需要佔用記憶體多用一個臨時變數 iris2:
iris2 = subset(iris, select=Sepal.Length)
summary(iris2)
dplyr 套件這個符號源自於 magrittr 套件,除了「%>%」符號外,還有「%<>%」、「%$%」、「%T>%」三種運算子可用。但是,這類屬於某特定套件的運算符號,目前尚未被納入 R 軟體核心,因此國外也有些人認為,在寫 R 的套件時,不適合使用這類運算符號,以免造成新套件對其他套件的過度依賴。