2017年12月21日 星期四

R 語言學習筆記 (一) : 基本語法與向量

我一直想找時間好好把 R 語言測試一番, 上週因為買 "實戰 R 語言預測分析" 觸動了我的學習欲望, 所以這幾天都在玩這個新玩具. 開始接觸到 R 語言是在 2015 年從市圖借了一本大數據的書, 雖然抱著極大學習熱忱, 但無奈時間總是不夠用, 只能偶而望著書架過乾癮. 今年 228 連假時我在樹莓派上安裝了 R 語言解譯器, 實測發現雖然繪圖效能沒有 PC 好, 但樹莓派低功耗可 24 小時開機的特性, 非常適合在背景中進行資料探勘, 從此開始學習 R 語言.

以下是綜合過去一段時間斷斷續續寫下的備忘與這幾天重新複習 R 基本語法後所整理的筆記, 參考了下面幾本書 :
  1. R 語言資料分析活用範例詳解 (方匡南等, 碁峰出版)
  2. R 語言-邁向 Big Data 之路 (洪錦魁, 蔡桂宏, 上奇出版)
  3. 應用 R 語言於資料分析-從機器學習, 資料探勘, 到巨量資料 (李仁鐘, 松崗)
  4. 利用 R 語言打通大數據的經脈 (黃文, 王正林, 佳魁出版)
  5. R 錦囊妙計 (Paul Teeter, 歐萊里出版)
  6. R 軟體資料分析基礎與應用 (旗標)
R 語言解譯器在 Windows/Linux 均可安裝 (樹莓派亦可), 參考 :

R 語言安裝
在樹莓派上安裝 R 語言

R 語言線上文件參考 (HTML) :

https://stat.ethz.ch/R-manual/R-devel/library/base/html/

R 語言的特性 :
  1. R 是免費開源 (GPL) 的跨平台高階語言, 具有強大的統計分析與圖形處理功能. 
  2. R 是直譯的動態語言, 變數使用前不須宣告資料型態.
  3. R 是指令式 (Imperative) 語言, 按照敘述流程一行一行執行.  
  4. R 是函數式 (Functional) 語言, 函數是第一級 (first-class) 物件, 函數可當變數並遞迴呼叫. 
  5. R 是物件導向 (Object-Oriented) 語言, 所有的資料都以物件型態儲存.
  6. R 程式在運算時會將資料全部載入記憶體, 因此只要記憶體夠大, R 的執行速度很快. 
R 語言揉合了各種語言的功能, 但它並非萬靈丹. R 的長處在於圖形繪製, 資料分析, 與統計建模; 但不能像 Python 那樣拿來撰寫桌面, 網頁, 或電玩遊戲程式. R 誕生於 1994 年 (比 Java 還老 1 歲, 比 Python 年輕 3 歲), 發展迄今已逾 24 年, 目前由包括 R 語言之父 Ross Ihaka 與 Robert Gentleman 在內的 18 人核心開發團隊維護, 每年四月與十月各發布一次版本更新於 CRAN ( R 語言綜合典藏網).

一. 敘述與註解 :

R 語言的敘述以跳行為界, 不須用分號結束 (有加分號結尾也不會錯誤). 在 R 控制台若敘述不完全就按 Enter 鍵跳行會在下一行開頭出現 + 表示需要繼續輸入未完成部分 :

> 1+2+
+ 3+4+
+ 5
[1] 15

R 語言以 # 作為程式註解標記, # 後面的敘述會被直譯器認為是註解不予執行. 輸出訊息最前面的 [1] 表示 15 是向量的第一個元素索引, 如果元素很多跳行列印時, 開頭的索引有助於找尋元素位置, 例如呼叫內建函數 runif() 產生 20 個均勻分布的隨機數時, 每列輸出 6 個隨機數, 可利用前面中括號內的索引找到特定元素 :

>x <- p="" runif="">>x
 [1] 0.22747749 0.82250470 0.99277969 0.26681451 0.33374732 0.14401908
 [7] 0.99045832 0.79202189 0.40882923 0.07766307 0.29366118 0.37315030
[13] 0.22812758 0.47525042 0.39673555 0.43922495 0.69614128 0.42930582
[19] 0.73167837 0.65415575


R 是向量語言, 其資料都是以向量建構而成, 運算結果均為向量. 在 R Console 介面直接輸入變數按 Enter 會自動呼叫 print() 函數輸出結果, 但在程式檔案中則必須使用 print() 才會輸出.


二. 變數與函數名稱 (識別字) :

R 語言識別字的命名規則如下 :
  1. 識別字由英文字母, 數字 (0~9), 小數點符號, 或底線組成. 
  2. 英文字母有分大小寫, Tony 與 tony 是不同的識別字. 
  3. 只能以字母或小數點開頭, 若以小數點開頭, 後面不可以是數字或底線.
  4. 不可使用 R 語言保留字.
  5. 函數名稱與變數名稱相同無妨, 函數 f() 與變數 f 可同時存在. 
R 語言常用點式風格 (dot style) 來命名變數或資料型態, 例如 temperature.Taipei, data.frame 等, 許多內建函數也採用點式風格, 例如 is.integer(), as.integer() 等等, 這是因為 R 的早期版本不允許在識別字使用底線, 因此大量地使用句點當作識別字連接字符, 後來雖然可以使用底線了, 但 R 語言的句點串接風格已成為一種慣例.

R 的保留字一共有 19 個如下, 這些都不可以當變數或函數名稱 :

其中 9 個是流程控制與函數語法保留字 :

