R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
170: Reading SPSS/SAS/Stata Files with haven
I recently had a collaborator send me a dataset from a longitudinal study on urban transit. They're SPSS power users, so they sent me a .sav file. Now, if you've only worked with CSVs or Parquet files, you might be tempted to just ask them to "export it to Excel," but that's a rookie move. You lose the metadata—the variable labels and value labels—that are baked into the SPSS format. We want that data.
The "Why isn't this working?" moment
My first instinct was to see if base R could handle it. I tried a few things, but it quickly became apparent that R doesn't natively understand the binary structure of a .sav file. I needed the haven package. It's the industry standard for this kind of thing because it's designed specifically to bridge the gap between R and the "big three" of social science software: SPSS, SAS, and Stata.
install.packages("haven")
library(haven)
# Let's try to bring in the transit survey data
transit_data <- read_sav("city_transit_survey.sav")
head(transit_data)
At first glance, the data looks fine. I see my columns: user_id, commute_time, and satisfaction_level. But when I look closer at satisfaction_level, something is off. The values are numbers—1, 2, 3—but I know that in the original survey, 1 meant "Very Dissatisfied" and 5 meant "Very Satisfied."
The mystery of the labelled class
I ran class(transit_data$satisfaction_level) and got something I've never seen in a standard data frame: "haven_labelled". This is where haven does something clever (and slightly annoying if you aren't expecting it). It doesn't just give you the numbers, and it doesn't just give you the text labels; it gives you both, wrapped in a special class.
If I try to run a simple summary, it behaves like a numeric vector. But if I want to use these as categories for a plot or a regression, I need them to be actual R factors. I tried to just wrap it in as.factor(), but that only turned the numbers (1, 2, 3) into factors. The descriptive labels—the "Very Dissatisfied" part—were still hidden in the metadata.
# This doesn't do what I want; it just factors the numbers
as.factor(transit_data$satisfaction_level)
# Output: [1] "1" "2" "1" "3" ...
Bridging the gap to R factors
This is where as_factor() from the haven package comes in. Notice the underscore—it's different from the base R as.factor(). This specific function is designed to look at those haven_labelled attributes and actually swap the numbers for the labels stored in the file.
# Let's convert the labelled columns to actual R factors
transit_clean <- as_factor(transit_data)
head(transit_clean$satisfaction_level)
# Output: [1] "Very Dissatisfied" "Neutral" "Very Satisfied" ...
That's much better. Now the data is actually readable. If I have a massive dataset and I only want to convert specific columns, I can do that within a mutate call using dplyr, but applying as_factor() to the whole data frame is usually the quickest way to "R-ify" a social science dataset.
What about Stata and SAS?
I haven't had to deal with Stata or SAS files as often, but the logic in haven is identical. You just swap the reading function. If a colleague hands you a .dta file from Stata or a .sas7bdat from SAS, you don't need to learn a new workflow.
# For Stata
stata_data <- read_dta("health_metrics.dta")
# For SAS
sas_data <- read_sas("clinical_trial.sas7bdat")
# And then, just like before:
stata_clean <- as_factor(stata_data)
The consistency here is great. Whether it's SPSS, SAS, or Stata, the pattern is always: read_[format] → as_factor() → analysis.
📋 Practical Task
Converting Legacy Health Records from Stata
You have been provided with a Stata file named patient_outcomes.dta. This file contains a column called treatment_group and another called recovery_status. Both are stored as labelled vectors (e.g., 1 = "Control", 2 = "Experimental").
Write a script that:
- Loads the
havenlibrary. - Reads the
patient_outcomes.dtafile into a data frame. - Converts all labelled columns into R factors so that the text labels (like "Control") are visible instead of the numeric codes.
- Displays the first 6 rows of the resulting cleaned data frame to verify the labels have been applied.
There are no comments for now.