Data wrangling with dplyr
1 Introduction
1.1 What we’ll cover
Many of the most common data analysis tasks involve working with tabular data, i.e. data with rows and columns. In this session, you’ll learn to work with tabular data in R using the dplyr package.
For example, you’ll see how to subset, manipulate and summarize a dataset — the kinds of tasks commonly referred to as “data wrangling”. Such data processing is often essential before you can move on to data visualization (next session of this workshop!) or statistical analyses.
1.2 Setting up
Use a new script for this session, much like we did for the previous one:
Open a new R script (Click the
+symbol in the toolbar at the top, then clickR Script)1.Save the script straight away as
data-wrangling.R– you can save it anywhere you like, though it is probably best to save it in a folder specifically for this workshop.If you want the section headers as comments in your script, like in the script I am showing you in the live session, then copy-and-paste the following into your script:
Section headers for your script (Click to expand)
# 1 - Introduction ------------------------------------------------------------- # 1.4 - Loading the tidyverse # 2 - The gapminder dataset ---------------------------------------------------- # Challenge 1 # The country column repeats the same country many times. # Scroll down in the View() tab: what makes each row unique? # 3 - arrange() ---------------------------------------------------------------- # Challenge 2 # Which line of code would you use to find the row with the highest # per-capita GDP? # A) arrange(.data = gapminder, desc(gdpPercap), year, country) # B) arrange(.data = gapminder, country, year, gdpPercap) # C) arrange(.data = gapminder, desc(gdpPercap)) # D) arrange(.data = gapminder, gdpPercap) # 4 - filter() ----------------------------------------------------------------- # 4.1 - Filter based on one condition # 4.2 - Filter based on multiple conditions # 5 - The pipe (|>) ------------------------------------------------------------ # Challenge 3 # The pipeline below is supposed to find the 3 countries with the lowest # GDP per capita in 1997, sorted from lowest to highest. # It has two errors. Find and fix them: gapminder filter(year = 1997) |> arrange(gdpPercap) |> head(n = 3) # Challenge 4 # Using filter(), arrange(), and the pipe (|>), answer the following: # A) Which African country had the highest life expectancy in 2002? # B) What was the smallest population recorded in Asia across all years? # 6 - mutate() ----------------------------------------------------------------- # Challenge 5 # Use mutate() to create a new column gdp_billion that has the absolute GDP # (i.e., not relative to population size) in units of billions. gapminder |> mutate(______) # 7 - summarize() -------------------------------------------------------------- # Challenge 6 # A) Calculate the average life expectancy for each country and store the # result in a new data frame. gapminder |> ______ |> ______ # B) Use the data frame you just created to find out which country has the # longest average life expectancy and which has the shortest.
1.3 The dplyr package and the tidyverse
One of R’s most powerful features is its ability to deal with tabular data. That is, data with rows and columns like those familiar from Excel spreadsheets and so on. R stores tabular data in a data structure called a “data frame”.
The dplyr package provides useful functions for manipulating data in data frames. In this session, we’ll cover the following commonly used dplyr functions:
arrange()to change the order of rows (i.e., to sort a data frame)filter()to keep only a subset of rowsmutate()to manipulate columns and create new columnssummarize()to compute data summaries across rows (if we have time)
dplyr has many more functions, and we encourage you to explore these on your own: bonus material on this site / dplyr documentation.
dplyr, in turn, belongs to the “tidyverse”, a family of R packages for data science. Another key tidyverse package we’ll cover in today’s workshop is ggplot2 for making plots.
1.4 Loading the tidyverse
You should have the tidyverse already installed, but in every new R session, you need to load it before you can use it. Let’s do that now:
library(tidyverse)── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
The output tells you which packages have been loaded as part of the tidyverse. (For now, you don’t have to pay attention to the “Conflicts” section.)
install.packages("tidyverse")
install.packages("gapminder")2 The gapminder dataset
In this session and the next one, we will work with the gapminder dataset. This dataset contains statistics such as population size and life expectancy for 142 countries, at five-year intervals from 1952 to 2007.
It is available in a package of the same name. Like with the tidyverse, you should have it installed but do, as always, need to load it:
# (Unlike with the tidyverse, no output is expected when you load gapminder)
library(gapminder)Take a look at the gapminder data frame that is now available to you:
gapminder# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
Above, the gapminder data frame is referred to as a “tibble”, which is the tidyverse’s version of a data frame, with a few small differences2.
Only the first 10 rows are printed, and the dataset has the following columns:
| column name | data type | meaning |
|---|---|---|
country |
factor (<fct>) |
Country |
continent |
factor (<fct>) |
Continent that the country is in |
year |
integer (<int>) |
Focal year for the stats in the next columns |
lifeExp |
double (<dbl>) |
Mean life expectancy in years |
pop |
integer (<int>) |
Population size |
gdpPercap |
double (<dbl>) |
Per-capita GDP |
Two columns are of type factor, an alternative to character commonly used for categorical data.
You can also use the View() function to look at the data frame. This will open a new tab in your editor pane with a spreadsheet-like look and feel:
View(gapminder)
# (Should display the dataset in an editor pane tab) Challenge 1: Explore the gapminder dataset
The country column repeats the same country many times. Scroll down in the View() tab: what makes each row unique?
Each row is one country in one year. Afghanistan, for example, takes up 12 rows: one for each year from 1952 to 2007, in five-year steps.
3 arrange()
The arrange() function is like sorting functionality in Excel: it changes the order of rows based on the values in one or more columns. Entire rows are always moved together: it never reorders the values within a single column on its own, because that would scramble the data.
gapminder is currently first sorted alphabetically by country, and next by year. You may want to sort, for example, by population size instead, and can do so with arrange() as follows:
gm_arranged <- arrange(.data = gapminder, pop)Before we take a look at the result, let’s break down the syntax of the arrange() function:
- The first argument is the data frame to be sorted, which we specify with the
.dataargument. - The second argument is the column to sort by, which we specify without an argument name.
Like all dplyr functions, arrange() outputs a new data frame, and does not modify the input data frame. In this case, we chose to assign the output to a new object called gm_arranged.
What would have happened if we had assigned the output to gapminder?
In that case, the original data frame would have been overwritten with the sorted version.
Finally, let’s look at the result of the sorting:
gm_arranged# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Sao Tome and Principe Africa 1952 46.5 60011 880.
2 Sao Tome and Principe Africa 1957 48.9 61325 861.
3 Djibouti Africa 1952 34.8 63149 2670.
4 Sao Tome and Principe Africa 1962 51.9 65345 1072.
5 Sao Tome and Principe Africa 1967 54.4 70787 1385.
6 Djibouti Africa 1957 37.3 71851 2865.
7 Sao Tome and Principe Africa 1972 56.5 76595 1533.
8 Sao Tome and Principe Africa 1977 58.6 86796 1738.
9 Djibouti Africa 1962 39.7 89898 3021.
10 Sao Tome and Principe Africa 1982 60.4 98593 1890.
# ℹ 1,694 more rows
Sorting helps you find observations with the smallest or largest values for a certain column: above, we see that the dataset’s smallest population size is from Sao Tome and Principe in 1952.
Default sorting is from small to large, as seen above. To sort in reverse order, use the desc() (descending) helper function:
arrange(.data = gapminder, desc(pop))# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 China Asia 2007 73.0 1318683096 4959.
2 China Asia 2002 72.0 1280400000 3119.
3 China Asia 1997 70.4 1230075000 2289.
4 China Asia 1992 68.7 1164970000 1656.
5 India Asia 2007 64.7 1110396331 2452.
6 China Asia 1987 67.3 1084035000 1379.
7 India Asia 2002 62.9 1034172547 1747.
8 China Asia 1982 65.5 1000281000 962.
9 India Asia 1997 61.8 959000000 1459.
10 China Asia 1977 64.0 943455000 741.
# ℹ 1,694 more rows
Here, we didn’t assign the output to a new object, so it was just printed to screen. We’ll keep doing that for the remainder of the session, so we can more easily see the results of our operations.
Finally, you may want to sort by multiple columns, where ties in the first column are broken by a second column (and so on). Do this by simply listing the columns in the appropriate order:
# Sort first by continent, then by country:
arrange(.data = gapminder, continent, country)# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Algeria Africa 1952 43.1 9279525 2449.
2 Algeria Africa 1957 45.7 10270856 3014.
3 Algeria Africa 1962 48.3 11000948 2551.
4 Algeria Africa 1967 51.4 12760499 3247.
5 Algeria Africa 1972 54.5 14760787 4183.
6 Algeria Africa 1977 58.0 17152804 4910.
7 Algeria Africa 1982 61.4 20033753 5745.
8 Algeria Africa 1987 65.8 23254956 5681.
9 Algeria Africa 1992 67.7 26298373 5023.
10 Algeria Africa 1997 69.2 29072015 4797.
# ℹ 1,694 more rows
Pay attention to the syntax: additional columns to sort by are additional arguments to the function, not part of the same argument with c(). Other dplyr functions work the same way.
Challenge 2: arrange()
One observation (row) in the gapminder dataset has the highest per-capita GDP. Which line of code would you use to find out which row that is?
Try it, and report which row (which country and year) you found.
The best answer is C. While both A and C give you the row with the highest per-capita GDP, A will also sort the entire dataset by year and country, which is not necessary to answer the question.
Most importantly, you want to sort by gdpPercap in descending order, so the row with the highest value ends up at the top:
arrange(.data = gapminder, desc(gdpPercap))# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Kuwait Asia 1957 58.0 212846 113523.
2 Kuwait Asia 1972 67.7 841934 109348.
3 Kuwait Asia 1952 55.6 160000 108382.
4 Kuwait Asia 1962 60.5 358266 95458.
5 Kuwait Asia 1967 64.6 575003 80895.
6 Kuwait Asia 1977 69.3 1140357 59265.
7 Norway Europe 2007 80.2 4627926 49357.
8 Kuwait Asia 2007 77.6 2505559 47307.
9 Singapore Asia 2007 80.0 4553009 47143.
10 Norway Europe 2002 79.0 4535591 44684.
# ℹ 1,694 more rows
Kuwait in 1957 had the highest per-capita GDP in the dataset, at $113,523.
4 filter()
The filter() function outputs only those rows that satisfy one or more conditions. It is similar to filtering functionality in Excel.
4.1 Filter based on one condition
This first filter() example outputs only rows for which the life expectancy exceeds 80 years (remember, each row represents a country in a given year):
filter(.data = gapminder, lifeExp > 80)# A tibble: 21 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Australia Oceania 2002 80.4 19546792 30688.
2 Australia Oceania 2007 81.2 20434176 34435.
3 Canada Americas 2007 80.7 33390141 36319.
4 France Europe 2007 80.7 61083916 30470.
5 Hong Kong, China Asia 2002 81.5 6762476 30209.
6 Hong Kong, China Asia 2007 82.2 6980412 39725.
7 Iceland Europe 2002 80.5 288030 31163.
8 Iceland Europe 2007 81.8 301931 36181.
9 Israel Asia 2007 80.7 6426679 25523.
10 Italy Europe 2002 80.2 57926999 27968.
# ℹ 11 more rows
How many rows were output? (Click to see the answer)
21 rows were output. This is most easily seen in the first line of the output (21 x 6, i.e. 21 rows and 6 columns).
As the example above demonstrated, filter() outputs rows that satisfy the condition(s) you specify. These conditions don’t have to be based on numeric comparisons:
# Only keep rows where the value in the 'continent' column is 'Europe':
filter(.data = gapminder, continent == "Europe")# A tibble: 360 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Albania Europe 1952 55.2 1282697 1601.
2 Albania Europe 1957 59.3 1476505 1942.
3 Albania Europe 1962 64.8 1728137 2313.
4 Albania Europe 1967 66.2 1984060 2760.
5 Albania Europe 1972 67.7 2263554 3313.
6 Albania Europe 1977 68.9 2509048 3533.
7 Albania Europe 1982 70.4 2780097 3631.
8 Albania Europe 1987 72 3075321 3739.
9 Albania Europe 1992 71.6 3326498 2497.
10 Albania Europe 1997 73.0 3428038 3193.
# ℹ 350 more rows
Remember to use two equals signs == to test for equality!
4.2 Filter based on multiple conditions
It’s also possible to filter based on multiple conditions. For example, you may want to see which countries in Asia had a life expectancy greater than 80 years:
filter(.data = gapminder, continent == "Asia", lifeExp > 80)# A tibble: 6 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Hong Kong, China Asia 2002 81.5 6762476 30209.
2 Hong Kong, China Asia 2007 82.2 6980412 39725.
3 Israel Asia 2007 80.7 6426679 25523.
4 Japan Asia 1997 80.7 125956499 28817.
5 Japan Asia 2002 82 127065841 28605.
6 Japan Asia 2007 82.6 127467972 31656.
As in the example above, multiple conditions are by default combined using a Boolean AND. In other words, in a given row, each condition must be met to output the row.
If you want to combine conditions using a Boolean OR, where only one of the conditions needs to be met, use a | (vertical bar) between the conditions:
# Keep rows with a high life expectancy and/or a high per-capita GDP:
filter(.data = gapminder, lifeExp > 80 | gdpPercap > 100000)# A tibble: 24 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Australia Oceania 2002 80.4 19546792 30688.
2 Australia Oceania 2007 81.2 20434176 34435.
3 Canada Americas 2007 80.7 33390141 36319.
4 France Europe 2007 80.7 61083916 30470.
5 Hong Kong, China Asia 2002 81.5 6762476 30209.
6 Hong Kong, China Asia 2007 82.2 6980412 39725.
7 Iceland Europe 2002 80.5 288030 31163.
8 Iceland Europe 2007 81.8 301931 36181.
9 Israel Asia 2007 80.7 6426679 25523.
10 Italy Europe 2002 80.2 57926999 27968.
# ℹ 14 more rows
5 The pipe (|>)
The examples so far applied a single dplyr function to a data frame. But in practice, it’s common to use several consecutive dplyr functions to wrangle a data frame into the format you want.
For example, you may want to filter rows and then sort the result. You could do that as follows:
gm_filt <- filter(.data = gapminder, lifeExp < 50)
arrange(.data = gm_filt, desc(pop))# A tibble: 491 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 China Asia 1962 44.5 665770000 488.
2 China Asia 1952 44 556263527 400.
3 India Asia 1967 47.2 506000000 701.
4 India Asia 1962 43.6 454000000 658.
5 India Asia 1957 40.2 409000000 590.
6 India Asia 1952 37.4 372000000 547.
7 Nigeria Africa 2007 46.9 135031164 2014.
8 Indonesia Asia 1972 49.2 121282000 1111.
9 Nigeria Africa 2002 46.6 119901274 1615.
10 Indonesia Asia 1967 46.0 109343000 762.
# ℹ 481 more rows
And you could go on like this, successively creating new objects you use for the next step. But there is a more elegant way of doing this!
You can directly send (“pipe”) output from one function into the next function with the pipe operator |>, which is a vertical bar | followed by a greater-than sign >.
Let’s start by seeing a rephrasing of the code above, now using pipes:
gapminder |>
filter(lifeExp < 50) |>
arrange(desc(pop))# A tibble: 491 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 China Asia 1962 44.5 665770000 488.
2 China Asia 1952 44 556263527 400.
3 India Asia 1967 47.2 506000000 701.
4 India Asia 1962 43.6 454000000 658.
5 India Asia 1957 40.2 409000000 590.
6 India Asia 1952 37.4 372000000 547.
7 Nigeria Africa 2007 46.9 135031164 2014.
8 Indonesia Asia 1972 49.2 121282000 1111.
9 Nigeria Africa 2002 46.6 119901274 1615.
10 Indonesia Asia 1967 46.0 109343000 762.
# ℹ 481 more rows
What happened here? We took the gapminder data frame, sent (“piped”) it into the filter() function, whose output in turn was piped into the arrange() function. You can think of the pipe as “then”: take gapminder, then filter, then arrange.
When using the pipe, you no longer specify the input data frame with the .data argument, because the function now gets its input data via the pipe3.
Using pipes involves less typing and, above all, is more readable than using successive assignments4.
For code readability, it is good practice to always start a new line after a pipe |>, and to keep the subsequent line(s) indented as RStudio will automatically do.
Challenge 3: Find the mistakes
The below “pipeline” is supposed to find the 3 countries with the lowest GDP per capita in 1997, sorted from lowest to highest. It has two errors. Find and fix them:
The two errors are:
- Line 1: Missing pipe
|>after gapminder - Line 2: Should use
==(not=) to test for equality
Corrected code:
gapminder |>
filter(year == 1997) |>
arrange(gdpPercap) |>
head(n = 3)# A tibble: 3 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Congo, Dem. Rep. Africa 1997 42.6 47798986 312.
2 Myanmar Asia 1997 60.3 43247867 415
3 Burundi Africa 1997 45.3 6121610 463.
Challenge 4: Find the extremes
Using filter(), arrange(), and the pipe (|>), answer the following questions about the gapminder dataset:
- Which African country had the highest life expectancy in 2002?
We’ll use the same head() trick as in the exercise above to see only the top country, but this is not strictly necessary:
gapminder |>
filter(continent == "Africa", year == 2002) |>
arrange(desc(lifeExp)) |>
head(n = 1)# A tibble: 1 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Reunion Africa 2002 75.7 743981 6316.
- What was the smallest population recorded in Asia across all years?
gapminder |>
filter(continent == "Asia") |>
arrange(pop) |>
head(n = 1)# A tibble: 1 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Bahrain Asia 1952 50.9 120447 9867.
6 mutate()
So far, we’ve focused on functions that subset and reorganize data frames. But we haven’t yet seen how to change the data or compute derived data. This can be done with the mutate() function.
For example, to create a new column with population sizes in millions:
# Create a new column 'pop_million' by dividing 'pop' by a million:
gapminder |>
mutate(pop_million = pop / 10^6)# A tibble: 1,704 × 7
country continent year lifeExp pop gdpPercap pop_million
<fct> <fct> <int> <dbl> <int> <dbl> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779. 8.43
2 Afghanistan Asia 1957 30.3 9240934 821. 9.24
3 Afghanistan Asia 1962 32.0 10267083 853. 10.3
4 Afghanistan Asia 1967 34.0 11537966 836. 11.5
5 Afghanistan Asia 1972 36.1 13079460 740. 13.1
6 Afghanistan Asia 1977 38.4 14880372 786. 14.9
7 Afghanistan Asia 1982 39.9 12881816 978. 12.9
8 Afghanistan Asia 1987 40.8 13867957 852. 13.9
9 Afghanistan Asia 1992 41.7 16317921 649. 16.3
10 Afghanistan Asia 1997 41.8 22227415 635. 22.2
# ℹ 1,694 more rows
To modify an existing column rather than adding a new one, simply “assign back to the same name”:
# Change the unit of the 'pop' column:
gapminder |>
mutate(pop = pop / 10^6)# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <dbl> <dbl>
1 Afghanistan Asia 1952 28.8 8.43 779.
2 Afghanistan Asia 1957 30.3 9.24 821.
3 Afghanistan Asia 1962 32.0 10.3 853.
4 Afghanistan Asia 1967 34.0 11.5 836.
5 Afghanistan Asia 1972 36.1 13.1 740.
6 Afghanistan Asia 1977 38.4 14.9 786.
7 Afghanistan Asia 1982 39.9 12.9 978.
8 Afghanistan Asia 1987 40.8 13.9 852.
9 Afghanistan Asia 1992 41.7 16.3 649.
10 Afghanistan Asia 1997 41.8 22.2 635.
# ℹ 1,694 more rows
Challenge 5: Absolute GDP
Use mutate() to create a new column gdp_billion that has the absolute GDP (i.e., not relative to population size) in units of billions.
gapminder |>
mutate(gdp_billion = gdpPercap * ______ / ______)You need to do two things, which can be combined into a single line:
- Make the GDP absolute by multiplying by the population size:
gdpPercap * pop - Change the unit of the absolute GDP to billions by dividing by a billion:
/ 10^9
gapminder |>
mutate(gdp_billion = gdpPercap * pop / 10^9)# A tibble: 1,704 × 7
country continent year lifeExp pop gdpPercap gdp_billion
<fct> <fct> <int> <dbl> <int> <dbl> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779. 6.57
2 Afghanistan Asia 1957 30.3 9240934 821. 7.59
3 Afghanistan Asia 1962 32.0 10267083 853. 8.76
4 Afghanistan Asia 1967 34.0 11537966 836. 9.65
5 Afghanistan Asia 1972 36.1 13079460 740. 9.68
6 Afghanistan Asia 1977 38.4 14880372 786. 11.7
7 Afghanistan Asia 1982 39.9 12881816 978. 12.6
8 Afghanistan Asia 1987 40.8 13867957 852. 11.8
9 Afghanistan Asia 1992 41.7 16317921 649. 10.6
10 Afghanistan Asia 1997 41.8 22227415 635. 14.1
# ℹ 1,694 more rows
7 summarize() (If we have time)
The final dplyr function we’ll cover is summarize(), which computes summaries of your data across rows. For example, to calculate the mean GDP across the entire dataset:
# The syntax is similar to 'mutate': <new-column> = <operation>
gapminder |>
summarize(mean_gdp = mean(gdpPercap))# A tibble: 1 × 1
mean_gdp
<dbl>
1 7215.
The output is still a data frame, but unlike with the previous dplyr functions, its rows are not the rows of the input: summarize() “collapses” the data down, here to a single number.
summarize() becomes really powerful in combination with group_by(), which lets you compute groupwise stats. For example, to get the mean GDP separately for each continent:
gapminder |>
group_by(continent) |>
summarize(mean_gdp = mean(gdpPercap))# A tibble: 5 × 2
continent mean_gdp
<fct> <dbl>
1 Africa 2194.
2 Americas 7136.
3 Asia 7902.
4 Europe 14469.
5 Oceania 18622.
group_by() implicitly splits a data frame into groups of rows: here, one group for observations from each continent. After that, operations like in summarize() will happen separately for each group, which is how we ended up with per-continent means.
Challenge 6: Mean life expectancy
- Calculate the average life expectancy for each country and store the result in a new data frame.
lifeExp_bycountry <- gapminder |>
group_by(______) |>
summarize(mean_lifeExp = ______)First, create a data frame with the mean life expectancy by country:
lifeExp_bycountry <- gapminder |>
group_by(country) |>
summarize(mean_lifeExp = mean(lifeExp))- Use the data frame you just created to find out which country has the longest average life expectancy and which has the shortest.
Sort the data frame twice, once in each direction, to see the countries with the shortest and the longest life expectancy. You could optionally pipe into head() to only see the top n, here top 1:
lifeExp_bycountry |>
arrange(mean_lifeExp) |>
head(n = 1)# A tibble: 1 × 2
country mean_lifeExp
<fct> <dbl>
1 Sierra Leone 36.8
lifeExp_bycountry |>
arrange(desc(mean_lifeExp)) |>
head(n = 1)# A tibble: 1 × 2
country mean_lifeExp
<fct> <dbl>
1 Iceland 76.5
So, Sierra Leone has the shortest average life expectancy (36.8 years), and Iceland has the longest average life expectancy (76.5 years).
Footnotes
Or click
File=>New file=>R Script.↩︎The main difference is the nicer default printing behavior of tibbles: e.g. the data types of columns are shown, and only a limited number of rows are printed.↩︎
Specifically, the input goes to the function’s first argument by default.↩︎
Using pipes also avoids cluttering your environment with intermediate objects, which saves computer memory.↩︎