ifelserepeatwhilefunctionforinnextbreak

其次是 10 個特殊符號保留字 :

TRUEFALSENULLInfNaNNA
NA_integerNA_realNA_complexNA_character

其中 TRUE/FALSE 是資料型態 logical 的兩種值域, NULL 是空物件, Inf 表示無限大值 (除以 0 情況), NaN 表示非數字, NA/NA_integer/NA_real/NA_complex/NA_character 用來表示五種遺漏值 (沒有內容, 例如問卷中的未填欄位). 例如 :

> 1==1
[1] TRUE
> 1==2
[1] FALSE
> 1/0
[1] Inf
> -1/0
[1] -Inf
> Inf-Inf
[1] NaN

另外還有 5 個內建常數也不要使用作為識別字, 雖然作為變數名稱不會出現錯誤, 但會破壞這些內建常數的預設值 (很奇怪, 常數不應該允許被修改才對) :

piLETTERSlettersmonth.abbmonth.name

> pi
[1] 3.141593
> LETTERS
 [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
> letters
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
> month.abb
 [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
> month.name
 [1] "January"   "February"  "March"     "April"     "May"       "June"
 [7] "July"      "August"    "September" "October"   "November"  "December"

R 語言變數的指定或賦值 (assignment) 可以用如下四種方式 :

x = 5
x <- 5   (建議用法)
5 -> x
asign("x", 5)

其中第二種方式是 R 語言建議的用法, 而 "=" 則不建議使用, 因為等號賦值只在 R Console 互動模式下輸入完整敘述時可用, 而且某些情況下會有混淆問題, 例如在 SQL 命令時, "=" 是比較是否相等, 這容易與賦值造成混淆. 參考 :

https://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html

不論是 "<-" 或 "=" 都可以用來同時賦值多個變數, 例如 :

> a <- b <- 2
> a
[1] 2
> b
[1] 2
> a = b = 2
> a
[1] 2
> b
[1] 2

合法的變數名稱範例如下 :

> name <- "tony"
> name
[1] "tony"
> .name <- "Tony"
> .name
[1] "Tony"
> p2p <- "peer to peer"
> p2p
[1] "peer to peer"
> .n_ame="tony"           #小數點後面不是數字或底線可也
> .n_ame
[1] "tony"
> IF=TRUE                   #IF 不是保留字可也
> IF
[1] TRUE
> 名字 <- "Tony"      #可以使用中文當變數名稱 (各語言字母均可)
> 名字
[1] "Tony"
> assign("x",1)
> x
[1] 1

雖然允許使用中文作為變數名稱, 但是為了程式可攜性, 最好只使用英文字母.

下面則是不合法的變數名稱 :

> if=TRUE                                              #不可以使用保留字 if
錯誤: 未預期的 '=' in "if="
> NA=""                                                  #不可以使用保留字 NA
Error in NA = "" : (do_set) 賦值公式左側不正確
> .2name="tony"                                     #小數點後面不可以是數字
錯誤: unexpected symbol in ".2name"
>._name="tony"                                      #小數點後面不可以是底線
錯誤: unexpected input in "_"

另外, R 語言以跳行作為一個敘述結束標記, 若跳行時敘述不完整, 則會出現 "+" 符號表示繼續輸入未完部分. 若要在一行裡執行多個敘述, 則個敘述之間用分號 ";" 隔開即可, 例如 :

> v1 <- 1:10; v2 <- c("A", "B")
> v1
 [1]  1  2  3  4  5  6  7  8  9 10
> v2
[1] "A" "B"


三. 資料型態 :

R 是物件導向語言, R 所有的東西不論是常數, 變數, 函數, 甚至表示式都是物件. R 常用的資料物件有下面幾種 :
  1. 向量 (vector) 
  2. 矩陣 (matrix)
  3. 陣列 (array)
  4. 因子 (factor)
  5. 列表 (list)
  6. 資料框 (data.frame)
  7. 日期物件 (Date)
  8. 日期時間物件 (POSIXct/POSIXt)
其中向量是 R 最基本的物件, R 沒有純量 (scaler) 資料型態, 其最小的資料型態是向量 (vector), 所有其他資料物件 (matrix, factor, array, list, data.frame 等) 都是用向量建構的. R 語言中看似純量的資料例如 5 或 pi 其實都是只包含單一元素的向量. R 的大部分運算都是向量運算, 運算子會套用到每一個向量元素上 (不需要迴圈迭代), 函數的傳回值也是向量, 因此 R 可說是以向量資料為基礎的向量運算語言, 例如 :

> 5
[1] 5                   #純量 5 在 R 中是單一元素的向量
> length(5)    #查詢向量長度 (元素個數)
[1] 1
> 5[1]            #索引 1 就是資料本身
[1] 5
> 5[2]            #索引 2 無值=NA
[1] NA

R 的向量資料有如下 6 種類型, 稱為原型向量 (atomic vector), 此乃相對於被稱為泛型向量 (generic vector) 的列表 (list) 而言, 泛型向量例如 list 的元素允許異質, 亦即可以是任何資料物件 (vector, list, array, matrix, data.frame 等等), 但向量的元素必須是同質性資料 (即全部元素之資料型態必須相同) :

 資料類型 說明
 integer 整數資料, 以 L 結尾, 例如 10L.
 numeric 數值資料, 包含整數與倍精度實數 (預設), 可用浮點或科學記號形式. 
 character 字元資料, 使用單引號或雙引號夾住.
 logical 布林資料, 只有 T (TRUE) 與 F (FALSE) 兩種值.
 complex 複數資料, 即 a+bi 包含實部 a 與虛部 b 的複數
 raw 原始資料, 以二進位形式

注意, 類型 numeric 包含 integer 與 double 兩種數值, 預設是 double (實數), 可用浮點數如 3.14159 或科學記號 3.14159e1 表示. 向量可用 class(), typeof(), mode(), 或 storage.mode() 這四個內建函數查詢其類型. 其次, R 與數學習慣一樣使用小寫 i 來表示虛數, 這與 Python 偏向工程界使用 j 來表記虛數有所不同.

常數看似純量 (scaler), 但其實是只含有一個元素的向量, 例如在 R console 輸入數字或字串 :

> 5                                     #單一元素的向量 (整數)
[1] 5
> "Tony"                            #單一元素的向量 (字元)
[1] "Tony"
> 6.626069934e-34           #科學表示法 (普郎克常數)
[1] 6.62607e-34
> 6.626069934*10^-34     #指數表示法 (普郎克常數)
[1] 6.62607e-34

上面輸出訊息的每一列開頭會顯示該列第一個元素的索引, 常數向量 5 只含有一個元素 5, [1] 表示此輸出列第一個元素 5 在向量中的索引為 1.

向量是有序的同類型資料 (即不可文字與數字夾雜), 相當於是一維陣列, 其元素 (分量) 可以用索引存取, 例如向量 v 的第 i 個元素為 v[i]. 不過與 C 或 Python 等語言不同的是, R 的有序資料物件索引都是從 1 起始的, 不是 0.

在 R 語言大部分的向量含有多個分量 (元素), R 提供了多種方法來建立數值向量 :
  1. 冒號運算子 
  2. seq() 函數
  3. rep() 函數
  4. integer(), numeric(), character(), logical(), complex(), raw() 函數
  5. vector() 函數

1. 使用冒號運算子建立向量 : 

建立向量的第一個方法是利用冒號運算子來產生間隔為 1 的向量, 例如 1:50 表示含有元素 1~50 的整數向量, 例如 :

> 1:50
 [1]  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] 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
[49] 49 50

冒號運算子也可以用在浮點數, 間隔同樣是 1:

> 2.2:9.9
[1] 2.2 3.2 4.2 5.2 6.2 7.2 8.2 9.2
> 9.9:2.2
[1] 9.9 8.9 7.9 6.9 5.9 4.9 3.9 2.9

可以將向量指定給變數, 以索引來存取元素. 與 Python 或 C 語言族系不同的是, R 語言的索引是從 1 起算的, 若索引超出範圍將輸出 NA, 表示此為缺漏值 :

> n <- 1:50
> n
 [1]  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] 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
