-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path02b-for-loops-iteration-complete.qmd
More file actions
309 lines (219 loc) · 9.91 KB
/
Copy path02b-for-loops-iteration-complete.qmd
File metadata and controls
309 lines (219 loc) · 9.91 KB
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
303
304
305
306
307
308
309
---
title: "For-Loops for Multiple Outputs"
subtitle: "Complete Solution"
author: "Instructor"
format:
html:
embed-resources: true
toc: true
execute:
warning: false
editor: visual
editor_options:
chunk_output_type: console
---
```{r}
#| label: load-packages
library(tidyverse)
library(gt)
```
# Introduction
This assignment deepens your understanding of for-loops in R. You will learn when for-loops are useful and when alternative approaches are better suited. You will also practice creating multiple outputs like plots or summary tables.
## Learning Objectives
After completing this assignment, you will be able to:
- Decide when a for-loop is necessary and when it is not
- Write for-loops to create multiple separate outputs
- Store plots and tables in lists
- Identify and correct common errors in for-loops
## Prerequisites
- You have completed the "Vectors for Iteration in R" exercise
- You know the basics of `dplyr` and `ggplot2`
- You understand how to create vectors and access elements
## Data
We will use global sanitation data from the WHO/UNICEF Joint Monitoring Programme (JMP). This dataset contains information about sanitation services across different countries, regions, and years.
```{r}
# Read the data
san <- read_csv("data/jmp_wld_sanitation_long.csv")
glimpse(san)
```
## Get an overview
First, get an overview of the data. What regions are included?
```{r}
san |>
distinct(region_sdg) |>
arrange(region_sdg)
```
You should see 8 regions: Australia and New Zealand, Central and Southern Asia, Eastern and South-Eastern Asia, Europe and Northern America, Latin America and the Caribbean, Northern Africa and Western Asia, Oceania (excluding Australia and New Zealand), and Sub-Saharan Africa.
# Task 1: Understanding the Problem - Repetitive Code
Imagine you want to create a **separate plot for each region** showing how basic sanitation services (san_bas) have changed over time for national-level data.
## 1.1 Analyze the Copy-Paste Approach
```{r}
# Plot 1: Australia and New Zealand
san |>
filter(region_sdg == "Australia and New Zealand",
varname_short == "san_bas",
residence == "national") |>
ggplot(aes(x = year, y = percent, colour = name)) +
geom_line(linewidth = 1.2) +
labs(
title = "Basic Sanitation: Australia and New Zealand",
x = "Year",
y = "Percent with basic sanitation"
) +
theme_minimal()
# Plot 2: Central and Southern Asia
san |>
filter(region_sdg == "Central and Southern Asia",
varname_short == "san_bas",
residence == "national") |>
ggplot(aes(x = year, y = percent, colour = name)) +
geom_line(linewidth = 1.2) +
scale_y_continuous(limits = c(0, NA)) +
labs(
title = "Basic Sanitation: Central and Southern Asia",
x = "Year",
y = "Percent with basic sanitation"
) +
theme_minimal()
# Plot 3: Eastern and South-Eastern Asia
san |>
filter(region_sdg == "Eastern and South-Eastern Asia",
varname_short == "san_bas",
residence == "national") |>
ggplot(aes(x = year, y = percent, colour = name)) +
geom_line(linewidth = 1.2) +
scale_y_continuous(limits = c(0, NA)) +
labs(
title = "Basic Sanitation: Eastern and South-Eastern Asia",
x = "Year",
y = "Percent with basic sanitation"
) +
theme_minimal()
# ... and so on for the remaining 5 regions
```
## 1.2 Answer the Questions
1. If you were to write out the code for all 8 regions, how many lines of code would you need approximately? (Each plot has about 16 lines)
**Answer:** About 128 lines of code (8 regions × 16 lines per plot).
2. What would you need to change if you wanted to increase the base font size in the plots from the default to 14? At how many locations?
**Answer:** You would need to change `theme_minimal()` to `theme_minimal(base_size = 14)` at 8 different locations (one for each region's plot), making the change repetitive and error-prone.
3. What happens if you have an error in your code (e.g., wrong column name)? How many places do you need to fix?
**Answer:** You would need to fix the error in 8 different places, which increases the chance of making more mistakes.
4. Why is this approach not sustainable or maintainable?
**Answer:** This approach is not sustainable because: - It requires a lot of repetitive code - Any changes need to be made in multiple places - It's error-prone (easy to forget to update all locations) - It doesn't scale well if you need to add more regions - The code is difficult to read and understand
# Task 2: When Do You Need a For-Loop?
Before writing a for-loop, we need to understand: **When is a for-loop even necessary?**
## 2.1 Situation A: Vectorized Operations (No Loop Needed!)
Many operations in R are **vectorized** - this means they automatically work on all elements.
```{r}
# Example: Create a new column for all rows
san_with_proportion <- san |>
mutate(proportion = percent / 100) # Works for ALL rows at once!
# Example: Group by a column and summarize
san_by_region <- san |>
filter(varname_short == "san_bas", residence == "national") |>
group_by(region_sdg) |>
summarise(
mean_percent = mean(percent, na.rm = TRUE),
min_year = min(year),
max_year = max(year)
)
san_by_region
```
**Important:** You **do not need a for-loop** here! `dplyr` already does this automatically for all groups.
## 2.2 Situation B: Multiple Separate Outputs (For-Loop Needed!)
But what if you want to **create a separate plot for each group** or **save multiple files**?
**This does not work with group_by()** - here you need a for-loop!
```{r}
# This code creates only one plot for all regions together
san |>
filter(varname_short == "san_bas", residence == "national") |>
ggplot(aes(x = year, y = percent, color = region_sdg)) +
geom_line(linewidth = 1.2) +
scale_y_continuous(limits = c(0, NA)) +
labs(title = "All Regions in One Plot",
x = "Year",
y = "Percent with basic sanitation") +
theme_minimal() +
theme(legend.position = "bottom")
```
## 2.3 Answer the Questions
1. What is the difference between the plot above and the plots in Task 1.1?
**Answer:** Task 1.1 creates separate plots for each region (8 individual plots), while the plot above shows all regions together in a single plot with different colored lines. In Task 1.1, each region gets its own dedicated visualization, making it easier to see details for that specific region.
2. Name two examples when you need a for-loop:
**Answer:** - When you want to create multiple separate plots (one for each category) - When you want to save multiple files (e.g., one CSV file per region or one plot per country)
3. Name two examples when you do not need a for-loop:
**Answer:** - When you want to create a new column that applies the same calculation to all rows - When you want to summarize data by groups (use `group_by()` and `summarise()` instead)
4. Complete the decision rule:
- ✅ **For-loop needed:** When you need multiple **separate** outputs
- ❌ **No for-loop:** When you work with all data **together**
# Task 3: Writing a For-Loop
Now let's convert the repetitive code into a for-loop.
## 3.1 Step 1: Create a Vector with All Regions
```{r}
# Create a vector with all unique regions
regions <- san |>
distinct(region_sdg) |>
arrange(region_sdg) |>
pull(region_sdg)
regions
```
**Questions:**
1. What type is the `regions` vector? (Use `typeof()` or `class()`)
```{r}
typeof(regions)
class(regions)
```
**Answer:** The `regions` vector is of type "character" (contains text strings).
2. How many elements does the vector have?
```{r}
length(regions)
```
**Answer:** The vector has 8 elements (one for each region).
## 3.2 Step 2: Write the For-Loop
Now let's write a for-loop that iterates over all regions:
```{r}
# Iterate over all regions
for (i in seq_along(regions)) {
# Extract the i-th region
region_current <- regions[[i]]
# Create plot for this region
plot_current <- san |>
filter(region_sdg == region_current,
varname_short == "san_bas",
residence == "national") |>
ggplot(aes(x = year, y = percent, colour = name)) +
geom_line(linewidth = 1.2) +
scale_y_continuous(limits = c(0, NA)) +
labs(
title = paste("Basic Sanitation:", region_current),
x = "Year",
y = "Percent with basic sanitation"
) +
theme_minimal()
# Display the plot
print(plot_current)
}
```
**Answer the Questions:**
1. How many plots are created?
**Answer:** 8 plots are created (one for each region).
2. What does `seq_along(regions)` do? Test it separately and describe it:
```{r}
seq_along(regions)
```
**Answer:** `seq_along(regions)` creates a sequence of integers from 1 to the length of the vector. In this case, it creates the sequence 1, 2, 3, 4, 5, 6, 7, 8. This is useful for for-loops because it provides the index positions we need to access each element.
3. What happens when `i = 1`? Which region is used? Test it:
```{r}
# Test manually
regions[[1]]
```
**Answer:** When `i = 1`, the first region in the vector is used, which is "Australia and New Zealand".
4. Why do we need `print(plot_current)` in the loop?
**Answer:** In a for-loop, ggplot objects are not automatically displayed. We need to explicitly use `print()` to show each plot. Without `print()`, the loop would run without errors, but no plots would be visible.
5. Compare copy-paste and for-loop: What are the three most important advantages of the for-loop?
**Answer:** - **Maintainability:** Changes need to be made in only one place - **Scalability:** Easy to add more regions without changing the code structure - **Readability:** The code is more concise and easier to understand
## Task 4: Data Communication
Add your name as the author in the YAML header at the top of this document.
Render the document and fix any errors that occur.
## Task 5: Commit & Push & Issue
Refer back to the instructions on the course website to complete the assignment: https://ds4owd-002.github.io/website/content/assignments/md-06/am-06-3-for-loops.html