Optional: More tidyverse

These sections continue from Working with Tidyverse. They use the same data and R script, and build on the sgvp_flag data frame we created in section 4.

6. Summarising by group

group_by() splits the data into groups. Any summarise() that comes after it is calculated separately for each group, giving one row per group.

Volunteering rate for each age group:

rate_by_age <- sgvp_flag |>
  group_by(age_group) |>
  summarise(
    people        = n(),
    weighted_rate = weighted.mean(volunteer_flag, weight)
  )

You can group by more than one column. This gives one row for every combination of age group and gender:

rate_by_age_gender <- sgvp_flag |>
  group_by(age_group, gender) |>
  summarise(
    people        = n(),
    weighted_rate = weighted.mean(volunteer_flag, weight),
    .groups       = "drop"  # remove the grouping when we're done
  )

7. Sorting

arrange() sorts the rows by the values in a column, smallest to largest:

rate_lowest_first <- rate_by_age |>
  arrange(weighted_rate)

Put the column inside desc() to sort from largest to smallest:

rate_highest_first <- rate_by_age |>
  arrange(desc(weighted_rate))

You can sort by more than one column. This sorts by gender first, then by rate (largest first) within each gender:

rate_by_gender_sorted <- rate_by_age_gender |>
  arrange(gender, desc(weighted_rate))

arrange() on a text column sorts alphabetically. It can’t put education levels in a custom order like “Less than high school” first. For that we need factors (next section).

8. Putting categories in order

Volunteering rate for each education level:

rate_by_education <- sgvp_flag |>
  group_by(education) |>
  summarise(
    people        = n(),
    weighted_rate = weighted.mean(volunteer_flag, weight)
  )

Look at the order of the rows. R has sorted the education levels alphabetically, which isn’t intuitive here!

A factor is R’s version of a categorical variable. Unlike plain text, a factor keeps a list of its categories (called levels) in a fixed order, and R uses that order in tables and plots.

sgvp_education <- sgvp_flag |>
  filter(education != "Not stated") |>    # != means "is not equal to"
  mutate(education = fct_relevel(education,
                                 "Less than high school",
                                 "Graduated from high school",
                                 "Post-secondary diploma",
                                 "University diploma"))

The category names must match the data exactly. If you make a typo, R will warn you about an “unknown level”.

Now the summary makes more sense!

rate_by_education <- sgvp_education |>
  group_by(education) |>
  summarise(
    people        = n(),
    weighted_rate = weighted.mean(volunteer_flag, weight)
  )

9. Reshaping data

rate_by_age_gender is in long format. To compare men and women, it is easier to have them side by side, in wide format.

pivot_wider() spreads one column out into several:

  • names_from: the column whose values become the new column names
  • values_from: the column whose values fill in the new columns
rate_wide <- rate_by_age_gender |>
  select(age_group, gender, weighted_rate) |>
  pivot_wider(names_from = gender, values_from = weighted_rate)

pivot_longer() does the reverse: it gathers several columns into one.

10. Joining data

A join combines two datasets by matching rows on a column they share.

rate_wide has the rate for each gender, and rate_by_age has the rate for everyone. Let’s put them in one table, matching rows on age_group.

First, keep the columns we need and give the rate a better name with rename(). For rename(), the new name goes on the left and the old name on the right:

rate_everyone <- rate_by_age |>
  select(age_group, weighted_rate) |>
  rename(everyone = weighted_rate)

left_join() keeps every row of the first dataset and adds the matching columns from the second:

rate_table <- rate_wide |>
  left_join(rate_everyone, by = "age_group")

View in GitHub

Loading last updated date...