[49] 49 50
> n[25]                            #使用索引存取向量元素
[1] 25
> n[51]                            #不存在的索引其值為 NA
[1] NA        


R 輸出此向量時每 24 個元素為一列, 因此第二列第一個元素索引為 25, 第三列第一個元素索引為 49. 如果 ":" 冒號運算子前面數值比後面數值大, R 會自動偵測出此為遞減序列, 例如 :

> 9:0
 [1] 9 8 7 6 5 4 3 2 1 0

R 提供內建函數 c() 來連接向量 (c 表示 combine 或 concat), 例如 :

> fibo <- c(0,1,1,2,3,5,8,13)         #8 個費伯納西整數向量
> fibo
[1]  0  1  1  2  3  5  8 13
> fibo[4]                                            #第 4 個元素為 2 (索引從 1 起算)
[1] 2
> users <- c("Tony","Peter","Kelly","Amy")       #字串向量
> users
[1] "Tony"  "Peter" "Kelly" "Amy"
> users[2]                                          #第 2 個元素為 "Peter" (索引從 1 起算)
[1] "Peter"
users[5]                                                   #不存在的元素
[1] NA   
> adult <- c(TRUE,FALSE,FALSE,FALSE)       #布林向量
> adult
[1]  TRUE FALSE FALSE FALSE
> adult[1]                                           #第 1 個元素為 TRUE (索引從 1 起算)
[1] TRUE

向量的索引可以用 ":" 運算子做範圍存取, 但不能向 Python 的串列那樣頭尾不指定時表示到頭或到尾, 例如 :

> fibo[4:6]
[1] 2 3 5
> users[3:]                                   #不支援
錯誤: 未預期的 ']' in "users[3:]"
> users[:4]                                   #不支援
錯誤: 未預期的 ':' in "users[:"
> users[3:4]
[1] "Kelly" "Amy" 

向量的索引可用負數排除指定元素, 例如 -2 表示排除索引 2 :

> users <- c("Tony","Peter","Kelly","Amy")
> users_1 <- users[-2]              #排除索引 2
> users_1
[1] "Tony"  "Kelly" "Amy"

也可以傳入真值向量來排除, 例如 :

> users <- c("Tony","Peter","Kelly","Amy")
> users[c(TRUE,FALSE,TRUE,TRUE)]    #排除索引 2
[1] "Tony"  "Kelly" "Amy"

連接函數 c() 可以連接不同類型的原型向量, 但串接後元素類型會改變, logical 與 numeric 串接 TRUE/FALSE 會變 1/0; logical 與 character 串接 TRUE/FALSE 會變 "TRUE"/"FALSE"; numerical 與 character 串接則全部變 character :

