R · Intermediate

The tidyverse in an afternoon

3 min read

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.

tasktidyversepandas equivalent
read a fileread_csv(), read_delim()pd.read_csv()
keep rowsfilter()boolean mask
add columnsmutate()assign()
group and summarisegroup_by() |> summarise()groupby().agg()
sortarrange()sort_values()
plotggplot()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):

bank.R
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:

poutcomecallssubscribed
success1,51164.7%
other1,84016.7%
failure4,90112.6%
unknown36,9599.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 dplyr after other packages and being surprised by masking. filter and lag shadow base functions; the messages on load tell you so.

  • Growing data frames in loops. Use vectorised mutate() or purrr, as you would avoid iterrows() 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

  1. Rebuild by_outcome in pandas and check the numbers match.

  2. Relevel poutcome so unknown is the reference and reinterpret the odds ratios.

  3. Add a ggplot of subscription rate by age band, faceted by housing.

Further reading