【回到首頁】


在R語言中只是第一步。若要熟練地處理/分析資料,必須要掌握另一個技巧:
套件(package)與函式(function)。

沒有寫過程式的人,可能對函式(function)不是那麼熟悉,但其實理解起來並不難。
還記得國中的數學課,有一個章節叫「代數與函數」嗎?
我們可能會根據某一道題目,建立一個f(x)=2x+3的式子對吧?這裡的f(x),就是「函式」(函數)。
函式之所以好用,就是因為裡面已經幫你制定好規則。
因此,即使把不同的情況(x=2, x=3)丟入,也會根據相同的規則(f(x)=2x+3),產出結果(f(x=2)=7, f(x=3)=9)。

由於R是一個Open Source的程式語言(簡單來說,全世界的人在R語言上進行開發,撰寫自己的函式),因此具有豐沛的函式集,也就是「套件」(package)。

以下將會介紹R裡面一些實用的函式,以及如何根據自己的需求,搜尋到對應的套件並安裝。


1. 函式(function)

‧summary()

如果還記得的話,其實在上一篇的文章中,已經介紹過許多函式(is.integer(), data frame(), c(), str()…)
其中,str()十分好用,尤其在了解一筆資料時或未知的變數時,能派上很大的用場。
除此之外,還有一個相當強大、具有類似功能的函式,叫做summary()
我們先拿R內建的鳶尾花資料(iris),比較看看str()summary()的功用吧:

str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
summary(iris)
##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 

你會發現,str()列出資料內每個欄位的狀態,
summary()則給出每個欄位的「最大值」、「最小值」、「平均值」、「中位數」「第一四分位數」…等等。
那麼,str()summary()的差別究竟在哪裡呢?
這裡要教一個實用的小技巧:當你不清楚「一個函式的用途」、「該如何使用」時,要從哪裡找到說明文件(Help)?
答案很簡單!請在console裡面,輸入?str?summary指令(如下圖):


你會發現,在右手邊的「Help」欄位,會出現說明文件,裡面包括「函式的套件」、「函式的用途」、「參數說明」、「使用上的教學示範」…
這個技巧,在日後會時常用到!
(重要觀念:當接觸一個新的函式時,第一步就是要去了解「它的用途」、以及「如何去使用」!)

(小練習)請試著在console裡,查詢summary()的說明文件

‧敘述統計函式

敘述統計是進行資料分析時,有效瀏覽(explore)、了解(recognize)資料狀態的步驟。
作為一個資料分析軟體,R裡面自然有許多可以協助我們進行敘述統計分析的函式:

  • mean():平均值
  • var():變異數
  • sd():標準差
  • median():中位數
  • max():最大值
  • min():最小值
  • sum():綜合相加
  • quantile():分位數
  • range():全距

對鳶尾花資料(iris)進行簡單的示範:

# 從iris的資料集中,取"Sepal.Length"(花萼長度)這個欄位的資料出來(利用神奇符號$)
iris$Sepal.Length  
##   [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4
##  [18] 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5
##  [35] 4.9 5.0 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0
##  [52] 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8
##  [69] 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4
##  [86] 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8
## [103] 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7
## [120] 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7
## [137] 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

發現到了嗎?從data frame裡面取出來的「某一欄」資料,就是一個陣列(vector)的形式。(代表每一筆觀測值的花萼長度)
現在,就把上面這些函式,應用到這個陣列資料上吧(雖然有點無聊XD):

mean(iris$Sepal.Length)     #「花萼長度」的平均值
var(iris$Sepal.Length)      #「花萼長度」的變異數
sd(iris$Sepal.Length)       #「花萼長度」的標準差
median(iris$Sepal.Length)   #「花萼長度」的中位數
max(iris$Sepal.Length)      #「花萼長度」中的最大值
min(iris$Sepal.Length)      #「花萼長度」中的最小值
sum(iris$Sepal.Length)      #「花萼長度」加總
range(iris$Sepal.Length)    #「花萼長度」最小值和最大值(全距)
## [1] 5.843333
## [1] 0.6856935
## [1] 0.8280661
## [1] 5.8
## [1] 7.9
## [1] 4.3
## [1] 876.5
## [1] 4.3 7.9