> fibo <- c(0,1,1,2,3,5,8,13)
> users <- c("Tony","Peter","Kelly","Amy")
> adult <- c(TRUE,FALSE,FALSE,FALSE)
comp <- c(1+1i,2+2i)
> c(adult,fibo)
 [1]  1  0  0  0  0  1  1  2  3  5  8 13     #全部變整數
> c(adult,users)
[1] "TRUE"  "FALSE" "FALSE" "FALSE" "Tony"  "Peter" "Kelly" "Amy"    #全部變字串
> c(fibo,users)
 [1] "0"     "1"     "1"     "2"     "3"     "5"     "8"     "13"    "Tony"
[10] "Peter" "Kelly" "Amy"
> c(comp,fibo)
 [1]  1+1i  2+2i  0+0i  1+0i  1+0i  2+0i  3+0i  5+0i  8+0i 13+0i      #全部變複數
> c(comp,users)
[1] "1+1i"  "2+2i"  "Tony"  "Peter" "Kelly" "Amy"      #全部變字串
> c(comp,adult)
[1] 1+1i 2+2i 1+0i 0+0i 0+0i 0+0i        #全部變複數

可見任何類型與字元向量串接全部會被轉型為字元, 數值, 布林值與複數串接全部被轉型為複數, 亦即 character 擁有最大的同化能力, complex 次之, numerical 又次之; 而 logical 則總是被同化, 其同化能力可以用下列關係表示 :

character > numerical > integer > logical


2. 使用 seq() 函數建立向量 :

建立向量的第二個方法是用 seq() 函數. 冒號 ":" 運算子只能產生間隔為 1 的向量, 若要產生規則間隔的數值序列可使用內建的 seq() 函數. 在 R console 輸入 help(seq) 可知 seq() 主要有 4 個參數 :
  1. from : 起值
  2. to : 終值
  3. by : 增量值 (負為減量值)
  4. length 或 length.out : 元素個數
其中前三個參數若不指明固定為 to , from 與 by, 其餘必須指明.  參數 from 為起值, to 為終值, by 則為增量值, length 為向量長度 (即元素個數), 其中 by 預設值為 1, 例如 :

> seq(from=1,to=10,by=2)         #1~10 的奇數
[1] 1 3 5 7 9
> seq(from=2,to=10,by=2)         #2~10 的偶數
[1]  2  4  6  8 10
> seq(1,10,2)                               #不指明時預設參數為 to, from, by
[1] 1 3 5 7 9
> seq(from=-5,to=5)                   #by 預設值為 1
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5
> seq(from=-5,to=5,length=11)  #11 個元素  (相當於 by=2)
[1] -5 -4 -3 -2 -1  0  1  2  3  4  5
> seq(from=-5,to=5,length=5)    #元素長度 5 個
[1] -5.0 -2.5  0.0  2.5  5.0
> seq(from=5,to=-5,by=1)          #倒序時 by 須為負數
Error in seq.default(from = 5, to = -5, by = 1) :
  wrong sign in 'by' argument
> seq(from=5,to=-5,by=-1)         #倒序時 by 須為負數
 [1]  5  4  3  2  1  0 -1 -2 -3 -4 -5

seq() 也可以產生實數向量, 例如 :

> seq(from=3.5,to=10.2)              #by 預設為 1
[1] 3.5 4.5 5.5 6.5 7.5 8.5 9.5
> seq(from=-5,to=5,length=9)      #9 個元素
[1] -5.00 -3.75 -2.50 -1.25  0.00  1.25  2.50  3.75  5.00

3. 使用 rep() 函數建立向量 :

R 還有一個重複函數 rep() 常用於產生向量物件, 以 help(rep) 查詢可知 rep() 除了要重複的向量當第一參數外, 主要有下面 3 個參數 :
  1. times : 重複次數, 若不指明此為預設第二參數 (預設值為 1)
  2. length 或 length.out : 重複後之向量元素個數
  3. each : 每個元素重複次數 (each 須大於 0)
其中 times 為預設之第二參數可以不指明, 例如 :

> names <- c("花甲","雅婷", "阿瑋")
> rep(names)                         #預設重複 1 次
[1] "花甲" "雅婷" "阿瑋"
> rep(names, 3)                     #重複 3 次
[1] "花甲" "雅婷" "阿瑋" "花甲" "雅婷" "阿瑋" "花甲" "雅婷" "阿瑋"
> rep(names, length=3)         #重複後向量長度為 3
[1] "花甲" "雅婷" "阿瑋"
> rep(names, length=5)         #重複後向量長度為 5
[1] "花甲" "雅婷" "阿瑋" "花甲" "雅婷"
> rep(names, 2, 2)                 #重複 2 次, 但重複後向量長度為 2
[1] "花甲" "雅婷"
> rep(names, 2)                     #重複 2 次
[1] "花甲" "雅婷" "阿瑋" "花甲" "雅婷" "阿瑋"
> rep(names, 2, each=2)        #整個向量重複 2 次, 重複時每個元素重複 2 次
 [1] "花甲" "花甲" "雅婷" "雅婷" "阿瑋" "阿瑋" "花甲" "花甲" "雅婷" "雅婷"
[11] "阿瑋" "阿瑋"
> rep(names, 2, each=0)        #重複次數須大於 0
character(0)

不過 each 參數只能以固定次數重複每個元素, 如果要指定各元素的重複次數該怎麼做? 這時可傳入整數向量的 times 參數來達成, 但要注意 times 向量元素個數須與被重複之向量元素個數相等, 否則會執行錯誤, 例如 :

