R · Intermediate
The tidyverse in an afternoon
Why it matters
R appeared in a third of the Data Scientist job descriptions we read, especially in banking risk, pharmaceuticals, public health and research-heavy teams. You do not need to master both R and Python, but reading and extending R code is a common expectation in those teams.
The concept
The tidyverse is a family of R packages built around tidy data: one row per observation, one column per variable.
| task | tidyverse | pandas equivalent |
|---|---|---|
| read a file | read_csv(), read_delim() | pd.read_csv() |
| keep rows | filter() | boolean mask |
| add columns | mutate() | assign() |
| group and summarise | group_by() |> summarise() | groupby().agg() |
| sort | arrange() | sort_values() |
| plot | ggplot() | matplotlib or seaborn |
The native pipe |> passes the result of one step into the next, so analysis reads top to bottom. Statistical models such as lm() and glm() are built into base R and use formulas: y ~ x1 + x2.
Worked example: the bank marketing calls
Install R and, in an R session, install.packages(c("readr", "dplyr", "ggplot2")). Then with bank-full.csv from the UCI Bank Marketing data (CC BY 4.0):
library(readr)
library(dplyr)
library(ggplot2)
bank <- read_delim("bank-full.csv", delim = ";", show_col_types = FALSE)
by_outcome <- bank |>
group_by(poutcome) |>
summarise(calls = n(), subscribed = mean(y == "yes")) |>
arrange(desc(subscribed))
print(by_outcome)
model <- glm(I(y == "yes") ~ age + balance + contact + poutcome + housing + loan,
data = bank, family = binomial)
print(round(exp(coef(model)), 2)) # odds ratios
plot <- ggplot(by_outcome, aes(x = reorder(poutcome, subscribed), y = subscribed)) +
geom_col(fill = "grey60") +
coord_flip() +
scale_y_continuous(labels = scales::percent) +
labs(x = "Previous campaign outcome", y = "Subscription rate",
title = "Previous success is the strongest signal")
ggsave("by_outcome.png", plot, width = 6, height = 3.5)Run it with Rscript bank.R:
| poutcome | calls | subscribed |
|---|---|---|
| success | 1,511 | 64.7% |
| other | 1,840 | 16.7% |
| failure | 4,901 | 12.6% |
| unknown | 36,959 | 9.2% |
The logistic regression reports odds ratios relative to the reference level, which R picks alphabetically (failure for poutcome, cellular for contact). A previous success multiplies the odds of subscribing by about 9.9 compared with a previous failure, holding the other variables fixed. Having a housing loan roughly halves the odds (0.51).
Notice that the whole analysis, from file to chart, is 25 lines. That economy is why statisticians like R.
Common mistakes
Forgetting the reference level. Odds ratios are relative to it. Set it on purpose with
relevel().Loading
dplyrafter other packages and being surprised by masking.filterandlagshadow base functions; the messages on load tell you so.Growing data frames in loops. Use vectorised
mutate()orpurrr, as you would avoiditerrows()in pandas.Charts without a message.
labs(title = ...)should state the finding, as in the example.
Interview angle
If a job asks for "R or Python", say which you are stronger in and show you can read the other. Explaining odds ratios from a glm output, including the reference level, is a common statistics interview question in banking and pharma.
Practice task
Rebuild
by_outcomein pandas and check the numbers match.Relevel
poutcomesounknownis the reference and reinterpret the odds ratios.Add a ggplot of subscription rate by age band, faceted by
housing.