然而quantile()這個函式有點特殊:

quantile(iris$Sepal.Length, probs=0.25)  # 第一四分位數 
## 25% 
## 5.1
quantile(iris$Sepal.Length, probs=0.75)  # 第三四分位數 
## 75% 
## 6.4

注意到了嗎?在quantile()這個函式裡面,除了iris$Sepal.Length以外,後面加了一個逗號,並且多出probs的參數。
這代表什麼意思呢,當你對函式有所困惑時,就讓我們偷看一下說明文件吧!

明白了嗎?所以:
prob=0.25,代表「第一四分位數」;
prob=0.1,代表「在連續分布上,對應到機率0.1的那個點是多少」
以此類推…就是這麼簡單喔!
(話說回來,你能從說明文件中注意到,quantile()這個函式是屬於哪個套件嗎?(Ans:stats套件))


那如果資料裡面,有遺漏值的話呢?

a <- c(1, 2, 3, 5, 8, 13, 21, NA, 55)
sum(a)
## [1] NA

遇到資料有遺漏值的時候,函式往往會無法運作,最後結果如上面顯示是NA
但如果我們想要把「NA以外的值」加總起來,又該怎麼做?
其實挺容易的:

sum(a, na.rm=TRUE)
## [1] 108

注意到我們在sum()函式裡面,多加一個參數na.rm=TRUE
其中,na.rm意味著“remove NA”,表示若資料裡面有遺漏值NA,會把它忽略,對剩下的資料進行加總。

我們也可以查看sum()的說明文件,發現在函式裡面,果然有na.rm的參數可以設定(預設是FALSE):


‧其他實用函式

除了敘述統計的函式以外,R裡面還有一些好用的函式,常常會在處理資料時派上用場。
以下列出個人自認好用的函式,但這裡不會多加解釋。
若有困惑的話,先閱讀函式的說明文件,再加上自我練習,才能漸漸掌握每個函式的使用:

paste(), append()

# paste():拼貼字串(把 "Happy"" 和 "White Day"" 兩個字串拼貼起來,sep代表連結字串的符號)
paste("Happy", "White-Day", sep=" ") 

# append():把兩個vector串接起來 
b <- c(1,2,3)
c <- c(4,5,6)
append(b, c)
## [1] "Happy White-Day"
## [1] 1 2 3 4 5 6

rbind(), cbind()

a <- data.frame(x=c(1,2,3), y=c("Henry", "Lun", "Kevin"))
b <- data.frame(x=c(4,5,6), y=c("Helen", "Tommy", "Leon"))
rbind(a,b) # rbind():把兩個data frame,依據row串接起來
##   x     y
## 1 1 Henry
## 2 2   Lun
## 3 3 Kevin
## 4 4 Helen
## 5 5 Tommy
## 6 6  Leon
cbind(a,b) # cbind():把兩個data frame,依據column串接起來
##   x     y x     y
## 1 1 Henry 4 Helen
## 2 2   Lun 5 Tommy
## 3 3 Kevin 6  Leon

sample(), seq()

sample(x=1:100, size=10)  # 從1~100數字中,隨機挑10個數字,產生一個數列(vector)
seq(from=1, to=5, by=0.5) # 產生一個「從1開始,每次加0.5,直到5為止」的數列(vector)
##  [1] 52 71 75 26 86 79 12 97 69 46
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0

head(), tail()

head(iris, n=6)  # head(): 顯示data frame中的前6筆資料
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
tail(iris, n=6)  # tail(): 顯示data frame中的後6筆資料
##     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 145          6.7         3.3          5.7         2.5 virginica
## 146          6.7         3.0          5.2         2.3 virginica
## 147          6.3         2.5          5.0         1.9 virginica
## 148          6.5         3.0          5.2         2.0 virginica
## 149          6.2         3.4          5.4         2.3 virginica
## 150          5.9         3.0          5.1         1.8 virginica

order(), sort()