> rep(c(4,5,6), c(1,2,3))                    #參數 times 為向量
[1] 4 5 5 6 6 6
> rep(c("花甲","雅婷","阿瑋"), c(1,2,3))           #參數 times 為向量
[1] "花甲" "雅婷" "雅婷" "阿瑋" "阿瑋" "阿瑋"
> rep(1:5, 1:4)                                   #參數 times 少一個元素
Error in rep(1:5, 1:4) : 'times' 引數不正確
> rep(1:5, 1:5)                                   #參數 times 元素個數剛剛好
 [1] 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
> rep(1:5, 1:6)                                   #參數 times 多一個元素
Error in rep(1:5, 1:6) : 'times' 引數不正確

4. 使用原型向量函數建立向量 :

R 語言對 6 種原型向量都提供了同名的函數來建立向量 :

 函數 說明
 integer(length) 建立長度為 length 的整數向量
 double(length) 建立長度為 length 的實數向量
 numeric(length) 建立長度為 length 的實數向量
 character(length) 建立長度為 length 的字元向量
 logical(length) 建立長度為 length 的布林向量
 complex(length) 建立長度為 length 的複數向量
 raw(length) 建立長度為 length 的 byte 向量

函數 numeric(length) 會建立一個長度為 length, 值為 0 的實數向量 (double), 例如 :

> numeric(10)                #建立一個含有 10 個元素的 0 向量
 [1] 0 0 0 0 0 0 0 0 0 0
> (v=numeric(10))         # 外圍的 () 代表 print()
 [1] 0 0 0 0 0 0 0 0 0 0
> v
 [1] 0 0 0 0 0 0 0 0 0 0
> v[1] <- 1; v[7] <- 7; v[10] <- 10     #更改 0 向量元素值
> v
 [1]  1  0  0  0  0  0  7  0  0 10
> v=numeric(10)
> class(v)
[1] "numeric"
> mode(v)
[1] "numeric"
> typeof(v)
[1] "double"         #numerc() 建立的是 double 實數

函數 integer(length) 會建立一個長度為 length, 值為 0 的整數向量 (integer), 例如 :

> v=integer(10)
> class(v)
[1] "integer"
> mode(v)
[1] "numeric"
> typeof(v)
[1] "integer"

5. 使用 vector() 函數建立向量 :

函數 vector() 可建立指定資料類型 (預設 logical) 與長度 (預設 0) 之向量, 格式如下  :

vector(mode="logical", length = 0)

例如 :

> vector()      #建立空向量 (預設 logical)
logical(0)            #空的 logical 向量
> v=vector(mode="integer",length=5)    #建立長度為 5 的整數向量
> v
[1] 0 0 0 0 0
> mode(v)
[1] "numeric"      #模式 (mode) 為 numeric
> class(v)       #類型 (class) 為 integer
[1] "integer"
> v=vector(mode="double",length=5)    #建立長度為 5 的實數向量
> v
[1] 0 0 0 0 0
> class(v)
[1] "numeric"       #模式 (mode) 為 numeric
> mode(v)       #類型 (class) 為 numeric
[1] "numeric"
> v=vector(mode="double",length=10)
> v
 [1] 0 0 0 0 0 0 0 0 0 0
> v[1] <- 1; v[7] <- 7; v[10] <- 10
> v
 [1]  1  0  0  0  0  0  7  0  0 10


四. 運算子 :

R 語言基本資料型態為向量, 因此主要的運算也是向量運算, 其運算子如下 :

 運算子 說明
 ** 平方
 ^ 次方
 + - 取正負 (單元運算)
 %/% 整數除法取商
 %% 整數除法取餘數
 * / + - 四則運算
 %*% 矩陣乘法

運算子優先順序如下 :
  1. 指數 : 平方, 次方
  2. 乘, 除, 取商, 取餘數 : 依出現之先後次序
  3. 加, 減 : 依出現之先後次序 
但括號可以改變優先順序, 括號內的優先運算.

例如 :

> 3**2        #平方
[1] 9
> 3^2          #平方
[1] 9
> c(1,2,3,4,5)**2     #各分量都平方
[1]  1  4  9 16 25
> (1:10)**2              #各分量都平方 
 [1]   1   4   9  16  25  36  49  64  81 100
> 5e5/2e3                 #科學表示法指數相除
[1] 250
> 1*2/3                     #乘除依照順序計算 (先乘後除)
[1] 0.6666667
> 1/2*3                     #乘除依照順序計算 (先除後乘)
[1] 1.5


五. 內建函數 :

R 語言內建很多好用函數, 因為 R 是向量語言, 這些函數的傳回值都是向量.

1. 向量建構函數 : 

函數 說明
 c(x1, x2, ...) 將向量或純量組合成新的向量
 seq(from, to, by, length) 以起始值 from, 終值 to, 間隔 length 建立向量
 rep(x, times) 將向量 x 重複 times 次組合成新的向量
 numeric(length) 建立一個長度為 length 值為 0 的數值向量
 vector(mode, length) 建立類型 mode (預設 logical) 長度 length (預設 0) 之向量

這些函數的用法已如上述.

2. 物件結構查詢函數 :

 函數 說明
 str(x) 顯示物件結構與內容
 length(x) 計算向量長度 (即元素或分量個數)
 dim(x) 顯示物件的因次 (dimension 維度)
 class(x) 顯示物件類型
 mode(x) 顯示物件模式
 typeof(x) 顯示物件類型
 storage.mode(x) 顯示物件之儲存模式

這些函數主要用來查詢資料物件之結構訊息, str() 用來檢查物件結構與內容, 例如 :

