19  R for Data Analysis

R is the primary statistical computing environment used in Communication Science research at VU Amsterdam. This chapter points you to resources for learning R, running common analyses, and reporting results in APA format. It also covers how AI tools can help you write and debug R code.

19.1 Getting started with R

If you are new to R or need a refresher, start here:

Resource What it covers
R for Social Scientists (Canvas) The departmental resource — covers common analyses relevant to Communication Science; start here
CCS Amsterdam R Course Material Modular R tutorials developed at VU Amsterdam for Communication Science students — covers R fundamentals, tidyverse, ggplot2, regression, multilevel models, factor analysis, text analysis, topic modeling, and more
R for Data Science (Wickham et al.) Free online book; covers data import, transformation, visualization with the tidyverse
Learning Statistics with R (Navarro) Free textbook; covers statistics concepts alongside R implementation
swirl Interactive R tutorials you run inside R itself
Posit Cheatsheets One-page visual references for ggplot2, dplyr, tidyr, etc.
TipStatistics helpdesk

VU Amsterdam runs a statistics helpdesk for students. Check Canvas for the current schedule and how to book an appointment. This is the right place for questions about which test to use and how to run it — not me.

19.2 Essential packages

Install these packages to cover most analyses you’ll need:

install.packages(c(
  "tidyverse",   # data manipulation and visualization (dplyr, ggplot2, tidyr, ...)
  "haven",       # import SPSS (.sav) and Stata files
  "psych",       # reliability (alpha, omega), descriptive stats, factor analysis
  "car",         # ANOVA, Levene's test, recoding
  "lme4",        # multilevel / mixed models
  "lavaan",      # SEM and CFA
  "mediation",   # causal mediation analysis
  "effectsize",  # Cohen's d, eta-squared, omega-squared
  "pwr",         # a priori power analysis
  "interactions",# interaction plots for moderation
  "apaTables",   # export APA-formatted tables to Word
  "papaja",      # APA-style reporting in R Markdown / Quarto
  "report"       # automatic plain-language results reporting
))

19.3 Power analysis

Run an a priori power analysis before data collection to determine the required sample size. The pwr package covers the most common designs. See the Method chapter for guidance on choosing and justifying the effect size, and this blog post for a detailed conceptual introduction.

library(pwr)

# Experiment: independent-samples t-test (two groups)
pwr.t.test(d = 0.40, sig.level = .05, power = .80, type = "two.sample")

# Survey: correlation or simple regression
pwr.r.test(r = .20, sig.level = .05, power = .80)

# Multiple regression (u = number of predictors; f2 = R²/(1−R²))
pwr.f2.test(u = 3, f2 = .06, sig.level = .05, power = .80)

Leave the argument you want to solve for out of the call — pwr will compute it. The examples above all solve for n (sample size). To check achieved power for a given N, replace power = .80 with n = <your N> and omit power.

Reporting template:

“Based on [cite prior study], we expected a small-to-medium effect (r = .20 / d = 0.40). A power analysis (α = .05, 1 − β = .80) indicated a required sample of N = XX (pwr package; Champely, 2020).”

19.4 Common analyses

19.4.1 Descriptive statistics and correlations

library(tidyverse)
library(psych)

# Descriptive statistics
describe(data[, c("var1", "var2", "var3")])

# Correlation matrix (APA-ready)
library(apaTables)
apa.cor.table(data[, c("var1", "var2", "var3")],
              filename = "Table1_correlations.doc")

19.4.2 Reliability (Cronbach’s α and McDonald’s ω)

APA 7 recommends reporting McDonald’s ω alongside or instead of Cronbach’s α. Both are available in the psych package.

library(psych)

# Cronbach's α
alpha(data[, c("item1", "item2", "item3", "item4")])
# Look at: raw_alpha

# McDonald's ω (preferred in APA 7)
omega(data[, c("item1", "item2", "item3", "item4")], nfactors = 1)
# Look at: omega.tot (total omega)

Report as: “The scale showed good reliability (α = .84, ω = .86).”

19.4.3 Independent samples t-test

# Test whether group means differ
t.test(outcome ~ group, data = data, var.equal = TRUE)

# Effect size
library(effectsize)
cohens_d(outcome ~ group, data = data)

Report as: t(df) = X.XX, p = .XXX, d = X.XX

19.4.4 One-way and factorial ANOVA

library(car)

# Factorial ANOVA (e.g., 2x2 between-subjects experiment)
model <- lm(outcome ~ factor_a * factor_b, data = data)
Anova(model, type = "III")   # Type III sums of squares

# Effect size
library(effectsize)
eta_squared(model, partial = TRUE)

Report as: F(df1, df2) = X.XX, p = .XXX, η²_p = .XX

19.4.5 Linear regression

# Simple regression
model1 <- lm(outcome ~ predictor, data = data)
summary(model1)

# Multiple regression
model2 <- lm(outcome ~ predictor1 + predictor2 + covariate, data = data)
summary(model2)

# Standardized coefficients
library(effectsize)
standardize_parameters(model2)

Report as: b = X.XX, SE = X.XX, 95% CI [XX, XX], β = X.XX, p = .XXX

For more comprehensive tutorials, see here.

19.4.6 Moderation (interaction effects)

# Center continuous predictors before creating interaction term
data$pred_c     <- scale(data$predictor, center = TRUE, scale = FALSE)
data$moderator_c <- scale(data$moderator, center = TRUE, scale = FALSE)

model_mod <- lm(outcome ~ pred_c * moderator_c, data = data)
summary(model_mod)

# Visualize interaction with ggplot2 or the 'interactions' package
library(interactions)
interact_plot(model_mod, pred = pred_c, modx = moderator_c)

19.4.7 CFA and SEM with lavaan

