-
Notifications
You must be signed in to change notification settings - Fork 10
/
ch8.Rmd
302 lines (223 loc) · 6 KB
/
ch8.Rmd
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
---
title: "迴圈與流程控制"
author: "郭耀仁"
date: "`r Sys.Date()`"
output: slidy_presentation
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, results = 'hide', warning = FALSE)
```
## 迴圈
- 善用迴圈讓你能夠寫出簡短的程式碼
- R 語言可以使用常見的兩種迴圈
- for 迴圈
- while 迴圈
## 迴圈(2)
- 有一個內建的向量 `month.name`
- 我想要把它所有的內容一一輸出在命令列
- 土法煉鋼沒什麼不好:
```{r}
month.name[1]
month.name[2]
month.name[3]
month.name[4]
month.name[5]
month.name[6]
month.name[7]
month.name[8]
month.name[9]
month.name[10]
month.name[11]
month.name[12]
```
## 迴圈(3)
- 今天運氣好,`month.name` 只有 12 個元素
- 萬一裡面的元素很多怎麼辦?
- 用迴圈吧!
- `for` 迴圈長這個樣子:
```{r}
# for 迴圈
for (i in month.name) {
print(i)
}
```
## 迴圈(4)
- 或者我們讓 i 代表索引值
```{r}
# for 迴圈
for (i in 1:length(month.name)) {
print(month.name[i])
}
```
## 迴圈(5)
- 小小高斯:
- 計算 `1:100` 這個向量中的元素總和
## 迴圈(6)
- 計算 `1:100` 這個向量中的元素個數
## 隨堂練習
- 計算 `1:100` 這個向量中元素的平均數
## 隨堂練習(2)
- 將這段繪圖的程式碼用迴圈改寫:
```
par(mfrow = c(2, 2))
boxplot(iris$Sepal.Length ~ iris$Species, main = "Sepal length by species")
boxplot(iris$Sepal.Width ~ iris$Species, main = "Sepal width by species")
boxplot(iris$Petal.Length ~ iris$Species, main = "Petal length by species")
boxplot(iris$Petal.Width ~ iris$Species, main = "Petal width by species")
```
## 迴圈(6)
- 巢狀迴圈(nested loop)是指迴圈包含另一個迴圈
```{r results='markup'}
outer_vector = c(1, 2, 3)
inner_vector = c(4, 5, 6)
for (outer_i in outer_vector) {
for (inner_i in inner_vector) {
print(outer_i * inner_i)
}
}
```
## 隨堂練習(3)
- 運用巢狀迴圈做出一個九九乘法表的矩陣
```{r echo=FALSE, results='markup'}
result_mat <- matrix(nrow = 9, ncol = 9)
for (i in 1:9) {
for (j in 1:9) {
result_mat[i, j] <- i * j
}
}
result_mat
```
## 隨堂練習(4)
- 裝飾一下這個九九乘法表
```{r echo=FALSE, results='markup'}
result_mat <- matrix(nrow = 9, ncol = 9)
for (i in 1:9) {
for (j in 1:9) {
result_mat[i, j] <- paste(i, "X", j, "=", i * j)
}
}
result_mat
```
## 迴圈(8)
- `while` 迴圈會先檢查條件才執行程式碼
```{r}
i <- 1
while (i <= length(month.name)) {
print(month.name[i])
i <- i + 1
}
```
## `for` 與 `while` 的使用時機
- 所有的 `for` 都可以用 `while` 改寫
- 但是反過來並非如此
- 不知道迭代次數的時候用 `while`
## `for` 與 `while` 的使用時機(2)
- 投擲一個公正的銅板,必須出現三次正面才可以停止
- 請問總共要投幾次?
```{r}
coin_flips <- c()
coin <- c(TRUE, FALSE) # TRUE 代表正面,FALSE 代表反面
i <- 1
while (sum(coin_flips) < 3){
coin_flips[i] <- sample(coin, size = 1)
i <- i + 1
}
coin_flips # 投擲紀錄
length(coin_flips) # 總共投了幾次
```
## 流程控制
- 一如其他的程式語言,R 語言也習慣使用 `if-else` 的語法來進行流程控制:
```
if (條件一) {
# 程式一
} else if (條件二) {
# 程式二
} else {
# 程式三
}
```
## 流程控制(2)
- 兩個分支用 `if-else` 的語法來進行流程控制:
```{r}
weather <- sample(c("晴天", "下雨", "陰天"), size = 1)
if (weather == "晴天"){
print(paste("天氣是:", weather, ",去戶外跑步", sep = ""))
} else {
print(paste("天氣是:", weather, ",去健身房", sep = ""))
}
```
## 隨堂練習(5)
- 多個分支要採用 `if-else if-else` 的語法來進行流程控制:
- 晴天或多雲印"去戶外跑步",毛毛雨印"去健身房",否則印"當沙發馬鈴薯"
```{r}
weather = c("晴天", "多雲", "毛毛雨", "狂風", "暴雨", "下雪", "打雷閃電")
```
## 迴圈與流程控制
- 在迴圈中加入 `break` 或 `next` 讓你的程式更有彈性
```{r}
for (i in month.name) {
if (i == "September") {
break
}
print(i)
}
for (i in month.name) {
if (i == "September") {
next
}
print(i)
}
```
## 隨堂練習(6)
- 將 1 到 100 印出,但是:
- 碰到 3 的倍數輸出 "三的倍數"
- 碰到 5 的倍數輸出 "五的倍數"
- 碰到 3 與 5 的公倍數時輸出 "十五的倍數"
## 隨堂練習(7)
- 將 87 因數分解,輸出所有的正因數
## 隨堂練習(8)
- 輸出以 0, 1 起始的前 20 個 [Fibonacci 數列](https://en.wikipedia.org/wiki/Fibonacci_number)
## 迭代觀念
- 進階的 R 語言使用者應該具備這樣的概念:
- 向量計算 > `apply()` 函數家族 > `for` `while` 迴圈
- 舉例:計算 50 萬個人的 [BMI](https://zh.wikipedia.org/wiki/%E8%BA%AB%E9%AB%98%E9%AB%94%E9%87%8D%E6%8C%87%E6%95%B8)
```{r}
heights <- runif(500000) * 50 + 140
weights <- runif(500000) * 50 + 40
h_w_df <- data.frame(heights, weights)
```
## 迭代觀念(2)
- `system.time()` 函數可以觀察程式執行時間
- 首先登場的是向量計算:
```{r}
heights <- runif(500000) * 50 + 140
weights <- runif(500000) * 50 + 40
h_w_df <- data.frame(heights, weights)
system.time(
h_w_df$bmi <- h_w_df$weights / (h_w_df$heights / 100)^2
)
```
## 迭代觀念(3)
- 接著登場的是 `apply()` 函數家族的 `mapply()` 函數:
```{r}
bmi_calculator <- function(height, weight){
return(weight / (height / 100)^2)
}
system.time(
h_w_df$bmi <- mapply(FUN = bmi_calculator, h_w_df$heights, h_w_df$weights)
)
```
## 迭代觀念(4)
- 最後登場的是 `for` 迴圈:
```{r}
bmi <- rep(NA, times = nrow(h_w_df))
system.time(
for (i in 1:nrow(h_w_df)){
bmi[i] <- bmi_calculator(h_w_df[i, "heights"], h_w_df[i, "weights"])
}
)
```
## 期中作業
我們把公正的**銅板**改成公正的**骰子**,必須出現三次六點才可以停止
- 請問總共要投幾次?
- 投擲的歷史紀錄為何?