> str(1:10)
 int [1:10] 1 2 3 4 5 6 7 8 9 10
> str(c(1.1, 2.2, 3.3))
 num [1:3] 1.1 2.2 3.3
> str(c("A", "B", "C"))
 chr [1:3] "A" "B" "C"
> str(c(TRUE, FALSE, T, F))
 logi [1:4] TRUE FALSE TRUE FALSE
> str(c(1+1i, 2+2i))
 cplx [1:2] 1+1i 2+2i
> str(raw(3))
 raw [1:3] 00 00 00
> str(c(NA, NA))
 logi [1:2] NA NA
> str(c(NA, NULL))
 logi NA

length() 傳回向量的元素個數 :

> length(100)
[1] 1
> length(1:10)
[1] 10
> length(c("a","b","c"))
[1] 3

dim() 查詢物件的維度, 主要是用在矩陣, 陣列, 資料框等較複雜資料型態. 向量雖然看起來像是一維陣列, 但其實 R 語言的向量與因子類型是沒有維度的 (NULL), 例如 :

> dim(1:5)       #向量沒有維度 (NULL)
NULL           
> dim(matrix(1:10, 2))
[1] 2 5
> dim(array(1:10, 2))
[1] 2
> dim(array(1:24, c(3,4,2)))
[1] 3 4 2
> dim(factor(c("A","B","B","C")))    # factor 類型沒有維度 (NULL)
NULL
> name <- c("Kelly", "Peter", "Amy")
> gender <- c("Female", "Male", "Female")
> height <- c(162, 170, 161)
> dim(data.frame(name, gender, height))
[1] 3 3

四個檢查資料類型的函數 : class(), mode(), typeof(), storage.mode(), 傳回值差異不大, 其中 typeof() 與 storage.mode() 能區分出 integer 與 double; class() 可區分出 integer, 而 mode() 則通通視為 numeric, 例如 :

> class(1:5)
[1] "integer"
> mode(1:5)
[1] "numeric"
> typeof(1:5)
[1] "integer"
> storage.mode(1:5)
[1] "integer"
> class(c(3.14, 1.728))
[1] "numeric"
> mode(c(3.14, 1.728))
[1] "numeric"
> typeof(c(3.14, 1.728))
[1] "double"
> storage.mode(c(3.14, 1.728))
[1] "double"
> class(c(TRUE, FALSE))
[1] "logical"
> mode(c(TRUE, FALSE))
[1] "logical"
> typeof(c(TRUE, FALSE))
[1] "logical"
> storage.mode(c(TRUE, FALSE))
[1] "logical"
> class(c("A", "B", "C"))
[1] "character"
> mode(c("A", "B", "C"))
[1] "character"
> typeof(c("A", "B", "C"))
[1] "character"
> storage.mode(c("A", "B", "C"))
[1] "character"
> class(c(1+2i, 1-2i))
[1] "complex"
> mode(c(1+2i, 1-2i))
[1] "complex"
> typeof(c(1+2i, 1-2i))
[1] "complex"
> storage.mode(c(1+2i, 1-2i))
[1] "complex"
> class(vector(mode="raw"))
[1] "raw"
> mode(vector(mode="raw"))
[1] "raw"
> typeof(vector(mode="raw"))
[1] "raw"
> storage.mode(vector(mode="raw"))
[1] "raw"

輸出摘要如下表 :

類型 class() mode() typeof() storage.mode()
 integer integer numeric integer integer
 numeric numeric numeric double double
 charactor charactor charactor charactor charactor
 logical logica logica logica logica
 complex complex complex complex complex
 raw raw raw raw raw


3. 物件判斷函數 :

R 語言提供下列函數來判斷一個物件是否為某種資料類型 :

 函數 說明
 is.integer(x) 判斷是否為整數向量
 is.double(x) 判斷是否為實數向量
 is.numeric(x) 判斷是否為數值向量
 is.character(x) 判斷是否為字元向量
 is.logical(x) 判斷是否為布林向量
 is.complex(x) 判斷是否為複數向量
 is.raw(x) 判斷是否為原始數據向量
 is.array(x) 判斷是否為陣列物件
 is.list(x) 判斷是否為列表物件
 is.factor(x) 判斷是否為因子物件
 is.matrix(x)  判斷是否為矩陣物件
 is.data.frame(x) 判斷是否為資料框物件

例如 :

> is.integer(c(1,2,3))    #R 的數值預設是 double
[1] FALSE
> typeof(c(1,2,3))
[1] "double"
> i=integer(3)
> i
[1] 0 0 0
> is.integer(i)
[1] TRUE
> is.numeric(i)
[1] TRUE
> d=double(3)
> d
[1] 0 0 0
> is.integer(d)
[1] FALSE
> is.numeric(d)
[1] TRUE

由於 R 語言的數值預設是 double, 因此 c(1,2,3) 是 double 類型的數值向量, 用 is.integer() 去檢驗會得到 FALSE, 必須用 integer() 建立的向量才是整數向量.

但若用 integer() 建立整數向量後, 卻填入浮點數, R 語言會自動將此向量轉型為 double, 例如 :

> i=integer(3)    #建立有 3 元素之整數向量
> i
[1] 0 0 0
> i[1]=1.1          #整數向量填入實數
> i
[1] 1.1 0.0 0.0
> typeof(i)          #自動轉型為實數向量
[1] "double"


4. 轉型函數 : 