a <- sample(x=1:100, size=10) # 從1~100數字中,隨機挑10個數字,產生一個數列(vector)
a
##  [1] 20 63 52 80  2 64 81 87 90 86
# 用order(),把數列由大排到小;從小排到大,decreasing = FALSE
a[order(a, decreasing=TRUE)]   
##  [1] 90 87 86 81 80 64 63 52 20  2
# 和 a[order(a, decreasing=TRUE)] 一樣效果
sort(a, decreasing=TRUE)      
##  [1] 90 87 86 81 80 64 63 52 20  2

unique(), duplicated()

a <- c("A", "B", "C", "A", "A", "B")
unique(a)       # 萃取資料中unique的element
## [1] "A" "B" "C"
duplicated(a)            # 若後面有重複的資料,函式會回傳TRUE,而第一個資料會是FALSE
a[duplicated(a)==FALSE]  # 和 unique(a)一樣效果
## [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE
## [1] "A" "B" "C"

which()

# which():找出第幾個element是TRUE(在a裡面,第幾個element的值等於100)
a <- c(68,73,99,100,56,100,85,36)
which(a==100)
## [1] 4 6

除此之外,網路上有人詳列出各種好用的函式的一覽表,當作參考。


2. 套件(package)

基本上,每一個函式都有對應的套件(package)。
不過你可能會覺得奇怪,當我們在使用上面那些函式時,似乎沒怎麼琢磨在套件上?
那是因為,R已經將那些套件內建在裡面,因此我們可以直接呼叫(call)這些函式來使用。

現在問題來了,如果我們想使用那些「沒有內建在R裡面」的函式呢?
例如,我們想要使用一個強大的繪圖函式ggplot()

ggplot(data=CO2)
## Error in ggplot(data = CO2): 沒有這個函數 "ggplot"

結果R跟你說「沒有這個函數」,這代表ggplot()函式沒有內建在R裡面。
因此,你得另外(1)安裝對應的套件(package),並且(2)匯入到R裡面才可以!


(1)安裝套件

我們先求助google大神,看ggplot()對應到的套件是哪一個?
光看搜尋結果,就會發現對應的套件是ggplot2
不過我們還是點開這個有CRAN字樣的網站:CRAN(Comprehensive R Archive Network),是R的官方網站之一,裡面收錄了所有經過R官方核可後的函式、以及對應的說明文件,就像這樣:

因此,現在我們知道要使用ggplot()函式,需要先下載ggplot2套件。


既然知道套件名稱,那麼就要把套件下載下來。
下載R的套件有兩種方式:

[1] 用RStudio介面:
在RStudio上點開「Tools」->「Install Packages」 :

在中間填入想要安裝的套件名稱,點「Install」就大功告成!

[2] 用R的函式(指令):
直接在console裡面輸入函式install.packages("套件名稱")


(2)匯入到R

當出現這樣的畫面,就代表安裝完成,這代表你已經把R的套件下載到電腦裡面了!

接下來,要使用套件裡面的函式,要將套件匯入到R裡面才可以,
這時就要用到library()/require(),用來「匯入套件」的函式:

library(ggplot2) #匯入ggplot2套件到R裡面
ggplot(data=CO2) + geom_boxplot(data=CO2,aes(x=conc, y=uptake, colour=Plant))

如此一來,就可以順利使用ggplot()函式進行繪圖囉~
(P.S.關於ggplot繪圖的相關細節,會在之後的的筆記中提及,請不用擔心!)


總結

套件和函式是R很重要的功能,但我們不可能記住所有的套件和對應的函式。
因此,如何妥善運用google和說明文件,是在R的學習之路上很重要的一環!

接下來,會進入比較接近「程式設計」的主題:條件式(if-else, switch)、迴圈(for, while),與函式搭配的情形。
謝謝大家!
It’s still a long way to go~


(額外) Happy White Day

今天恰好是3/14,祝大家白色情人節快樂!(R code from here)

require(graphics)
dat<- data.frame(t=seq(0, 2*pi, by=0.1) )
xhrt <- function(t) 16*sin(t)^3
yhrt <- function(t) 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t)
dat$y=yhrt(dat$t)
dat$x=xhrt(dat$t)
with(dat, plot(x,y, type="l"))
with(dat, polygon(x,y, col="hotpink")) 
points(c(10,-10, -15, 15), c(-10, -10, 10, 10), pch=169, font=5)