R擁有一般現(xiàn)代編程語言中都有的標(biāo)準(zhǔn)控制結(jié)構(gòu)。在學(xué)習(xí)控制流之前,應(yīng)該理解以下概念:
語句(statement)是一條單獨(dú)的R語句或一組復(fù)合語句(包含在花括號(hào){ } 中的一組R語句,使用分號(hào)分隔);
條件(cond)是一條最終被解析為真(TRUE)或假(FALSE)的表達(dá)式;
表達(dá)式(expr)是一條數(shù)值或字符串的求值語句;
序列(seq)是一個(gè)數(shù)值或字符串序列。
1. 重復(fù)與循環(huán)
1.1 for結(jié)構(gòu)
for循環(huán)重復(fù)地執(zhí)行一個(gè)語句,直到某個(gè)變量的值不再包含在序列seq中為止。
for (var in seq) statement
若要將“Hello”打印10次:
> for (i in 1:10)
+ print("Hello!")
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
1.2 while結(jié)構(gòu)
while循環(huán)重復(fù)地執(zhí)行一個(gè)語句,直到條件不為真為止。
while (cond) statement
同樣,我們再來重復(fù)輸出10次“Hello!”
> i <- 10
> while (i > 0) {
+ print("Hello!");
+ i <- i - 1}
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
[1] "Hello!"
需要注意的是,在處理大數(shù)據(jù)集中的行和列時(shí),R中的循環(huán)可能比較低效費(fèi)時(shí)。只要可能,最好聯(lián)用R中的內(nèi)建數(shù)值/字符處理函數(shù)和apply族函數(shù)。這與其他的大量使用循環(huán)的語言是有區(qū)別的。
2. 條件執(zhí)行
在條件執(zhí)行結(jié)構(gòu)中, 一條或一組語句僅在滿足一個(gè)指定條件時(shí)執(zhí)行。 條件執(zhí)行結(jié)構(gòu)包括 if-else、ifelse和switch。
2.1 if-else結(jié)構(gòu)
控制結(jié)構(gòu)if-else在某個(gè)給定條件為真時(shí)執(zhí)行語句。也可以同時(shí)在條件為假時(shí)執(zhí)行另外的語句:
if (cond) statement
if (cond) statement1 else statement2
> a=5
> b=6
> if (a < b) {a <- -1
+ } else if (a == b) {a <- 0
+ } else {a <- 1}
> print(a)
[1] -1
2.2 ifelse結(jié)構(gòu)
ifelse結(jié)構(gòu)是if-else結(jié)構(gòu)比較緊湊的向量化版本,其語法為:
ifelse(cond,statement1,statement2)
若cond為TRUE,則執(zhí)行第一個(gè)語句;若cond為FALSE,則執(zhí)行第二個(gè)語句。
> x <- factor(sample(letters[1:5], 10, replace = TRUE))
> x
[1] a a c d a b d b d d
> ifelse(x %in% c("a", "b", "c"), x, factor(NA))
[1] 1 1 3 NA 1 2 NA 2 NA NA
2.3 switch結(jié)構(gòu)
switch(expr,...)
switch根據(jù)一個(gè)表達(dá)式的值選擇語句執(zhí)行。其中的...表示與expr的各種可能輸出值綁定的語句。
> feelings <- c("sad","afraid")
> for (i in feelings)
+ print(switch(i,
+ happy = "I am happy today",
+ afraid = "There is nothing to fear",
+ sad = "cheer up",
+ angry = "calm down now"))
[1] "cheer up"
[1] "There is nothing to fear"
#當(dāng)表達(dá)式(exp)匹配后續(xù)的參數(shù)名(即變量名)時(shí),返回參數(shù)的值
> t = "r"
> switch(t,r='re',g='gr',b='bl',"error")
[1] "re"
#如果不匹配任何參數(shù)名,switch函數(shù)不返回任何值,可以添加一個(gè)匿名的參數(shù),
#當(dāng)表達(dá)式(exp)匹配不上任意一個(gè)命名參數(shù)時(shí),switch函數(shù)將返回匿名參數(shù)的值:
> t = "xs"
> switch(t,r='re',g='gr',b='bl',"error")
[1] "error"
3. 用戶自編函數(shù)
R的最大優(yōu)點(diǎn)之一就是用戶可以自行添加函數(shù)。
myfunc <- function(arg1,arg2,....)
{
statements
return(object)
}
#example1
> avg <- function(a,b){
+ c <- mean(c(a,b));
+ return(c)
+ }
> avg(3,4)
[1] 3.5
#example2
#練習(xí)一個(gè)每次學(xué)循環(huán)都要做的矩陣的乘法
matrixf <- function(a,b){
row1 <- dim(a)[1]
col1 <- dim(a)[2]
row2 <- dim(b)[1]
col2 <- dim(b)[2]
if (col1 == row2) {
result <- matrix(0,nrow = row1,ncol = col2)
for (i in 1:row1)
for (j in 1:col2)
result[i,j] <- sum(a[i,]*b[,j])
return(result)
}
else {
print("error")
return(0)
}
}
> a <- matrix(10,2)
> a
[,1]
[1,] 10
[2,] 10
> a <- (c(1:4,2))
> a
[1] 1 2 3 4 2
> a <- matrix(1:4,2)
> a
[,1] [,2]
[1,] 1 3
[2,] 2 4
> b <- matrix(1:4,2)
> b
[,1] [,2]
[1,] 1 3
[2,] 2 4
> matrixf(a,b)
[,1] [,2]
[1,] 7 15
[2,] 10 22
4. 整合與重構(gòu)
R中提供了許多用來整合(aggregate)和重塑(reshape)數(shù)據(jù)的強(qiáng)大方法。
4.1 轉(zhuǎn)置
轉(zhuǎn)置即反轉(zhuǎn)列和行,適用于矩陣和數(shù)據(jù)框,使用函數(shù)t()即可完成。
> head_cars <- head(mtcars,6)
> head_cars
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21 6 160 110 3.9 2.6 16 0 1 4 4
Mazda RX4 Wag 21 6 160 110 3.9 2.9 17 0 1 4 4
Datsun 710 23 4 108 93 3.9 2.3 19 1 1 4 1
Hornet 4 Drive 21 6 258 110 3.1 3.2 19 1 0 3 1
Hornet Sportabout 19 8 360 175 3.1 3.4 17 0 0 3 2
Valiant 18 6 225 105 2.8 3.5 20 1 0 3 1
> t(head_cars)
Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive Hornet Sportabout Valiant
mpg 21.0 21.0 22.8 21.4 18.7 18.1
cyl 6.0 6.0 4.0 6.0 8.0 6.0
disp 160.0 160.0 108.0 258.0 360.0 225.0
hp 110.0 110.0 93.0 110.0 175.0 105.0
drat 3.9 3.9 3.9 3.1 3.1 2.8
wt 2.6 2.9 2.3 3.2 3.4 3.5
qsec 16.5 17.0 18.6 19.4 17.0 20.2
vs 0.0 0.0 1.0 1.0 0.0 1.0
am 1.0 1.0 1.0 0.0 0.0 0.0
gear 4.0 4.0 4.0 3.0 3.0 3.0
carb 4.0 4.0 1.0 1.0 2.0 1.0
4.2 整合數(shù)據(jù)
在R中使用一個(gè)或多個(gè)by變量和一個(gè)預(yù)先定義好的函數(shù)來折疊(collapse)數(shù)據(jù)是比較容易的:
aggregate(x,by,FUN)
x是待折疊的數(shù)據(jù)對象
by是一個(gè)變量名組成的列表,這些變量將被去掉以形成新的觀測
FUN則是用來計(jì)算描述性統(tǒng)計(jì)量的標(biāo)量函數(shù),它將被用來計(jì)算新觀測中的值。
> detach(mtcars)
> options(digits = 3)
> attach(mtcars)
> aggdate <- aggregate(mtcars,by = list(cyl,gear),FUN=mean,na.rm = TRUE)
> print(aggdate)
Group.1 Group.2 mpg cyl disp hp drat wt qsec vs am gear carb
1 4 3 21.5 4 120 97 3.70 2.46 20.0 1.0 0.00 3 1.00
2 6 3 19.8 6 242 108 2.92 3.34 19.8 1.0 0.00 3 1.00
3 8 3 15.1 8 358 194 3.12 4.10 17.1 0.0 0.00 3 3.08
4 4 4 26.9 4 103 76 4.11 2.38 19.6 1.0 0.75 4 1.50
5 6 4 19.8 6 164 116 3.91 3.09 17.7 0.5 0.50 4 4.00
6 4 5 28.2 4 108 102 4.10 1.83 16.8 0.5 1.00 5 2.00
7 6 5 19.7 6 145 175 3.62 2.77 15.5 0.0 1.00 5 6.00
8 8 5 15.4 8 326 300 3.88 3.37 14.6 0.0 1.00 5 6.00
> detach(mtcars)
簡單解釋一下數(shù)據(jù),Group1即cyl,Group2即gear,則第一行的數(shù)據(jù)表示cyl為4、gear為3的所有車的其它變量disp,hp等的平均值。
這是非??膳碌墓δ埽梢宰杂傻恼郫B,提取數(shù)據(jù)子集。
需要注意的一點(diǎn)是,在使用aggregate()函數(shù)的時(shí)候,by中的變量必須在一個(gè)列表中(即使只有一個(gè)變量)。
4.3 reshape2
reshape2包是一套重構(gòu)和整合數(shù)據(jù)集的絕妙的萬能工具。我們將在下節(jié)專題介紹。