R 語言的每一種類型的資料物件都可以透過 as.xxx() 函數強制轉型 :

 函數 說明
 as.integer(x) 判斷是否為整數向量
 as.double(x) 判斷是否為實數向量
 as.numeric(x) 判斷是否為數值向量
 as.character(x) 判斷是否為字元向量
 as.logical(x) 判斷是否為布林向量
 as.complex(x) 判斷是否為複數向量
 as.raw(x) 判斷是否為原始數據向量
 as.array(x) 判斷是否為陣列物件
 as.list(x) 判斷是否為列表物件
 as.factor(x) 判斷是否為因子物件
 as.matrix(x)  判斷是否為矩陣物件
 as.data.frame(x) 判斷是否為資料框物件

例如 :

> v <- c(1,2,3)            #建立一個實數向量
> v
[1] 1 2 3
> class(v)
[1] "numeric"
> a <- as.integer(v)     #強制轉型為整數向量
> a
[1] 1 2 3
> class(a)
[1] "integer"
> a <- as.character(v)  #強制轉型為字元向量
> a
[1] "1" "2" "3"
> class(a)
[1] "character"
> a <- as.logical(v)      #強制轉型為布林向量
> a
[1] TRUE TRUE TRUE
> class(a)
[1] "logical"
> a <- as.complex(v)    #強制轉型為複數向量
> a
[1] 1+0i 2+0i 3+0i
> class(a)
[1] "complex"
> a <- as.raw(v)            #強制轉型為原始數據向量
> a
[1] 01 02 03
> class(a)
[1] "raw"
> a <- as.array(v)          #強制轉型為陣列物件
> a
[1] 1 2 3
> class(a)
[1] "array"
> a <- as.list(v)              #強制轉型為列表物件
> a
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

> class(a)
[1] "list"
> a <- as.factor(v)          #強制轉型為因子物件
> a
[1] 1 2 3
Levels: 1 2 3
> class(a)
[1] "factor"
> a <- as.matrix(v)         #強制轉型為矩陣物件
> a
     [,1]
[1,]    1
[2,]    2
[3,]    3
> class(a)
[1] "matrix"
> a <- as.data.frame(v)    #強制轉型為資料框物件
> a
  v
1 1
2 2
3 3
> class(a)
[1] "data.frame"


5. 排序函數 : 

排序函數可對數值元素進行排序 :

 函數 說明
 sort(x) 將向量元素由小至大排序
 rev(x) 將向量元素由大至小排序
 rank(x) 顯示向量的秩 (即原向量之元素排序後之索引位置)

注意, 這裡的秩 (rank) 並非矩陣中的秩, 而是原向量元素經 sort() 排序後的索引位置, 例如 :

> v=c(9,4,7,2,1,6,3)
> sort(v)
[1] 1 2 3 4 6 7 9        #由小至大排序
> v
[1] 9 4 7 2 1 6 3        #sort() 不會影響原向量
> rank(v)             #若 sort() 則元素在原向量之索引
[1] 7 4 6 2 1 5 3
> rev(v)               #由大至小排序
[1] 3 6 1 2 7 4 9
> v
[1] 9 4 7 2 1 6 3        #rev() 不會影響原向量

可見呼叫 sort() 或 rev() 並不會改變原向量, 而是傳回一個排序後的新向量. rank() 的傳回值顯示原向量第一個元素 9 排序後將位於索引 7; 第二個元素 4 位置在索引 4, ..., 因此 rank()

6. 數學函數 :


 函數 說明
 c(x1, x2, ...) 將向量或純量組合成新的向量
 seq(from, to, by, length) 以起始值 from, 終值 to, 間隔 length 建立向量
 rep(x, times) 將向量 x 重複 times 次組合成新的向量
 numeric(length) 建立一個長度為 length 值為 0 的數值向量
 length(x) 計算向量長度 (即元素或分量個數)
 range(x) 查詢數值向量元素範圍
 range(x1, x2, ...) 查詢全部數值向量之元素範圍 
 sum(x) 計算數值向量之元素和 
 sum(x1, x2, ...) 計算全部數值向量之元素和
 cumsum(x) 計算數值向量各分量的累積和
 prod(x) 計算數值向量各分量的乘積
 prod(x1, x2, ...) 計算全部數值向量各分量的乘積
 cumprod(x) 計算全部數值向量各分量的累積乘積
 round(x, digits=0) 將數值向量各分量四捨五入至指定位數
 ceiling(x) 求大於等於各分量之最小整數
 floor(x) 求小於等於各分量之最大整數
 trunc(x) 將數值向量各分量無條件捨去
 signif(x, digits=6) 將數值向量各分量由左到右四捨五入至指定位數
 min(x) 求數值向量各分量之最小值
 min(x1, x2, ...) 求全部數值向量各分量的最小值
 pmin(x1, x2, ...) 求全部數值向量各對應分量的最小值
 cummin(x) 求數值向量各分量累積最小值
 max(x) 求數值向量各分量之最大值
 max(x1, x2, ...) 求全部數值向量各分量的最大值
 pmax(x1, x2, ...) 求全部數值向量各對應分量的最大值
 cummax(x) 求數值向量各分量累積最大值
 abs(x) 求數值向量各分量之絕對值
 sqrt(x) 求數值向量各分量之平方根
 log(x) 求數值向量各分量之自然對數
 log2(x) 求數值向量各分量以 2 為底之對數
 log10(x) 求數值向量各分量以 10 為底之對數
 exp(x) 求數值向量各分量之自然指數
 sin(x) 求數值向量各分量之正弦
 cos(x) 求數值向量各分量之餘弦
 tan(x) 求數值向量各分量之正切
 asin(x) 求數值向量各分量之反正弦
 acos(x) 求數值向量各分量之反餘弦
 atan(x) 求數值向量各分量之反正切
 mean(x) 求數值向量各分量之平均值
 sd(x) 求數值向量各分量之標準差
 var(x) 求數值向量各分量之變異數
 median(x) 求數值向量各分量之正弦中位數
 factorial(x) 階乘函數=x*(x-1)*(x-2)*....*3*2*1

