本週上課將介紹R
的控制流程,也就是條件判斷與迴圈,讓電腦可以按照給定的邏輯,反覆執行指令,一直到滿足條件為止,這對於運算以及擷取資料非常有幫助。例如我們隨機找到10位民眾,想依據民眾的年齡是否在18歲以上,判斷是否應該訪問他們,並且顯示成為一個資料框,可寫語法運算如下:
age<-c(34, 12, 19, 21, 22, 30, 16, 18, 17, 39)
f<-function(x){
interview<-ifelse(x>=18, "Yes", "No")
return(data.frame(Age=x, Interview=interview, row.names=NULL))
}
f(age)
## Age Interview
## 1 34 Yes
## 2 12 No
## 3 19 Yes
## 4 21 Yes
## 5 22 Yes
## 6 30 Yes
## 7 16 No
## 8 18 Yes
## 9 17 No
## 10 39 Yes
在介紹R
的控制流程之前,先介紹資料的子集合。
從一筆資料取出部分資料,稱謂資料的子集合動作(Subsetting)。子集合可幫助 後續的資料分析,因為很多資料裡面只有一部分是我們所需要的。
在DSC2014Tutorial的套件中,輸入slides(‘Basic’),就可以學習到許多資料子集合的技巧。在此簡單敘述。
向量的子集合方式可以分成用索引以及which()
函數方式:
向量的數學表示方式為 \(x_{i}\),其中下標i表示向量的第幾個元素,我們稱之為索引。從向量取出部分元素的方法就是以括號的方式,例如:
state.name[1]
## [1] "Alabama"
state.abb[1:4]
## [1] "AL" "AK" "AZ" "AR"
sleep$extra[nrow(sleep)]
## [1] 3.4
which()
適用於條件篩選向量內的元素,例如我們想找出哪些美國的州名是以B跟C開頭,可寫語法如下:
state.abb[1:10]
## [1] "AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA"
state.abb.abb<-substr(state.abb, 1,1)
state.abb[which(state.abb.abb=="B")]
## character(0)
state.abb[which(state.abb.abb=="C")]
## [1] "CA" "CO" "CT"
這裡使用到substr(A, i, j)
這個指令,A是字串向量,i是開始擷取向量內的文字的順位,j是結束擷取的位置,我們擷取每一個州名稱的第一個字母,然後存成用state.abb.abb這個向量,再用which()
函數,對原本的state.abb向量配對。
請嘗試找出有幾個州的面積大於10萬平方英哩
請先建立一個列表:
ListA<-list(height=90, width=120, string=state.abb[1:2], data=state.area)
class(ListA)
## [1] "list"
從列表中以索引方式取出資料,格式可以是列表或者是數值、字串
ListA[c(1,2)]
## $height
## [1] 90
##
## $width
## [1] 120
ListA[[3]]
## [1] "AL" "AK"
ListA[4]
## $data
## [1] 51609 589757 113909 53104 158693 104247 5009 2057 58560 58876
## [11] 6450 83557 56400 36291 56290 82264 40395 48523 33215 10577
## [21] 8257 58216 84068 47716 69686 147138 77227 110540 9304 7836
## [31] 121666 49576 52586 70665 41222 69919 96981 45333 1214 31055
## [41] 77047 42244 267339 84916 9609 40815 68192 24181 56154 97914
或者直接使用列表中的名稱:
ListA["height"]
## $height
## [1] 90
ListA[["width"]]
## [1] 120
使用which()
篩選列表的資料之前,需要先轉換列表為資料框,然後把因素轉換為數值,而R
會按照因素的層級排序,從1開始:
dfA<-data.frame(value=unlist(ListA))
dfA$value
## [1] 90 120 AL AK 51609 589757 113909 53104 158693 104247
## [11] 5009 2057 58560 58876 6450 83557 56400 36291 56290 82264
## [21] 40395 48523 33215 10577 8257 58216 84068 47716 69686 147138
## [31] 77227 110540 9304 7836 121666 49576 52586 70665 41222 69919
## [41] 96981 45333 1214 31055 77047 42244 267339 84916 9609 40815
## [51] 68192 24181 56154 97914
## 54 Levels: 104247 10577 110540 113909 120 1214 121666 147138 ... AL
dfA$data<-as.numeric(dfA$value)
dfA$data[1:6]
## [1] 48 5 54 53 25 34
dfA[which(dfA$data<10),]
## value data
## width 120 5
## data3 113909 4
## data5 158693 9
## data6 104247 1
## data20 10577 2
## data26 147138 8
## data28 110540 3
## data31 121666 7
## data39 1214 6
以上是一維的資料,接下來介紹二維的資料子集合。
\(x_{11},\ldots, x_{r1}\)來自同樣的行(column),而\(x_{11},\ldots, x_{1c}\)來自同樣的列,所以前者可以用\(x_{,1}\)表示,後者\(x_{1,}\)表示。
假設有一個\(3\times 3\)的矩陣,我們用括號來取出其中的一個或是多個數值,或者加以替換:
m1<-matrix(c(1:9), 3, 3)
m1
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
print(m1[2,2]) #1
## [1] 5
print(m1[c(1:2)]) #2
## [1] 1 2
print(m1[c(1,2),c(1,2)]) #3
## [,1] [,2]
## [1,] 1 4
## [2,] 2 5
print(m1[c(1,3),c(1,3)]) #4
## [,1] [,2]
## [1,] 1 7
## [2,] 3 9
print(m1[,1]) #5
## [1] 1 2 3
m1[3,3]<-"Hello" #6
m1
## [,1] [,2] [,3]
## [1,] "1" "4" "7"
## [2,] "2" "5" "8"
## [3,] "3" "6" "Hello"
以上面語法中第3題的[c(1,2),c(1,2)]為例,矩陣對應索引的方式為(1,1),(2,1),(1,2),(2,2),因此得到
\[\begin{bmatrix} 1 & 4 \\ 2 & 5 \end{bmatrix}\]對於矩陣或是陣列,R
可以傳回每一個符合條件的行與列的對應資料,例如:
T <- array(1:20, dim=c(4,5))
which(T >= 15, arr.ind = T)
## row col
## [1,] 3 4
## [2,] 4 4
## [3,] 1 5
## [4,] 2 5
## [5,] 3 5
## [6,] 4 5
T[which(T[,5]>=15), ]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 5 9 13 17
## [2,] 2 6 10 14 18
## [3,] 3 7 11 15 19
## [4,] 4 8 12 16 20
資料框與矩陣類似,都有兩個象限,所以子集合的方法相近。
索引對象可以是資料框的行或是列的編號,也可以是欄位名稱,注意逗號前面是列,後面是行:
data(sleep)
names(sleep)
## [1] "extra" "group" "ID"
sleep[1:3, ]
## extra group ID
## 1 0.7 1 1
## 2 -1.6 1 2
## 3 -0.2 1 3
sleep[, "extra"]
## [1] 0.7 -1.6 -0.2 -1.2 -0.1 3.4 3.7 0.8 0.0 2.0 1.9 0.8 1.1 0.1
## [15] -0.1 4.4 5.5 1.6 4.6 3.4
當資料有一欄編號,可以用\(\%\textrm{in}\%\)方式擷取特定列的資料:
head(sleep)
## extra group ID
## 1 0.7 1 1
## 2 -1.6 1 2
## 3 -0.2 1 3
## 4 -1.2 1 4
## 5 -0.1 1 5
## 6 3.4 1 6
sleep[sleep$ID %in% c(1,2,3), ] #select by ID
## extra group ID
## 1 0.7 1 1
## 2 -1.6 1 2
## 3 -0.2 1 3
## 11 1.9 2 1
## 12 0.8 2 2
## 13 1.1 2 3
sleep[sleep$ID %in% c(1,2,3) & sleep$group %in% c(1), ] # two conditions
## extra group ID
## 1 0.7 1 1
## 2 -1.6 1 2
## 3 -0.2 1 3
\(\%\textrm{in}\%\)的意義是「屬於」,例如:
A<-c(0:5); B<-c(1:20)
A%in%B
## [1] FALSE TRUE TRUE TRUE TRUE TRUE
應用到資料框的子集合,則是列的序號對應為真則留下,為偽則不留下。
which()
可容納超過一個以上的條件,而且可以用「且」或是「或」連結條件與條件。針對資料框,可以比對出符合每一個條件的「列」,並且傳回向量。研究者可以由此取出對應的列。
cond <- which(sleep$extra>0.5 & sleep$group==1)
sleep[cond, ]
## extra group ID
## 1 0.7 1 1
## 6 3.4 1 6
## 7 3.7 1 7
## 8 0.8 1 8
## 10 2.0 1 10
比較\(\%\textrm{in}\%\)以及which()
,可得到相同結果:
mtcars[mtcars$cyl %in% c(4,8), ]
## mpg cyl disp hp drat wt qsec vs am gear carb
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
mtcars[which(mtcars$cyl==4 | mtcars$cyl==8) , ]
## mpg cyl disp hp drat wt qsec vs am gear carb
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
ifelse()
適用在「非A即B」的邏輯,也就是若A為真則進行某一動作,若A不為真則不進行。
例如面訪員到某一個家戶訪問,裡面有四人,訪員需要戶中抽樣,但是前提是只訪問18歲以上成年人,語法可以這樣寫:
x=c(20, 50, 16, 18)
interview<-ifelse(x>=18, "Yes", "No")
print(interview)
## [1] "Yes" "Yes" "No" "Yes"
ifelse()
可以判斷一個向量的真偽,其功能類似先前提到的變數轉換:
vote <- rep(NA, 3)
vote[x>=18]<-"Yes"
vote[x<18]<-"No"
vote
## [1] "Yes" "Yes" "No" "Yes"
ifelse()
也可以轉換字串為字串或者是數字,也可以把日期轉換為字串或是數字。
S<-c("2018-01-01", "2018-02-01", "2018-03-01", "2018-04-01")
S <- as.Date(S, format='%Y-%m-%d')
day<-as.Date("2018/02/28", format='%Y/%m/%d')
new.S<-ifelse(difftime(day, S)>=0, "Earlier", "Later")
new.S
## [1] "Earlier" "Earlier" "Later" "Later"
當條件成立時的執行的動作可以是函數,例如在日光節約時間結束之後,下午茶時間延後一個小時。假設日光節約時間在11月5日結束,三個日期的下午茶時間可計算如下:
ds<-as.POSIXct("2018-11-05 00:00:00", format = "%Y-%m-%d %H:%M:%S", tz="Asia/Taipei")
teatime<-as.POSIXct(c("2018-07-01 13:50:00", "2018-12-01 14:10:00", "2019-02-02 14:15:00"),
format = "%Y-%m-%d %H:%M:%S", tz="Asia/Taipei")
hrs <- function(u) {
x <- u * 3600
return(x)
}
ifelse(difftime(teatime, ds)>=0, paste(teatime+hrs(1)), paste(teatime))
## [1] "2018-07-01 13:50:00" "2018-12-01 15:10:00" "2019-02-02 15:15:00"
請注意時間的格式,以及設定時區的函數as.POSIXct()
。另外,paste()
函數可貼上計算結果。
if-else
可以幫助我們建立一個條件式的函數,當函數內的向量滿足某個條件,便會進行某一個動作。
temperature<-30
if (temperature>28){
cat ("Turn on air condition")
}else {
cat ("Turn off air condition")
}
## Turn on air condition
也可以進行運算
speed<-50
if (speed>=70){
speed
}else {
speed*1.6
}
## [1] 80
如果進行迴圈的條件是向量中的某一個或是所有元素符合某項條件,其他元素也會隨之進行我們希望的動作。例如警察測量許多輛車的速度,如果是任何一輛車超過時速110就顯示最高速的那一輛車速,反之顯示最慢的那一輛車速:
speed<-c(77, 90, 100, 120, 155)
if (any(speed>=110)){
y=max(speed)
} else{
y=min(speed)
}
y
## [1] 155
此處使用any()
這個函數,表示當物件或是多個物件滿足某一條件則回傳TRUE。例如:
A<-c(-1, 1.5); B<-c(2); C<-c('OK')
any (A>0)
## [1] TRUE
any (is.numeric(A) & is.numeric(B) & is.numeric(C))
## [1] FALSE
any (is.numeric(A) | is.numeric(B) | is.numeric(C))
## [1] TRUE
請練習如果「所有」車輛超過時速110,警察就會開罰單,顯示最快的車速,否則都不會開單。車速是130, 115, 120。
if-else if-else
可以幫助我們建立一個條件式的函數,當函數內的向量滿足第一個條件,便會進行第一個動作, 滿足第二個條件,便會進行第二個動作,一直到結束。例如電影的長度如果長過180分鐘則是太長,165分鐘是長,不到165分鐘是短。
movie<-170
if(movie>=180){
cat('Very long')
}else if(movie>=165){
cat('Long')
}else{
cat('Short')
}
## Long
在寫if-else時,請注意}
應該與else
或是else if
連在一起。
假設在入住前3個月(90天)訂飯店為原價的85折,2個月(60天)訂飯店為原價的9折,入住前1周到兩個月是原價,入住日期為1周內則是原價加上兩成。如果入住日期為今年5月20日,原價是3000元,請練習今天的日期以及隔兩週後的今天訂房的話,分別需要多少錢?
for
迴圈的功能是系統根據起始的條件,反覆進行同一動作。
例如重複顯示一個句子\(n\)次:
for (U in 1:5){
cat("All work and no play","\n")
}
## All work and no play
## All work and no play
## All work and no play
## All work and no play
## All work and no play
在這個迴圈中,U是一個變數,雖然U沒有出現在後面的語法,但是系統會執行該語法所設定的次數。
也可以貼上次數:
for (i in 1:5){
cat("All work and no play", paste(i), "times \n")
}
## All work and no play 1 times
## All work and no play 2 times
## All work and no play 3 times
## All work and no play 4 times
## All work and no play 5 times
在這個迴圈中,我們用paste()
這個函數貼上\(i\)這個變數的值。
又例如從1加到10:
sum<-0
for (i in 1:10){
sum = sum + i
}
print(sum)
## [1] 55
擲三顆公正的六面骰子1000次並且加總點數,將每一次得到的總和畫成長條圖:
set.seed(02138)
dice <- seq(1:6)
x <- c()
for (i in 1:1000){
x[i]<-sum(sample(dice, 1), sample(dice, 1), sample(dice, 1))
}
# graphic
df<-data.frame(Dice=x)
library(ggplot2)
g <- ggplot(aes(Dice), data=df) +
geom_histogram(binwidth = 0.8, fill='lightgreen', aes(y=..density..), position="identity")
g
可以看出點數的總和近似常態分佈,集中在10點附近。
這個迴圈運用到「索引」的概念,紀錄每一次抽樣並且加總的結果,但是不需要顯示在螢幕上,而是成為一個向量,作為後續統計的資料。
例如撲克牌點數為1到13點,抽出三張牌,如果前兩張的點數總和小於17,而且其中一張牌小於10,那麼就抽第三張,然後顯示三張的總和;如果不符合前一個條件,那麼就顯示兩張的總和。當我們給定隨機亂數的數字,我們設定的條件式函數根據隨機亂數得到的結果輸出。
set.seed(02138)
card<-function(x) {
set.seed(x)
for (i in 1:3)
x[i]<-sample(1:13, 1)
if (x[1]+x[2]<17 & x[1]<10 | x[2]<10 ){
print(x[1:3])
cat(sum(x[1:3]),"is sum of three cards \n")
}else {
print(x[1:2])
cat(sum(x[1:2]), "is sum of the first 2 cards \n")
}
}
card(100); card(5003); card(02138)
## [1] 5 4 8
## 17 is sum of three cards
## [1] 7 12
## 19 is sum of the first 2 cards
## [1] 7 8 5
## 20 is sum of three cards
上述的程式可以產生一個自訂函數card()
,該函數的參數x是任意整數,將產生隨機亂數。這個迴圈同樣運用到「索引」的概念。
某飯店單人房原價是3000元。假設在入住前3個月(90天)訂房為原價的85折,不到3個月但是超過2個月(60天)訂房為原價的9折,不到2個月但是超過1個月(30天)是原價,入住前1個月內則是原價加上兩成。如果入住日期為今年的12月31日、4月20日、5月20日、6月1日、6月30日以及隔一週的今天,請練習如果今天的日期訂房的話,分別需要多少錢?
如果把最早的日期放在第一個,迴圈會立刻停止
checkin<-c(checkin, today+7)
hotel(checkin)
## [1] "2018-12-31"
## -80 days: 3600
## [1] "2018-04-20"
## -335 days: 3600
## [1] "2018-05-20"
## -305 days: 3600
## [1] "2018-06-01"
## -293 days: 3600
## [1] "2018-06-30"
## -264 days: 3600
## [1] "2019-03-28"
## 7 days: 3600
## [1] "2019-03-28"
## 7 days: 3600
如果需要兩個變數才能產生所需要的結果,可以考慮迴圈之中的迴圈,例如我們想知道11到20的乘法表,需要兩個變數相乘:
multiplication <- matrix(nrow=10, ncol=10)
for (i in 1:dim(multiplication)[1]){
for (j in 1:dim(multiplication)[2]){
multiplication[i,j] <- (i+10)*(j+10)
}
}
rownames(multiplication)<-c(11:20)
colnames(multiplication)<-c(11:20)
multiplication
## 11 12 13 14 15 16 17 18 19 20
## 11 121 132 143 154 165 176 187 198 209 220
## 12 132 144 156 168 180 192 204 216 228 240
## 13 143 156 169 182 195 208 221 234 247 260
## 14 154 168 182 196 210 224 238 252 266 280
## 15 165 180 195 210 225 240 255 270 285 300
## 16 176 192 208 224 240 256 272 288 304 320
## 17 187 204 221 238 255 272 289 306 323 340
## 18 198 216 234 252 270 288 306 324 342 360
## 19 209 228 247 266 285 304 323 342 361 380
## 20 220 240 260 280 300 320 340 360 380 400
請嘗試用陣列加上迴圈產生三維的資料,例如我們模擬兩種隨機抽樣方式,第一種方式從5種隨機分佈每次抽出1, 10, 100, 200, 500, 1000個樣本,然後計算其平均值。第二種方式除了從5種隨機分佈每次抽出1, 10, 100, 200, 500, 1000個樣本,然後計算其平均值,還要重複以上步驟10, 100,1000次,分別計算平均值。
set.seed(02138)
sampleresult <- matrix(nrow=6, ncol=5)
R<-c(1, 10, 100, 200, 500, 1000)
L<-list(rnorm(1e+04,0,1), rnorm(1e+05,0,1), rnorm(1e+06,0,1), rnorm(1e+07,0,1), rnorm(1e+08,0,1))
for (i in 1:length(R)){
for (j in 1:5){
sampleresult[i,j] <- mean(sample (L[[j]], size=R[i], replace=T))
}
}
sampleresult
#replication
sampleresult2 <- array(dim=c(6, 5, 3))
S<-c(10,100, 1000)
for (i in 1:length(R)){
for (j in 1:5){
for(s in 1:length(S)){
su<-c();
sampleresult2[i,j,s] <- mean({su[s]=mean(sample (L[[j]], size=R[i], replace=T))})
}
}
}
sampleresult2
for
迴圈可以幫助我們清理資料,例如讀取一筆23個縣市的統計資料:
library(foreign)
stat.dat<-read.csv("CS3171D1A.csv",header=TRUE,sep=";",dec=".",fileEncoding="BIG5")
head(stat.dat)
## X 臺北縣 宜蘭縣 桃園縣 新竹縣 苗栗縣 臺中縣 彰化縣
## 1 老年人口比率(65歲以上) NA NA NA NA NA NA NA
## 2 2000 6.37 10.20 7.46 9.69 10.98 7.16 9.42
## 3 2001 6.44 10.49 7.49 9.91 11.21 7.32 9.73
## 4 2002 6.55 10.82 7.51 10.17 11.57 7.50 10.03
## 5 2003 6.67 11.17 7.56 10.39 11.87 7.68 10.31
## 6 2004 6.86 11.54 7.62 10.58 12.19 7.90 10.65
## 南投縣 雲林縣 嘉義縣 臺南縣 高雄縣 屏東縣 臺東縣 花蓮縣 澎湖縣 基隆市
## 1 NA NA NA NA NA NA NA NA NA NA
## 2 10.60 11.61 12.41 10.75 8.35 10.00 11.27 10.73 14.40 8.81
## 3 10.90 11.99 12.75 11.04 8.52 10.25 11.40 10.83 14.29 9.06
## 4 11.23 12.41 13.14 11.31 8.75 10.54 11.55 11.00 14.42 9.28
## 5 11.56 12.82 13.58 11.56 8.95 10.84 11.76 11.19 14.58 9.47
## 6 11.96 13.26 13.98 11.82 9.16 11.13 12.01 11.41 14.78 9.71
## 新竹市 臺中市 嘉義市 臺南市 臺北市 高雄市
## 1 NA NA NA NA NA NA
## 2 8.46 6.49 8.67 7.69 9.67 7.16
## 3 8.50 6.60 8.85 7.85 9.94 7.41
## 4 8.59 6.79 9.15 8.06 10.25 7.63
## 5 8.69 6.94 9.46 8.24 10.58 7.93
## 6 8.81 7.15 9.70 8.46 10.92 8.24
這筆資料的最左邊一欄有一個變數名稱,但是不是位在第一列,而是在第二列,我們如何正確地讀取每一列的資料?
- 首先創造一個有23個元素的向量 - 對某一個變數進行23次的迴圈 - 第一個元素應該來自於資料的第二列、第二行
old.2000<-rep(NA, 23) #讀取2010年老年人口比率
for (u in 1:23){
old.2000[u]<-stat.dat[2,u+1]
}
old.2000
## [1] 6.37 10.20 7.46 9.69 10.98 7.16 9.42 10.60 11.61 12.41 10.75
## [12] 8.35 10.00 11.27 10.73 14.40 8.81 8.46 6.49 8.67 7.69 9.67
## [23] 7.16
如果要系統在執行到滿足某一個條件時中斷,可以用while
迴圈。例如:
power<-0
while (power <= 12) {
if (2^power<1000){
cat(2^power, "\n")
}else{
cat("Stop")
}
power <- power +1
}
## 1
## 2
## 4
## 8
## 16
## 32
## 64
## 128
## 256
## 512
## StopStopStop
如果用for
迴圈,可以輸出\(2^{0}\)到\(2^{12}\),但是無法像while
中斷迴圈
for (a in -1:11){
a <- a +1
print(2^a)
}
## [1] 1
## [1] 2
## [1] 4
## [1] 8
## [1] 16
## [1] 32
## [1] 64
## [1] 128
## [1] 256
## [1] 512
## [1] 1024
## [1] 2048
## [1] 4096
break
可以在滿足某項條件情況下中斷迴圈,以上面的迴圈為例,假設我們要在超過1000時中斷:
power<-0
while (power <= 12) {
if (2^power<1000){
cat(2^power, "\n")
}else{
cat("Stop")
break
}
power <- power +1
}
## 1
## 2
## 4
## 8
## 16
## 32
## 64
## 128
## 256
## 512
## Stop
也可以應用在訂旅館的例子中,例如超過原價就停止計算房價:
today<-as.Date(Sys.Date(), format='%Y-%m-%d')
hotel <- function(checkin){
n <- length(checkin)
price <- 3000
diff <- difftime(checkin, today)
for (i in 1:n)
if (diff[i]>90){
print(checkin[i])
cat (round(diff[i]/30,1), "months:", price*0.85, "\n")
}else if (diff[i]>=60){
print(checkin[i])
cat (round(diff[i]/30,1), "months:",price*0.9,"\n")
}else if (diff[i]>=30){
print(checkin[i])
cat (round(diff[i]/30,1), "months:",price,"\n")
}else{
print(checkin[i])
cat("Over the budget")
break
#cat (diff[i], "days:",price*1.2, "\n")
}
}
checkin<-as.Date(c("2018-12-31", "2018-04-20","2018-05-20",
"2018-06-01","2018-06-30"), format='%Y-%m-%d')
checkin<-c(checkin, today+7)
hotel(checkin)
## [1] "2018-12-31"
## Over the budget
如果想跳過滿足某個條件的迴圈,執行下一個迴圈,可用next
。例如:
for (i in 1:10){
if (i<= 4){
next
}
#a <- a +1
cat(i, "squared is ", i^2, "\n")
}
## 5 squared is 25
## 6 squared is 36
## 7 squared is 49
## 8 squared is 64
## 9 squared is 81
## 10 squared is 100
請把美國的州名排成一個陣列,然後找出州名長度多於或等於13的州(提示:nchar()傳回字串的長度)
請讀取studentsfull.txt這個檔案,然後取出經濟系與化學系的學生資料。
老師決定把某次考試之中,60分以下開根號乘以10,60分以上維持原來批改分數,請寫一個程式幫老師轉換以下成績:34, 81, 55, 69, 77, 40, 49, 26,分數計算至小數點後第二位四捨五入。
請寫一個函數可以把兩個日期之間的差距轉換成月,並且以今天日期與2020年的7月31日之間的差距為例。
請練習讀取「失業率」,並且把2000年的各縣市的失業率與老年人口比率組成一個資料框。