# Run this only if a package is not already installed:
# install.packages(c("tidyverse", "haven", "labelled", "here"))
library(tidyverse)
library(haven)
library(labelled)
library(here)Lab 1: Your First Reproducible Survey Analysis
R, RStudio, Quarto, and the Latino National Survey
Purpose
This lab introduces the workflow we will use throughout the semester. We will work with a real public-opinion survey, the Latino National Survey (LNS), and learn how to move from a raw data file to a small, documented analysis file.
Most of the lab will be completed together in class. The final On Your Own section asks you to adapt the same workflow alone.
Learning objectives
By the end of this lab, you should be able to:
- identify the main parts of RStudio;
- work inside an RStudio project;
- distinguish a Quarto source file from the Console;
- install and load packages;
- import a Stata survey file with haven;
- inspect a data frame and use its codebook;
- recognize common variable types and labelled variables;
- select, filter, recode, mutate, count, and summarize with dplyr;
- distinguish substantive responses from missing values;
- save a clean analysis file; and
- render a reproducible HTML document.
Before class
Install current versions of R, RStudio Desktop, and Quarto.
Open the course project rather than opening this file by itself. A project keeps the data, code, and output in a stable relationship and helps us avoid fragile computer-specific paths.
The RStudio workspace
R is the programming language. RStudio is the interface we use to write, run, organize, and inspect R code.
The four panes normally contain:
- Source: the Quarto document or script we are writing;
- Console: commands R has executed and messages it returns;
- Environment/History: objects created during the current session;
- Files/Plots/Packages/Help: project files, graphics, packages, and documentation.
Write code in the source document and run it from there. Code typed only in the Console is easy to lose and cannot produce a reproducible analysis.
1. A Quarto document
This file combines prose, executable R code, results, and document settings. Add your name below, save the file, and render it before continuing.
Student: Your name here
If the document renders, Quarto can execute the code in a fresh session and build the output.
2. Packages
A package adds functions to R. We will use tidyverse for data work, haven for Stata files, labelled for survey labels, and here for stable project paths.
Install a package once with install.packages(). Load it in every new R session with library().
Do not place install.packages() in a document you submit. Installing changes the computer; loading declares what the analysis needs.
3. Import the Latino National Survey
The LNS interviewed more than 8,000 Latino adults in 2006. Its questionnaire contains measures of political attitudes, identity, discrimination, policy preferences, demographic characteristics, and incorporation.
The raw file is stored in Stata format. We import it with read_dta().
lns_raw <- read_dta(
here("Labs", "case_study", "data", "lns_full.dta")
)The assignment operator stores the result on its left. We use the name lns_raw deliberately: the raw data should remain unchanged.
Check the import
dim(lns_raw)
names(lns_raw)[1:20]
glimpse(lns_raw)- dim() reports rows and columns.
- names() reports variable names.
- glimpse() gives a compact view of names, types, and example values.
Checkpoint 1: How many respondents and variables are in the raw file? Why is the number of rows not necessarily the same as the number of people in the target population?
Your response:
4. Survey data and labelled variables
Survey files frequently store a short variable name, a longer variable label describing the question, and value labels explaining what numeric codes mean.
var_label(lns_raw$natprob)
val_labels(lns_raw$natprob)
var_label(lns_raw$age)
summary(lns_raw$age)The variable natprob records what respondents named as the most important problem facing the country. The variable age records respondent age.
Convert labelled response categories to readable factors when needed:
lns_raw |>
count(as_factor(natprob), sort = TRUE)A numeric code is not automatically a quantity. A code of 4 for “strongly agree” does not mean the respondent possesses twice as much agreement as someone coded 2. Consult the labels and questionnaire before calculating.
Checkpoint 2: What is the most common response to natprob? Identify at least one category that may represent missing information rather than a substantive answer.
Your response:
5. Build a small analysis file
A professional workflow rarely modifies the full raw file directly. Create a smaller analysis object containing the variables required for the current task.
lns_clean <- lns_raw |>
transmute(
main_problem = as_factor(natprob),
latino_problem = as_factor(latprob),
generation = as_factor(newgen),
age = as.numeric(age),
female = as_factor(female),
income = as_factor(income),
poor_work = as_factor(poordisc),
latino_work = as_factor(latdisc),
discrimination_index = as.numeric(discindx)
)This introduces several important ideas:
- the pipe sends the result from one step into the next;
- transmute() creates a new data frame containing only the listed variables;
- descriptive names document what variables mean; and
- conversion is performed one variable at a time.
Inspect the result:
glimpse(lns_clean)
summary(lns_clean$age)
count(lns_clean, generation, sort = TRUE)6. Missing and non-substantive responses
Don't know, refusal, not asked, and legitimate categories such as none are not interchangeable. Inspect the questionnaire and make an explicit decision.
lns_clean |>
count(main_problem, sort = TRUE)Retain the original variable and create an analysis version:
lns_clean <- lns_clean |>
mutate(
main_problem_analysis = main_problem,
main_problem_analysis = na_if(main_problem_analysis, "dk/na")
)Check the result:
lns_clean |>
summarize(
total_rows = n(),
observed_main_problem = sum(!is.na(main_problem_analysis)),
missing_main_problem = sum(is.na(main_problem_analysis)),
percent_missing = mean(is.na(main_problem_analysis)) * 100
)The text used for a missing category must match its value label exactly. If the code produces no change, inspect the frequency table and revise the text.
Checkpoint 3: Why did we create main_problem_analysis instead of overwriting main_problem?
Your response:
7. Filter, count, and summarize
Create an object containing respondents ages 18–29.
young_adults <- lns_clean |>
filter(age >= 18, age <= 29)
nrow(young_adults)Summarize their age:
young_adults |>
summarize(
respondents = n(),
mean_age = mean(age, na.rm = TRUE),
median_age = median(age, na.rm = TRUE),
minimum_age = min(age, na.rm = TRUE),
maximum_age = max(age, na.rm = TRUE)
)Count the most important problems they named:
young_adults |>
count(main_problem_analysis, sort = TRUE) |>
mutate(percent = n / sum(n) * 100)Checkpoint 4: In plain language, explain what one row of the table tells us. Why should we not yet describe these as nationally representative estimates?
Your response:
8. Save the analysis file
Save the smaller analysis object, not a modified version of the raw file.
dir.create(
here("Labs", "fall2026", "lab1", "output"),
recursive = TRUE,
showWarnings = FALSE
)
write_rds(
lns_clean,
here("Labs", "fall2026", "lab1", "output", "lns_clean.rds")
)An RDS file stores one R object and preserves its structure.
Guided-work checklist
Before moving to the independent section, confirm that you can:
- render the document;
- explain installing versus loading a package;
- locate data using a project-relative path;
- identify the dimensions and variables of a data frame;
- inspect variable and value labels;
- preserve a raw object while building a clean object;
- explain the principal dplyr functions used above; and
- identify an unresolved methodological question instead of silently making a coding decision.
On Your Own
Complete this section alone. You may consult the guided code, package help, and course materials. Include code, output, and brief interpretations.
Use latino_problem, which records what respondents considered the most important problem facing Latinos.
Question 1: Inspect the variable
Produce a frequency table for latino_problem, sorted from most to least frequent.
- What is the most common response?
- Which categories should be treated as non-substantive or missing?
- Explain your decision in two or three sentences.
# Your codeYour interpretation:
Question 2: Create an analysis version
Create latino_problem_analysis. Preserve latino_problem and recode the appropriate non-substantive categories to NA. Show the number and percentage missing.
# Your codeYour interpretation:
Question 3: Select a group
Choose one generation category and create a filtered data frame for that group. Report the category, number of respondents, mean and median age, and percentage missing latino_problem_analysis.
# Your codeYour interpretation:
Question 4: Produce a substantive table
Within the selected generation, calculate the count and percentage naming each substantive problem facing Latinos. Sort from highest to lowest and display the five most common responses.
# Your codeInterpret the leading response accurately without making a causal or population-level claim.
Question 5: Document one decision
Write a short paragraph explaining one decision made while cleaning, filtering, or summarizing. State what you decided, what evidence you used, how it affects the result, and what you would verify before publishing.
Submission
Submit the completed QMD source file, rendered HTML file, and lns_clean.rds analysis file. Before submitting, restart R and render again. A successful clean render is the final reproducibility check.
Reference materials
- Latino National Survey questionnaire and codebook in the repository
- R for Data Science, 2nd edition
- Quarto documentation
- Posit cheat sheets