library(tidyverse)
ghg_url <- "https://bcdanl.github.io/data/GHG_emissions_by.csv"
ghg <- read_csv(
ghg_url,
show_col_types = FALSE
)Classwork 1
Build and Audit a Greenhouse-Gas Change Pipeline
🎯 Research studio goal
This classwork applies Lecture 2: Data Transformation with dplyr.
Your final artifact is:
- one six-row table comparing U.S. sector values in 2005 and 2017;
- one defensible sentence describing the strongest pattern; and
- a six-part audit covering unit, scope, order, missingness, duplicates, and claim.
Work with a partner. One person drives the code while the other predicts the output grain and audits each decision; switch roles halfway through.
By the end, you should be able to:
- choose
dplyrverbs from a research question; - track what one row represents through a pipeline;
- distinguish missing values from zeros;
- defend a denominator rule for percentage change; and
- write a claim that stays within the evidence.
📥 Data and provenance
We will use the course-hosted GHG_emissions_by.csv.
| Variable | Meaning available from the file |
|---|---|
Party |
Reporting party or aggregate |
Year |
Inventory year |
Sector |
Environmental inventory sector |
GHG_emissions |
Reported numeric inventory value |
The file does not include a unit label or source documentation. Throughout this activity, say reported inventory value rather than silently assigning a unit or interpreting every value as a direct emission.
Setup
Run this code once.
Before looking at any summary, complete the sentence:
One intended row represents one ________________________________ record.
🧪 Part 1 · Audit before answering
1A. Predict the output grain
The pipeline below has no group_by(). How many rows should it return? Write your prediction, then replace the blanks and run it.
ghg |>
summarise(
rows = ___,
parties = n_distinct(___),
first_year = min(___),
last_year = max(___),
sectors = n_distinct(___),
missing_values = sum(is.na(___))
)1B. Audit the intended key
If one row is intended to be one party × year × sector record, those three variables form the candidate key. Complete a pipeline that returns only duplicated keys.
ghg |>
count(___, ___, ___) |>
filter(___ > 1)Write: What is the difference between checking a key and checking the truth of a value?
🕳️ Part 2 · Locate missingness
Count missing values by sector, retain the group size, compute the missing share, and place the most incomplete sector first.
missing_by_sector <- ghg |>
group_by(___) |>
summarise(
rows = ___,
missing = sum(is.na(___)),
missing_share = mean(is.na(___)),
.groups = "drop"
) |>
arrange(desc(___))
missing_by_sectorDiscuss with your partner:
- Why would
sum(GHG_emissions, na.rm = TRUE)be different from claiming that every missing value equals zero? - Which additional variable would you group by to learn whether missingness is concentrated in particular years or parties?
🗂️ Part 3 · Make the working table legible
Create lowercase names while preserving all 7,224 rows. Use select(), rename(), and relocate() once each.
ghg_working <- ghg |>
select(___, ___, ___, ___) |>
rename(
party = ___,
year = ___,
sector = ___,
emissions = ___
) |>
relocate(___, ___, ___)
glimpse(ghg_working)🇺🇸 Part 4 · Focus the environmental question
Our question is:
Between 2005 and 2017, which U.S. sector values changed the most, and which changes can be expressed as percentages without using a nonpositive denominator?
Create us_endpoints with only the United States, the two endpoint years, and all six sectors. Sort before using first() and last() later.
us_endpoints <- ghg_working |>
filter(
party == ___,
year %in% c(___, ___)
) |>
arrange(___, ___)
us_endpointsBefore running it, predict:
- number of rows: ________
- one row now represents: ________________________________
🧮 Part 5 · Change the grain and calculate change
Build one output row per sector. Keep an endpoint-completeness count, compute absolute change, and compute percentage change only when the 2005 value is positive.
us_change <- us_endpoints |>
group_by(___) |>
summarise(
start = first(___),
end = last(___),
endpoint_values = sum(!is.na(___)),
.groups = "drop"
) |>
mutate(
change = ___ - ___,
pct_change = if_else(
___ > 0,
100 * ___ / ___,
NA_real_
)
) |>
arrange(___)
us_changeAnswer in words:
- What does one row in
us_changerepresent? - Why did order matter before
first()andlast()? - Why is
pct_changemissing forLULUCFeven though both endpoints exist? - Why should the positive change for a negative
LULUCFvalue not be interpreted without sector documentation?
📊 Part 6 · Produce the analytical artifact
Create a presentation-ready six-row table. Keep the missing and nonpositive-baseline cases visible rather than silently dropping them.
final_table <- us_change |>
transmute(
sector,
value_2005 = round(start),
value_2017 = round(end),
absolute_change = round(change),
percent_change = round(pct_change, 1),
audit_status = case_when(
endpoint_values < 2 ~ "missing endpoint",
start <= 0 ~ "nonpositive baseline",
TRUE ~ "percent reported"
)
)
final_tableWrite one defensible sentence
Use a structure like this, then improve it:
In this inventory file, the reported U.S. ________ value [rose/fell] by ________ between 2005 and 2017 (________% using a positive 2005 baseline); the file does not document ________, so the result should be interpreted as ________________________________.
🛡️ Part 7 · Peer audit the claim
Exchange artifacts with another pair. The reviewing pair should check each item and identify the exact line of code or sentence that supplies the evidence.
Revise one line of code or one phrase after the audit. Record what changed and why.
🐦 Optional extension · Transfer the pipeline to climate tweets
If your pair finishes early, use the four 2017 climate-tweet files from the lecture. The CSVs contain only content; sentiment and strength must be recovered from the filenames.
tweet_urls <- c(
positive_weak =
"https://bcdanl.github.io/data/UStweets_positive_weak_2017.csv",
positive_strong =
"https://bcdanl.github.io/data/UStweets_positive_strong_2017.csv",
negative_weak =
"https://bcdanl.github.io/data/UStweets_negative_weak_2017.csv",
negative_strong =
"https://bcdanl.github.io/data/UStweets_negative_strong_2017.csv"
)
tweets <- bind_rows(
positive_weak = read_csv(tweet_urls[["positive_weak"]]),
positive_strong = read_csv(tweet_urls[["positive_strong"]]),
negative_weak = read_csv(tweet_urls[["negative_weak"]]),
negative_strong = read_csv(tweet_urls[["negative_strong"]]),
.id = "sample"
) |>
mutate(
sentiment = if_else(
str_starts(sample, "positive"), "positive", "negative"
),
strength = if_else(
str_ends(sample, "strong"), "strong", "weak"
)
)Choose one topic—hurricane, wildfire, flood, or drought—and produce one table with matching rows and within-topic shares by sentiment and strength. Then audit either repeated text or suspicious encoding.
Your claim must begin:
Within these four labeled tweet files, …
It may not claim to represent all U.S. tweets or public opinion because the files have no sampling documentation, tweet IDs, dates, users, or locations.
✅ Exit ticket
Submit or save:
final_table;- your revised one-sentence claim; and
- this completion:
The most consequential decision in our pipeline was __________________ because __________________.
Then annotate your pipeline with the row grain after filter(), after group_by() + summarise(), and in the final artifact.