This bank holds 40 questions, ten in each section. Section 1 gives you the data inside the question; Section 2 uses the canola-only RM yields file, and Sections 3–4 the full eight-crop long file (both described below). On the real test you receive four questions – one from each section – and you submit a single, well-commented R script: a header block at the top, a clearly labelled section for each question, and your sentence answers written as comments. The script should run from top to bottom in a project folder that has the csvs in data/. Each question is designed to take about 8–10 minutes.
Expand each Answer block to check your work. Every value has been computed from the real data; if the source file is refreshed the exact numbers may shift slightly, but the method stays the same.
The data. Two files, both in your project’s data/ folder:
rm_canola_yields_1990_2025.csv – average canola yield in every Saskatchewan Rural Municipality, 1990–2025, one row per RM-year. Section 2 uses this file: one crop, one unit, so its summary statistics mean something.
rm_yields_1990_2025.csv – the same data for all eight crops, one row per RM-year-crop. Sections 3 and 4 use this file. You worked with the wide version in Module 1; this is the long form, with Crop as a variable. Lentils are recorded in pounds per acre; every other crop is in bushels per acre – the Unit column says which, and several questions turn on it.
Both files have the same five columns: Year, RM, Crop, Yield, Unit.
Grading model.20% for script presentation – a header block, comments in the style of the module, clearly labelled question sections, and a script that runs from top to bottom in a fresh session. The remaining 80% is split evenly across the four questions, and evenly across the parts within each question. Parts are marked on follow-through: if an early part is wrong but the later parts are correctly worked from your own earlier answer, the later parts still earn full marks. Where a part asks for a sentence, write it as a comment in your script.
Vocabulary note. Everything here uses only Module 2 tools: <-, arithmetic on vectors, c(), data.frame(), $, mean, median, sd, var, min, max, range, sum, quantile (with probs), IQR, nrow, ncol, names, head, print, glimpse, summary, library(), install.packages(), read_csv with relative paths, filter (with ==, >, <, &, |, !, %in%), select (including - and :), rename, mutate, arrange and desc, the pipe |>, summarise, n(), group_by, and write_csv. Nothing beyond that is needed.
NoteA sample test, with a full-marks answer script
A real test looks like this – one question from each section (here Questions 1, 16, 25, and 36):
Five canola fields yielded 52.3, 47.8, 55.1, 44.6, and 50.9 bu/ac, on 160, 320, 240, 130, and 200 acres. Create the two vectors; convert the yields to t/ha; compute the mean and sd of the yields; compute total production and the acreage-weighted average yield.
Compute the mean, median, and standard deviation of canola Yield, and its 90th percentile. In a comment: the mean sits a little above the median – what does that direction of gap suggest about the shape of canola yields?
Filter to the lentil rows, saving as lentils (how many rows?); add a yield_kg_ha column (multiply by 1.12), saving back to lentils; compute the mean of the new column and of the original, and check their ratio.
In one pipeline, compute each RM’s mean Spring Wheat yield across all years, sorted best-first. Report the top three RMs. In a comment: what did each row of the input represent, and what does each row of the result represent?
And here is a script that would earn full marks, including all of the presentation component – with the console session it produces shown beneath it:
# ---# Title: Module 2 test# Author: Jordan Field# Date: 2026-10-15# Description:# Answers to the four test questions, one section per block.# Sentence answers are written as comments below each result.# ---# Load packageslibrary(tidyverse)# ============================================================# Section 1 (Question 1): five canola fields# ============================================================# Yields (bu/ac) and field sizes (acres)yields <-c(52.3, 47.8, 55.1, 44.6, 50.9)acres <-c(160, 320, 240, 130, 200)# (a/b) Convert every yield to tonnes per hectare in one stepyields_t_ha <- yields *0.0560yields_t_ha# (c) Centre and spread of the yieldsmean(yields) # 50.14 bu/acsd(yields) # 4.06 bu/ac# (d) Total production, then the average weighted by acrestotal_bu <-sum(yields * acres)total_bu # 52,866 butotal_bu /sum(acres) # 50.35 bu/ac# The weighted average differs from the plain mean because the# fields differ in size, so each yield should count by its acres.# ============================================================# Section 2 (Question 16): summary statistics for canola# ============================================================# Read the canola file using a relative path from the project folderrm_canola <-read_csv("data/rm_canola_yields_1990_2025.csv")# Centre and spread of the canola yieldsmean(rm_canola$Yield) # 28.29 bu/acmedian(rm_canola$Yield) # 26.9 bu/acsd(rm_canola$Yield) # 10.06 bu/ac# 90th percentilequantile(rm_canola$Yield, 0.9) # 42.5 bu/ac# The mean sits a little above the median, which suggests mild# right skew: the best RM-years pull the mean up more than the# worst years pull it down.# ============================================================# Section 3 (Question 25): converting the lentil yields# ============================================================# Read the full eight-crop filerm_yields <-read_csv("data/rm_yields_1990_2025.csv")# Keep only the lentil rowslentils <-filter(rm_yields, Crop =="Lentils")nrow(lentils) # 6,338 rows# Add the converted column (1 lb/ac is about 1.12 kg/ha) and# overwrite lentils with the version that has the extra columnlentils <-mutate(lentils, yield_kg_ha = Yield *1.12)# Means of the new and original columnsmean(lentils$yield_kg_ha) # 1,353.4 kg/hamean(lentils$Yield) # 1,208.39 lb/ac# Their ratio is 1.12, the conversion factor -- multiplying every# value by a constant multiplies the mean by the same constant.# ============================================================# Section 4 (Question 36): best wheat-growing RMs# ============================================================rm_yields |># take the data, THENfilter(Crop =="Spring Wheat") |># keep spring wheat, THENgroup_by(RM) |># split the rows by RM, THENsummarise(mean_yield =mean(Yield)) |># one row per RM: its mean, THENarrange(desc(mean_yield)) # best RMs on top# Top three: RM 369 (47.6), RM 333 (47.2), RM 368 (47.2) bu/ac.# Each input row was one RM-year observation of spring wheat; each# result row is one RM, its years collapsed into a single mean.
> # ---
> # Title: Module 2 test
> # Author: Jordan Field
> # Date: 2026-10-15
> # Description:
> # Answers to the four test questions, one section per block.
> # Sentence answers are written as comments below each result.
> # ---
>
> # Load packages
> library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
>
> # ============================================================
> # Section 1 (Question 1): five canola fields
> # ============================================================
>
> # Yields (bu/ac) and field sizes (acres)
> yields <- c(52.3, 47.8, 55.1, 44.6, 50.9)
> acres <- c(160, 320, 240, 130, 200)
>
> # (a/b) Convert every yield to tonnes per hectare in one step
> yields_t_ha <- yields * 0.0560
> yields_t_ha
[1] 2.9288 2.6768 3.0856 2.4976 2.8504
>
> # (c) Centre and spread of the yields
> mean(yields) # 50.14 bu/ac
[1] 50.14
> sd(yields) # 4.06 bu/ac
[1] 4.062388
>
> # (d) Total production, then the average weighted by acres
> total_bu <- sum(yields * acres)
> total_bu # 52,866 bu
[1] 52866
> total_bu / sum(acres) # 50.35 bu/ac
[1] 50.34857
> # The weighted average differs from the plain mean because the
> # fields differ in size, so each yield should count by its acres.
>
> # ============================================================
> # Section 2 (Question 16): summary statistics for canola
> # ============================================================
>
> # Read the canola file using a relative path from the project folder
> rm_canola <- read_csv("data/rm_canola_yields_1990_2025.csv")
Rows: 10039 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Crop, Unit
dbl (3): Year, RM, Yield
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
>
> # Centre and spread of the canola yields
> mean(rm_canola$Yield) # 28.29 bu/ac
[1] 28.29239
> median(rm_canola$Yield) # 26.9 bu/ac
[1] 26.9
> sd(rm_canola$Yield) # 10.06 bu/ac
[1] 10.06019
>
> # 90th percentile
> quantile(rm_canola$Yield, 0.9) # 42.5 bu/ac
90%
42.5
>
> # The mean sits a little above the median, which suggests mild
> # right skew: the best RM-years pull the mean up more than the
> # worst years pull it down.
>
> # ============================================================
> # Section 3 (Question 25): converting the lentil yields
> # ============================================================
>
> # Read the full eight-crop file
> rm_yields <- read_csv("data/rm_yields_1990_2025.csv")
Rows: 71104 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Crop, Unit
dbl (3): Year, RM, Yield
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
>
> # Keep only the lentil rows
> lentils <- filter(rm_yields, Crop == "Lentils")
> nrow(lentils) # 6,338 rows
[1] 6338
>
> # Add the converted column (1 lb/ac is about 1.12 kg/ha) and
> # overwrite lentils with the version that has the extra column
> lentils <- mutate(lentils, yield_kg_ha = Yield * 1.12)
>
> # Means of the new and original columns
> mean(lentils$yield_kg_ha) # 1,353.4 kg/ha
[1] 1353.402
> mean(lentils$Yield) # 1,208.39 lb/ac
[1] 1208.395
> # Their ratio is 1.12, the conversion factor -- multiplying every
> # value by a constant multiplies the mean by the same constant.
>
> # ============================================================
> # Section 4 (Question 36): best wheat-growing RMs
> # ============================================================
>
> rm_yields |> # take the data, THEN
+ filter(Crop == "Spring Wheat") |> # keep spring wheat, THEN
+ group_by(RM) |> # split the rows by RM, THEN
+ summarise(mean_yield = mean(Yield)) |> # one row per RM: its mean, THEN
+ arrange(desc(mean_yield)) # best RMs on top
# A tibble: 298 × 2
RM mean_yield
<dbl> <dbl>
1 369 47.6
2 333 47.2
3 368 47.2
4 271 46.1
5 303 45.0
6 427 45.0
7 404 44.9
8 496 44.8
9 493 44.6
10 338 44.5
# ℹ 288 more rows
>
> # Top three: RM 369 (47.6), RM 333 (47.2), RM 368 (47.2) bu/ac.
> # Each input row was one RM-year observation of spring wheat; each
> # result row is one RM, its years collapsed into a single mean.
Section 1 — R Basics
These questions are about the building blocks: objects, vectors, data frames, and functions. No data file is needed – the numbers are in the question. Answer in the Section 1 block of your script, with sentence answers written as comments.
Question 1
Five canola fields yielded 52.3, 47.8, 55.1, 44.6, and 50.9 bu/ac, on 160, 320, 240, 130, and 200 acres.
(a) Create a vector yields and a vector acres holding these values.
(b) Create a vector yields_t_ha converting the yields to tonnes per hectare (multiply by 0.0560). No loop, no repetition – one line.
(c) Compute the mean and standard deviation of yields.
(d) Compute total production in bushels (each field’s yield times its acres, summed), and the farm’s average yield weighted by acres (total bushels divided by total acres).
Total 52,866 bu; weighted average 50.35 bu/ac (slightly higher than the plain mean because the larger fields yielded a little less than the small high-yield field pulls up).
Question 2
(a) Build a data frame called fields with three columns: field_id containing "F1" to "F5", crop containing Canola, Wheat, Canola, Peas, Wheat, and yield containing 44.1, 52.7, 39.8, 41.5, 49.3.
(b) Report the number of rows, the number of columns, and the column names using functions (not by counting).
(c) Pull out the yield column with $ and compute its mean and median.
(d) In a comment: each column of a data frame is itself a familiar R object – which one?
(b, c) 25th percentile 32, 75th percentile 43.5 – identical both ways, because naming the arguments frees them from their positions.
R reads 0.25 as the data x and the yields as probs; since probs must lie between 0 and 1, it stops with Error: 'probs' outside [0,1]. Unnamed arguments only work in the order the function expects.
Question 4
A student types the following four lines into the console, in order:
x <-8x *3y <- x -3x * y
(a) In a comment: which lines print something to the console, and what exactly do they print (including the [1])?
(b) In a comment: after all four lines, what objects does the Variables pane show, with what values? Is the result of x * 3 among them?
(c) A fifth line, y <- y * 2, is now run. In a comment: what does the Variables pane show afterwards, and did the line print anything?
Answer
Only the second and fourth lines print: [1] 24 and [1] 40. Assignments print nothing.
x = 8 and y = 5. The result of x * 3 was displayed but never assigned, so it is not saved anywhere – displaying a result and saving one are different things.
y is now 10 (the old value was used to compute the new one, then overwritten); x is still 8. Nothing printed – it is an assignment.
Question 5
A student opens a new file in Positron, types a script that creates three objects, and saves the file – but the Variables pane still says “No variables have been created.”
(a) In a comment: why does nothing exist yet, in one sentence?
(b) In a comment: give the two ways to run the script from Module 2 (one uses a button, one a keyboard shortcut).
(c) In a comment: after running it, where do results appear, and where do the created objects appear?
Answer
Writing code in a script does not run it – typing puts text in a file, and nothing happens until the code is executed.
The Run button (source the whole file, or Execute code for selected lines), or Cmd+Enter (Mac) / Ctrl+Enter (Windows) to run the selected lines or the line under the cursor.
Results print in the console; created objects appear in the Variables pane.
Question 6
Consider these three lines:
n <-12n ==10n =15
(a) In a comment: say what each line does. Which ones assign, which one asks a question, and what does the question print?
(b) In a comment: all three symbols (<-, ==, =) are legal R. Which one does this book use for assignment, and why does keeping the three visually distinct matter?
(c)mean(x = c(4, 9, 11)) also contains an =. In a comment: what is = doing there?
Answer
Line 1 assigns 12 to n. Line 2 asks whether n equals 10 and prints [1] FALSE. Line 3 also assigns – n is now 15.
<- for assignment. It keeps assignment visually distinct from = naming arguments inside function calls and from == testing equality – three different jobs that are easy to confuse when they all look alike.
Naming an argument: it tells mean() that the vector is its x argument. It does not create an object called x in the Variables pane.
(a) Rewrite it with a proper header block (Title, Author, Date, Description) and a comment before each step, following the module’s conventions.
(b) Replace the object names with descriptive ones.
(c) In a comment: state the module’s test for whether a script is reproducible.
Answer
# ---# Title: Farm average yield# Author: Your Name# Date: 2026-10-08# Description:# Computes total production and the acreage-weighted# average yield for four fields.# ---# Field yields (bu/ac) and sizes (acres)yields <-c(38.2, 45.6, 41.9, 36.8)acres <-c(210, 180, 260, 240)# Total production in bushelstotal_bu <-sum(yields * acres)# Average yield weighted by acrestotal_bu /sum(acres)
Restart R and run the script from top to bottom: it should reproduce the analysis without any commands typed into the console. (The weighted average, for reference, is 40.35 bu/ac.)
Question 8
Five barley fields yielded 68.2, 71.5, 64.9, 74.1, and 66.3 bu/ac. Five lentil fields yielded 1450, 1720, 1280, 1610, and 1390 lb/ac.
(a) Compute the mean and standard deviation of each crop’s yields.
(b) The lentil standard deviation is far larger. In a comment: why can the two standard deviations not be compared directly?
(c) Compute the coefficient of variation (sd divided by mean) for each crop. Which crop’s yields are more variable relative to their own average?
Barley mean 69.0, sd 3.77; lentils mean 1490, sd 175.36.
They are in different units (bushels vs pounds per acre) and on very different scales, so the raw spreads are not comparable.
CV barley 0.055, lentils 0.118 – lentil yields are more variable relative to their own average.
Question 9
(a) In a comment: quantile() has two main arguments. Name them and say what each is.
(b) In a comment: you cannot remember what the probs argument of quantile() expects. What do you type to get the official documentation?
(c) A classmate writes Quantile(peas, 0.5) and gets could not find function "Quantile". In a comment: what went wrong?
Answer
x, the data, and probs, the percentile you want expressed in decimal form.
?quantile.
R is exact about names: Quantile with a capital Q is not the same as quantile, and no function by that name exists.
Question 10
A trial records, for each field: the crop grown, the seeded acres, and whether the field was irrigated.
(a) Create three vectors of length four holding made-up values for these three variables, choosing the appropriate type for each (character, numeric, logical).
(b) In a comment: which values needed quotation marks and which must not have them?
(c) Combine your three vectors into a data frame called trial and print it.
The character values (crop names) need quotes. Numbers must not have them (quoted numbers become text), and TRUE/FALSE must not have them – quoted, they would be text rather than logical values.
Section 2 — Reading and Inspecting Data
These questions use the canola-only file, rm_canola_yields_1990_2025.csv, in your project’s data/ folder. Answer in the Section 2 block of your script.
Question 11
(a) In a comment at the top of your script, sketch your project’s folder layout (the subfolders and where the csv sits).
(b) Load the tidyverse and read the canola file into an object called rm_canola, using a relative path.
(c) Report the number of rows, the number of columns, and the column names using functions.
(d) In a comment: why will your read_csv() line work on the grader’s computer, when a full path starting C:/Users/... would not?
10,039 rows, 5 columns: Year, RM, Crop, Yield, Unit.
The path is relative to the project folder, and the grader opens the same self-contained folder – so data/... exists on their machine too. An absolute path names one particular computer’s user and folder layout.
It runs on their laptop and fails on everyone else’s.
(a) In a comment: give two separate problems with this line (one about where the path points, one about the backslashes).
(b) Rewrite the line the way the module recommends, assuming the csv is in the project’s data/ folder.
(c) In a comment: the classmate asks “but with your short path, how does R know where to start looking?” Answer in one sentence.
Answer
The absolute path names one specific machine (user jordan, a Desktop folder), so it exists nowhere else; and backslashes mean something special inside an R string – paths in R use forward slashes even on Windows.
The starting point changed: relative paths begin at the folder you opened. With module_2/ open, the path is data/rm_canola_yields_1990_2025.csv.
From AREC_261, R goes into module_2, then into data, and finds rm_canola_yields_1990_2025.csv – each / steps into a subfolder.
Question 14
(a) Run glimpse() on rm_canola. In a comment: which columns are text (<chr>) and which are numeric (<dbl>)?
(b) When read_csv() ran, it printed a note about the file. In a comment: what did that note report, and why does the module say to read it every time?
(c)Year came in as a number. In a comment: would "2024" (with quotes) in a filter comparison against Year behave the same as 2024? What is the difference between the two?
Answer
Crop and Unit are <chr>; Year, RM, and Yield are <dbl>.
The row and column counts and its guess at each column’s type (here chr (2) and dbl (3)). R guesses well but not perfectly, so the note is the first check that the file read the way you expect.
No – "2024" is text and 2024 is a number; they are different types of value. The comparison wants the number.
Question 15
(a) Run summary(rm_canola). From its output, report the minimum, median, and maximum of Yield, and the first and last Year.
(b) In a comment: work through the module’s inspection questions for this file. Are the yields in a plausible range for canola in bu/ac? Are the years what the file name promises? Are there missing values?
(c) The minimum is below 2 bu/ac. In a comment: is a canola yield that low necessarily a data error? What kind of year could produce it?
Answer
Yield: min 1.9, median 26.9, max 61. Years 1990 to 2025.
Yes – everything sits between about 2 and 61 bu/ac, sensible for canola; the years run 1990–2025 as advertised; and summary() reports no NA counts, so no missing values.
Not necessarily – an RM average that low is what a severe drought or a widespread crop failure looks like. Extreme is not the same as wrong; it is a value to investigate, not delete.
Question 16
(a) Compute the mean, median, and standard deviation of rm_canola$Yield.
(b) Compute the 90th percentile of Yield.
(c) The mean sits a little above the median. In a comment: using Module 1’s language about means and medians, what does that direction of gap suggest about the shape of canola yields?
A mean above the median suggests mild right skew: the very best RM-years pull the mean up more than the worst years pull it down.
Question 17
Open rm_canola_yields_1990_2025.csv in Positron’s data viewer (click the file in the Explorer pane).
(a) In a comment: what percentage of values are missing in each column, according to the viewer?
(b) In a comment: expand the Yield column’s summary. Describe the shape of its histogram in one phrase, and say whether it matches your mean-versus-median reading from Question 16.
(c) A classmate says “the file is open in the viewer, so it’s loaded into R.” In a comment: correct them, and say what actually loads it.
Answer
0% missing in every column.
A single hump around the mid-20s with a longer tail to the right – consistent with the mean sitting a little above the median.
The viewer is Positron showing you the file; nothing exists in R until read_csv() runs and the result is assigned to an object.
Question 18
(a) Compute the 25th and 75th percentiles of Yield in a single quantile() call.
(b) Compute the interquartile range twice: once with IQR(), once by subtracting your two percentiles.
(c) In a comment: say what the interquartile range from (b) means in words, for a reader who farms.
The middle half of all RM-year canola yields falls between 21 and 35.4 bu/ac – a typical RM in a typical year lands somewhere in that 14-bushel window.
Question 19
A classmate’s fresh R session runs rm_yields <- read_csv("data/rm_yields_1990_2025.csv") and gets:
Error in read_csv(...) : could not find function "read_csv"
(a) In a comment: what is the most likely cause, and what one line fixes it?
(b) In a comment: they object, “but I installed the tidyverse last week!” Explain the difference between installing and loading, and how often each is done.
(c) In a comment: why does install.packages("tidyverse") need quotation marks while library(tidyverse) does not need them?
Answer
The package is not loaded in this session; run library(tidyverse) first.
Installing downloads the package onto the computer – once per computer. Loading switches it on – once per script or session. Installation does not carry across sessions as loaded.
It is a quirk to memorize at this stage: quotes when you install, none when you load.
Question 20
You spot an obviously wrong yield value in the csv. A classmate suggests opening the file in Excel, fixing the cell, and saving. Separately, your download folder contains RM Yields FINAL (2).csv.
(a) In a comment: what is wrong with the classmate’s suggestion, and where should the correction happen instead?
(b) In a comment: give two problems with the file name, and rename it following the module’s two rules.
(c) In a comment: if a date belonged in the file name, how should it be written, and what is the advantage?
Answer
It overwrites the only copy of the raw data and leaves no record of what changed. Keep the file exactly as it arrived and make the correction in the R script, where it leaves a trail.
Spaces and punctuation, and a FINAL (2) version tag doing a job version control should do. Something like rm_yields_long.csv.
As YYYY-MM-DD, e.g. 2026-10-08_rm_yields.csv – alphabetical order is then also chronological order.
Section 3 — Data Manipulation Functions
From here on, use the full eight-crop file: read rm_yields_1990_2025.csv into an object called rm_yields at the start of your Section 3 block. These questions use one function at a time; save intermediate results to objects where a later part needs them.
Question 21
(a) Filter rm_yields to Canola in 2024, saving the result as canola_2024. How many rows?
(b) Filter rm_yields to Canola in RM 18 (all years). How many rows?
(c) In a comment: after (a) and (b), how many rows does rm_yields itself have, and why?
31 rows (some years are missing – the crop was not grown or reported in that RM every year).
2016, at 43.9 bu/ac.
Question 30
(a) Using head(), display the first six rows of rm_yields.
(b) Display the first six rows of the data sorted by Yield in descending order (without changing rm_yields).
(c) In a comment: every row in (b) is the same crop. Which one, why those rows, and what would you check before comparing their values with the other crops?
(b, c) All lentils – their yields are recorded in pounds per acre, so they dominate the top of any sort on Yield. Before comparing across crops you would check the Unit column and convert to a common unit.
Section 4 — Pipelines and Grouped Summaries
Still the full eight-crop file (rm_yields). Answer in the Section 4 block of your script. Write multi-step work as pipelines with |>, one step per line.
Question 31
Here is a working but hard-to-read line:
arrange(select(filter(rm_yields, Crop =="Durum"& Year ==2025), RM, Yield), desc(Yield))
(a) Rewrite it as a pipeline, one step per line, with a short comment on each step.
(b) Run it. How many rows, and which RM had the best durum yield in 2025, at what value?
(c) In a comment: read your pipeline aloud as a “take the data, then …, then …, then …” sentence.
Answer
rm_yields |># take the data, THENfilter(Crop =="Durum"& Year ==2025) |># keep durum in 2025, THENselect(RM, Yield) |># keep two columns, THENarrange(desc(Yield)) # sort best-first
189 rows; RM 369 at 105.6 bu/ac.
Take rm_yields, then keep the 2025 durum rows, then keep the RM and Yield columns, then sort from highest yield to lowest.
Question 32
(a) In one pipeline, compute the mean flax yield across 2020–2025 (Year >= 2020), calling the result column mean_yield.
(b) Add n() to the same summarise() to count how many observations that mean is based on.
(c) In a comment: why is reporting the count alongside the mean good practice?
Answer
rm_yields |>filter(Crop =="Flax"& Year >=2020) |>summarise(mean_yield =mean(Yield),n =n())
(a, b) Mean 22.39 bu/ac from 1,143 observations.
A mean based on a handful of rows deserves less trust than one based on a thousand; the count tells the reader which they are looking at.
Question 33
(a) In one pipeline, filter to Canola and summarise three things: the mean yield, the standard deviation, and the number of observations.
(b) Report the three values.
(c) In a comment: your result is a data frame. How many rows does it have, and what would mutate() have produced instead of summarise() here?
Eight rows, one per crop: Barley 51.8, Canola 28.3, Durum 33.6, Flax 20.5, Lentils 1,208.4, Oats 64.7, Peas 31.8, Spring Wheat 35.3.
Lentils, at nearly twenty times any other crop.
Lentils are measured in pounds per acre and everything else in bushels – the Unit column. The group means are each fine on their own terms; comparing them across the unit boundary is not.
Question 35
(a) In one pipeline, compute the mean canola yield for each year from 2021 to 2025 (filter first, then group).
(b) Report the five means. Which year was worst, and which best?
(c) In a comment: 2021 was a severe drought year in Saskatchewan. Does the data agree?
Answer
rm_yields |>filter(Crop =="Canola"& Year >=2021) |>group_by(Year) |>summarise(mean_yield =mean(Yield))
(a, b) 2021 21.9, 2022 35.4, 2023 33.9, 2024 31.5, 2025 43.9. Worst 2021, best 2025.
Yes – the 2021 mean sits roughly a third below the surrounding years.
Question 36
(a) In one pipeline, compute each RM’s mean Spring Wheat yield across all years, and sort the result so the best wheat-growing RMs are on top.
(b) Report the top three RMs and their means.
(c) In a comment: your result has one row per RM. What did each row of the input represent, and what changed?
Top to bottom – each step’s output feeds the next. After summarise() the data has collapsed to one row and the yield_kg_ha column would not exist yet to summarise.
Question 38
A classmate hands you this pipeline and asks what it does:
(a) In a comment: explain the pipeline step by step, one sentence per step.
(b) Run it and report the output.
(c) In a comment: answer the classmate’s real question in plain language – what does the output say about oats and barley since 2015?
Answer
Take the data; keep only oat and barley rows from 2015 on; split those rows into the two crops; collapse each crop to its mean yield and its number of observations.
(a) In a comment: apply the module’s debugging habit – which step do you run first, and what do you check at each step?
(b) In a comment: identify the broken step and explain why it returns nothing.
(c) Write the corrected pipeline.
Answer
Run the first step alone and check the result looks right (the canola rows), then add the second step and check again – the first step where the data stops looking right is the problem.
The second filter: & demands both conditions true of the same row, and no yield is simultaneously below 15 and above 55. The question said “or”.
(a) In one pipeline: for 2025 only, compute each crop’s mean yield and observation count, sorted from highest mean to lowest, and save the result as crop_summary_2025.
(b) Write the table to output/crop_summary_2025.csv.
(c) Report the top two crops in the sorted table. In a comment: why does the crop in first place not mean what it appears to mean, and which crop is really the standout?
(a, c) Lentils top the table at 1,897 – but that is pounds per acre, not bushels. Among the bushel crops, Oats lead at 97.5 bu/ac (Barley next at 72.8). 2025 was a strong year across the board.