R語言之控制流的使用方法
來自專欄 R語言中文社區10 人贊了文章
作者:劉順祥
公眾號:數據分析1480 (微信ID:lsxxx2011)配套教程:手把手教你做文本挖掘 https://edu.hellobi.com/course/181
般在數據處理或建模過程中會使用到R語言中的控制流,控制流主要有以下三類,即
1)if或switch分支語句
2)for循環
3)while循環
下面就說說這幾種控制流,並講解我工作中的用法。
一、if或switch分支語句
首先看一下if分支語句,一般有雙分支和多分支。關於這兩種分支我們看下圖:
對於二分支,我個人更喜歡使用ifelse()函數,該函數是R語言內置的函數,運行速度是非常快的。下面舉個例子來說明一下:
```{r}
x <- rnorm(100000)
y <- numeric()
system.time(
for(i in 1:length(x)){
if(x[i]<0.5) y[i] = 0
else y[i] = 1
}
)
system.time(y <- ifelse(x<0.5, 0, 1))
```
同樣的目的,但兩者的差距是非常大的。
如果在實際業務中,二分支不能夠解決問題的話,這時就不得不考慮多分支的if語句了,下面舉個應用的場景:
```{r}
#隨機生成性別向量
gender <- sample(c(F,M,Unknow), size = 100000, replace = TRUE)
#現在需要解決的一個問題是,重編碼,即F改為Female,M改為Male,其他不變,一般會考慮使用if的多分支語句解決該問題
gender2 <- character()
system.time(
for(i in 1:length(gender)){
if(gender[i]==F) gender2[i] = Female
else if(gender[i]==M) gender2[i] = Male
else gender2[i] = Unknow
}
)
```
很明顯,對於10W行的數據,這樣的多分支仍然顯得非常慢,這個時候我建議使用switch分支語句,該語句的語法如下:
其實就是對號入座,需要哪條分支,就返回哪條分支的結果,但case只能是一個值,所以還需要配合sapply函數一起使用。
```{r}
#將字元變數設為有序因子
gender3 <- factor(gender, levels = c(F,M,Unknow))
#自定義switch函數返回值
s <- function(case) switch(case,Female,Male,Unknow)
system.time(gender4 <- sapply(as.numeric(gender3),s))
```
這樣的效率還是非常高的,一般多水平的離散變數重編碼(一一對應時)問題建議使用switch分支語句,當然你還可以使用within語句實現該功能,如:
```{r}
system.time(
within(data.frame(gender),{
gender5 <-
gender5[gender==F] <- Female
gender5[gender==M] <- Male
gender5[gender==Unknow] <- Unknow
})
)
```
雖然使用within()函數實現重編碼有一點點複雜,但計算效率還是非常高的!
二、for循環
其實在講if分支語句時,我們就用到了for循環,for循環實質上是對某個對象進行遍歷。一般for循環會配合if語句進行遍歷的條件判斷,下面通過一個實例來看看for循環的應用:
方法一:
```{r}
score <- round(runif(100000, min = 40, max = 92))
#計數器
i <- 1
score2 <-
system.time(
for (score in score){
if (score<60) score2[i] <- 不及格
else if (score>=60 & score<80) score2[i] <- 合格
else score2[i] <- 優秀
i <- i + 1
}
)
```
該方法是不知道該循環多少次時,可以使用這種for語句直接遍歷向量中的每一個值。
方法二:
```{r}
score <- round(runif(100000, min = 40, max = 92))
score3 <-
system.time(
for (i in 1:length(score)){
if (score[i]<60) score3[i] <- 不及格
else if (score[i]>=60 & score[i]<80) score3[i] <- 合格
else score3[i] <- 優秀
}
)
```
在知道循環多少次的前提下可使用這樣的for語句。上面這個例子不是一對一的重編碼問題,建議使用within()內置函數解決編碼,可以大大提高計算速度。
```{r}
score <- round(runif(100000, min = 40, max = 92))
system.time(
score <- within(data.frame(score),{
score4 <-
score4[score<60] <- 不及格
score4[score>=60 & score<80] <- 合格
score4[score>=80] <- 優秀
})
)
```
如果不是這樣的重編碼問題,可能就需要硬著頭皮使用for循環和if判斷條件了,這種顯式for循環會拉低R的計算效率。當然,還有一種可彌補的方法就是使用sapply()函數。
三、while循環
while循環語法:
i <- 1
while(condition){
statements
i = i + 1
}
這裡必須強調的是,while循環語句中必須給一個計數器i,否則無法進行一輪又一輪的循環迭代操作。這裡舉一個簡單的計算1~1000的和:
```{r}
s <- 0
i <- 1
while(i<=1000){
s <- s + i
i <- i + 1
}
s
```
其實,for循環基本可以替代while循環語句,在實際的工作中,我比較喜歡使用for循環,因為for循環可以實現「已知循環次數」和「未知循環次數」的功能,而且for循環也更加直觀。
參考資料:
《統計建模與R軟體》
《R語言與網站分析》
推薦閱讀:
※數學倒底有什麼用?
※死做10000道數學題,不如活讀這20本趣味數學圖書
※管理類聯考高分數學(管綜177分)超詳細複習時間規劃及筆記分享(附學習小秘訣)
※中國數學界掃地僧:當過服務生,蟄伏三十年拿遍榮譽