行列引用、條件篩選等可以簡單的數據管理,但其在無法有效處理多次、多重、有規律的循環和判斷問題,而控制流卻可以通過循環、判斷、跳錯等等操作輕鬆處理此類問題。
以下概念貫穿控制流張杰的內容,需要首先認識:
語句(statement):單獨或組合語句,一般在{}中以;分隔 。例如:{語句1;語句2}
條件(cond): 最常見的是判斷一個條件是否成立。如果成立則執行一條語句或者一個代碼塊,比如上例a是否小於b,如果小於則輸出b
表達式(expr):一個數值或字符的求值語句,多用於數據計算過程或賦值
序列(seq):一個數值或者字符序列
目錄
1 分支控制
1.1 if-else
1.2 ifelse
1.3 switch
2 循環控制流
2.1 for循環
2.2 while循環
2.3 repeat 循環
3 function函數(一次編寫,多次調用,一勞永逸)
3.1 自定義函數編寫
3.2 source()文件間調用自定義函數
分支和循環是通用程式語言中常見的兩大控制流。其中,分支控制是根據條件表達式的結果,執行不同的代碼段;循環控制是根據條件重複執行代碼塊,為了避免無限循環,可以根據條件結束循環。接下來分別從分支控制和循環控制,對R語言中的控制流做簡單講述。
正文
1 分支控制
1.1 if-else
經典的流程控制關鍵字是if-else,並可以把多個if-else語句連接到一起
#if-else分支控制流語法if ( test_expression1) {statement1} else if ( test_expression2) {statement2} else {statement3}示例
#嵌套用法> a=5> b=6> if (a < b) {a <- -1+ } else if (a == b) {a <- 0+ } else {a <- 1}> print(a)[1] -11.2 ifelse
ifelse控制可以理解為一個函數。
#ifelse語法ifelse(條件表達式, true, false)示例
> x <- factor(sample(letters[1:5], 10, replace = TRUE))> x [1] a a c d a b d b d dLevels: a b c d> ifelse(x %in% c("a", "b", "c"), x, factor(NA)) [1] 1 1 3 NA 1 2 NA 2 NA NA注意:返回值的class屬性跟test表達式相同,其mode屬性是由 yes 或 no表達式確定的。當ifelse()用於返回Date類型的對象時,返回值是numeric類型,而不是Date類型,這是因為返回值的class是由test表達式決定的。
> dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))> dates[1] "2011-01-01" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"> dates <- ifelse(dates == '2011-01-01', dates - 1, dates)> dates[1] 14974 14976 14977 14978 14979
#解決方案是:把返回值的class重新設置為Date類型。> dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))> dates[1] "2011-01-01" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"> dates <- ifelse(dates == '2011-01-01', dates - 1, dates)> dates[1] 14974 14976 14977 14978 14979> class(dates) <- 'Date'> dates[1] "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"1.3 switch
如果分支較多,可以使用switch函數實現分支的選擇,switch函數的第一個參數是表達式(exp),通常是一個字符串。當表達式(exp)匹配後續的參數名(即變量名)時,返回參數的值
#switch語法switch(字符,參數名1='參數值2',參數名2='參數值2',……"其他")示例
#當表達式(exp)匹配後續的參數名(即變量名)時,返回參數的值> t = "r"> switch(t,r='re',g='gr',b='bl',"error")[1] "re"
#如果不匹配任何參數名,switch函數不返回任何值,可以添加一個匿名的參數,#當表達式(exp)匹配不上任意一個命名參數時,switch函數將返回匿名參數的值:> t = "xs"> switch(t,r='re',g='gr',b='bl',"error")[1] "error"2 循環控制流
repeat、while和for是常見的循環控制語句。
2.1 for循環
使用迭代器和一個向量參數,在每個循環中,迭代器變量從向量中取得一個值,直到迭代所有得向量
#語句for (變量 in 序列/字符集) {語句/表達式}示例
#依次執行序列/字符集中的每一個數據+print語句> for (i in 1:5) print(letters[i])[1] "a"[1] "b"[1] "c"[1] "d"[1] "e"
#依次執行序列/字符集中的每一個數據+表達式+print語句> for (i in 1:5) {j = j + i; print(c(i,j))}[1] 1 1[1] 2 3[1] 3 6[1] 4 10[1] 5 15> j = 0> for (i in 1:5) {j = j + i; print(c(i,j))}[1] 1 1[1] 2 3[1] 3 6[1] 4 10[1] 5 15> print(j)[1] 152.2 while循環
先檢測條件,如果條件為TRUE,執行code;如果條件為FALSE,結束循環
示例
> i=5> while (i >0) {j = i; i=i-1 ; print(c(j,i))}[1] 5 4[1] 4 3[1] 3 2[1] 2 1[1] 1 0
2.3 repeat 循環 repeat 循環:先執行代碼,遇到break關鍵字,結束循環
repeat {code if(條件) break}示例
> i=100> sum=0> repeat + {+ if(i==0)+ break+ sum=i+sum+ i=i-1+ }> print(sum)[1] 5050
3 function函數(一次編寫,多次調用,一勞永逸)
3.1 自定義函數編寫
R通過function關鍵字定義函數,函數主要由函數名稱,參數,運行的代碼塊和返回值組成,函數名稱是變量,參數是調用函數時需要傳遞的形式參數;代碼塊是由由大括號構成,是調用函數時需要執行的代碼邏輯;R的函數不需要顯式地使用return關鍵字明確返回值,R函數的計算的最後一個值將自動作為返回值。
#語法myfunc=function(arg1,arg2,....) #參數{表達式/循環/print語句等return(object) #返回輸出的對象}
示例1:簡單計算
> avg <- function(a,b)+ {+ return(mean(c(a,b)))+ }> avg(4,5)[1] 4.5
> avg <- function(a,b)+ {+ mean(c(a,b))+ }> avg(4,5)[1] 4.5示例2:矩陣計算
> mat1<-matrix(c(1:12),nrow = 3,ncol = 4);mat1 [,1] [,2] [,3] [,4][1,] 1 4 7 10[2,] 2 5 8 11[3,] 3 6 9 12> mat2<-matrix(c(1:24),nrow = 4,ncol = 6);mat2 [,1] [,2] [,3] [,4] [,5] [,6][1,] 1 5 9 13 17 21[2,] 2 6 10 14 18 22[3,] 3 7 11 15 19 23[4,] 4 8 12 16 20 24> f<-function(x,y)+ {+ xcol<-dim(x)[2]+ yrow<-dim(y)[1] + m<-dim(x)[1]+ n<-dim(y)[2]+ if(xcol!=yrow) #向量乘積的要求+ {+ print("error")+ return(0)+ }+ else #if-else語句+ {+ mat<-matrix(0,nrow=dim(x)[1],ncol=dim(y)[2]) #首先要定義一個矩陣作為結果矩陣+ for(i in c(1:m))+ for(j in c(1:n))+ mat[i,j]<-sum(x[i,]*y[,j]) + return(mat)+ }+ }> f(mat1,mat2) #調用自定義矩陣計算函數 [,1] [,2] [,3] [,4] [,5] [,6][1,] 70 158 246 334 422 510[2,] 80 184 288 392 496 600[3,] 90 210 330 450 570 690> mat1%*%mat2 #驗證 [,1] [,2] [,3] [,4] [,5] [,6][1,] 70 158 246 334 422 510[2,] 80 184 288 392 496 600[3,] 90 210 330 450 570 6903.2 source()文件間調用自定義函數
在R語言裡我們需要藉助source()函數。
示例:自定義avgfunction函數並保存到avgfunction.R文檔裡
#avgfunction代碼avgfunction = function(x){sum(x)/length(x)}source('avgfunction.R') #注意需用引號將文檔名引起來,當avgfunction.R與operate.R在同一路徑時,不需要加路徑
將被調用的函數放置在電腦桌面(C:/Users/ysl/Desktop/),工作目錄(C:/Users/ysl/Documents)
> source('avgfunction.R') #因被調用函數與當前工作空間不一致,提示錯誤#Error in file(filename, "r", encoding = encoding) : 無法打開鏈結#此外: Warning message:#In file(filename, "r", encoding = encoding) :# 無法打開文件'avgfunction.R': No such file or directory
#重新調整在source()添加完整的文件路徑,即可成功調用> source('C:/Users/ysl/Desktop/avgfunction.R')> avgfunction(c(1:20))[1] 10.5
【推薦書籍】