The lavaan package handles confirmatory factor analysis (CFA) and structural equation modeling (SEM). Use CFA to validate your measurement model before testing structural paths.

library(lavaan)

# --- CFA: validate a single scale ---
model_cfa <- '
  privacy_concern =~ pc1 + pc2 + pc3 + pc4
'
fit_cfa <- cfa(model_cfa, data = data)
summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)
# Key fit indices: CFI, RMSEA (+ 90% CI), SRMR
# Target: CFI ≥ .95, RMSEA ≤ .06, SRMR ≤ .08

# --- SEM: test structural paths ---
model_sem <- '
  # Measurement model
  privacy_concern =~ pc1 + pc2 + pc3 + pc4
  disclosure      =~ sd1 + sd2 + sd3

  # Structural path
  disclosure ~ privacy_concern
'
fit_sem <- sem(model_sem, data = data)
summary(fit_sem, fit.measures = TRUE, standardized = TRUE)

Report fit indices and standardized path coefficients (see Results chapter for reporting conventions).

For a step-by-step tutorial, see the CCS Amsterdam SEM tutorial.

19.4.8 Mediation analysis

# Using the 'mediation' package (bootstrapped indirect effects)
library(mediation)

# Step 1: model for mediator
m_model <- lm(mediator ~ predictor, data = data)

# Step 2: model for outcome
y_model <- lm(outcome ~ predictor + mediator, data = data)

# Bootstrap mediation
med_out <- mediate(m_model, y_model,
                   treat = "predictor", mediator = "mediator",
                   boot = TRUE, sims = 5000)
summary(med_out)

Alternatively, you can also use lavaan for structural equation modeling in R to run similar analyses (see this tutorial)

19.4.9 Manipulation check (experiment)

# Did participants in different conditions perceive the manipulation differently?
t.test(manipulation_check ~ condition, data = data)

# For 2x2 design
aov_result <- aov(manipulation_check ~ factor_a * factor_b, data = data)
summary(aov_result)

19.5 APA-formatted reporting in R

19.5.1 The report package

library(report)

model <- lm(outcome ~ predictor, data = data)
report(model)
# Returns a plain-language sentence you can adapt for your results section

19.5.2 The apaTables package

library(apaTables)

# APA regression table exported to Word
apa.reg.table(model1, model2,
              filename = "Table2_regression.doc")

19.5.3 papaja (APA manuscripts in Quarto/R Markdown)

If you are writing your thesis in R Markdown or Quarto, the papaja package provides APA-formatted output. Use apa_print() to inline statistics:

library(papaja)
result <- t.test(outcome ~ group, data = data)
apa_print(result)$statistic   # → "t(48) = 2.34, p = .023"

19.5.4 Visualizations with ggplot2

ggplot2 (part of the tidyverse) is the standard tool for creating publication-quality figures in R. It builds plots in layers using a consistent grammar: data → aesthetics → geometric objects.

library(ggplot2)

# Scatter plot with a regression line
ggplot(data, aes(x = predictor, y = outcome)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "lm", se = TRUE) +
  labs(title = "Effect of X on Y",
       x = "Predictor", y = "Outcome") +
  theme_minimal()

# Bar chart of group means with error bars
data |>
  group_by(condition) |>
  summarise(mean = mean(outcome), se = sd(outcome) / sqrt(n())) |>
  ggplot(aes(x = condition, y = mean, fill = condition)) +
  geom_col(width = 0.5) +
  geom_errorbar(aes(ymin = mean - se, ymax = mean + se), width = 0.2) +
  labs(x = "Condition", y = "Mean outcome") +
  theme_minimal() +
  theme(legend.position = "none")

For a comprehensive step-by-step tutorial on data visualization with ggplot2, see the CCS Amsterdam visualization tutorial.

19.6 Keeping your syntax clean

Good syntax habits matter — I need to be able to reproduce your analyses from your raw data. You can use both a standard R file (.r) or an RMarkdown file (.rmd).

# ============================================================
# MA Thesis Analysis — [Your Name] — [Date]
# ============================================================

# 0. Load packages ----
library(tidyverse)
library(psych)
library(effectsize)

# 1. Import data ----
data_raw <- haven::read_sav("data/raw_data.sav")

# 2. Data cleaning ----
# Remove incomplete responses (n = 9)
data_clean <- data_raw |>
  filter(progress == 100)

# 3. Compute scale scores ----
# Scale: Vaccine Hesitancy (α = .82 in original; check below)
data_clean <- data_clean |>
  mutate(vacc_hes = rowMeans(across(c(vh1, vh2, vh3, vh4, vh5)),
                              na.rm = TRUE))

# 4. Descriptive statistics ----
describe(data_clean[, c("vacc_hes", "soc_media_exp", "age")])

# 5. H1: Regression of social media exposure on vaccine hesitancy ----
h1_model <- lm(vacc_hes ~ soc_media_exp, data = data_clean)
summary(h1_model)
TipUse section headers in your script

The # Section ---- pattern (four dashes) creates collapsible sections in RStudio’s code outline. This keeps your syntax file navigable when it grows long.

19.7 Getting help with R code

Beyond the statistics helpdesk and Canvas resources, AI tools can be genuinely useful for R:

Task Useful approach
Debugging an error message Paste the error + relevant code into Gemini or Copilot and ask what is wrong
Finding the right function Describe what you want to do in plain English
Writing boilerplate (e.g., a for-loop) Ask AI to generate it, then check you understand it
Interpreting output Ask AI to explain what a specific output means
WarningVerify AI-generated R code

AI tools can produce plausible-looking but incorrect R code. Always run it, check the output makes sense, and make sure you understand what every line does before including results in your thesis. See Using AI Tools for the full policy.