例如 :

四捨五入函數 :

R 的四捨五入函數有兩個 : 
  1. round(x, digits=0)
  2. signif(x, digits=6)
round() 的第二參數 digits 預設是 0, 可為正整數或負整數, 正整數時表示要四捨五入到小數點後第幾位, 例如 :

> round(1.23456789)        #預設四捨五入到個位數
[1] 1
> round(1.23456789,1)     #四捨五入到小數點後第 1 位
[1] 1.2
> round(1.23456789,2)
[1] 1.23
> round(1.23456789,3)
[1] 1.235
> round(1.23456789,4)
[1] 1.2346
> round(12345.6789)
[1] 12346
> round(12345.6789, 1)
[1] 12345.7
> round(12345.6789, 2)
[1] 12345.68
> round(12345.6789, 3)       
[1] 12345.68                            #奇怪, 不是應該 12345.679 嗎?

當 digits 為負整數時, -1 表示要四捨五入到十位; -2 表示要四捨五入到百位; -3 表示要四捨五入到千位, ... 例如 : 

> round(12345.6789,-1)     #四捨五入到十位數
[1] 12350
> round(12345.6789,-2)     #四捨五入到百位數
[1] 12300
> round(12345.6789,-3)     #四捨五入到千位數
[1] 12000

signif() 函數的 digits 參數表示由左到右的有效位數, 將下一位數四捨五入到有效位數的最後一位, 例如 : 

> signif(12345.6789)                   #預設有效位數 6 位, 7 四捨五入至 6, 6 進一為 7
[1] 12345.7
> signif(12345.6789, digits=1)    #有效位數 1 位, 2 四捨五入
[1] 10000
> signif(12345.6789, digits=2)    #有效位數 2 位, 3 四捨五入
[1] 12000
> signif(12345.6789, digits=3)    #有效位數 3 位, 4 四捨五入
[1] 12300
> signif(12345.6789, digits=4)    #有效位數 4 位, 5 四捨五入, 4 進一為 5
[1] 12350
> signif(12345.6789, digits=5)    #有效位數 5 位, 6 四捨五入, 5 進一為 6
[1] 12346
> signif(12345.6789, digits=6)    #有效位數 6 位, 7 四捨五入, 6 進一為 7
[1] 12345.7
> signif(12345.6789, digits=7)    #有效位數 7 位, 8 四捨五入, 7 進一為 8
[1] 12345.68
> signif(12345.6789, digits=8)    #?
[1] 12345.68
> signif(12345.6789, digits=9)    #?
[1] 12345.68

近似函數 : 

R 的近似函數有 3 個 :
  1. ceiling(x) : 小於等於 x 的最大整數
  2. floor(x) : 大於等於 x 的最小整數
  3. trunc(x) : 無條件捨去至個位數
例如 :

> ceiling(123.4)
[1] 124
> ceiling(123.9)
[1] 124
> ceiling(-123.9)
[1] -123
> floor(123.9)
[1] 123
> floor(-123.9)
[1] -124
> trunc(123.9)
[1] 123
> trunc(-123.9)
[1] -123


指數與對數 :

[1] 3
> log10(10)
[1] 1
> log2(8)
[1] 3
> log10(100)
[1] 2

三角函數 :

> sin(30*pi/180)
[1] 0.5
> sin(45*pi/180)
[1] 0.7071068
> sqrt(2)/2
[1] 0.7071068
> sin(60*pi/180)
[1] 0.8660254
> sqrt(3)/2
[1] 0.8660254
> sin(90*pi/180)
[1] 1
> cos(30*pi/180)
[1] 0.8660254
> cos(45*pi/180)
[1] 0.7071068
> cos(60*pi/180)
[1] 0.5
> cos(90*pi/180)
[1] 6.123032e-17

7. 輸出函數 :

在 R Console 中輸入變數名稱或表達式後, R 會直接輸出其值. 事實上這是因為 R 自動呼叫了 print() 函數來顯示之故. R 語言提供 print() 與 cat() 兩個輸出顯示函數 :

 函數 說明
 print() 輸出一個物件內容 (一次只能一個, 會自動跳行)
 cat() 串接輸出多個向量物件 (不包含 list, matrix 等複合物件,  不會自動跳行)

print() 可以輸出任何 R 物件 (包括陣列, 列表, 矩陣等) 並予以格式化, 例如 :

> matrix(c(1,2,3,4,5,6),2,3)
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> print(matrix(c(1,2,3,4,5,6),2,3))
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

但 print() 一次只能輸出一個物件, 若要同時輸出多個物件必須連續呼叫 print() :

> print("The square of 2 is ");sqrt(2)
[1] "The square of 2 is "
[1] 1.414214

因為 print() 預設會跳行, 因此分成兩行輸出. 但 cat() 則可串接多個物件, 例如 :

> cat("The square of 2 is",sqrt(2),"\n")
The square of 2 is 1.414214


參考 :

# Variable Name Restrictions in R
R筆記–(2)基本資料型態
R Variables and Constants
Beginner's guide to R: Syntax quirks you'll want to know

沒有留言 :