# if you haven't installed the tidyverse yet, uncomment the next line and run it once:
# install.packages("tidyverse")
# Load the tidyverse packages, including tibble and dplyr.
library(tidyverse)Lab 2: Tibbles and Basic Data Manipulation
Working with rectangular data using dplyr
Learning goals
By the end of this lab, you should be able to create and inspect a tibble, use the base R pipe (|>), and manipulate a small dataset with dplyr.
R Console
The R Console is where R receives and runs commands. A > at the left of a line is the R prompt: it means R is ready for you to type a command. You can try the code from this lab at that prompt, one command at a time. In this Quarto document, code inside an R code chunk (the sections between ```{r} and ```) runs the same way when you render the document.
Get help in the R Console
R includes help pages for functions and packages. At the > prompt in the Console, type ?function_name to open a function help page. For example, ?filter explains how filter() works. You can write the same request as help("filter").
If you do not know the exact name, type ??search_term to search the installed help files. For example, ??"data frame" searches for help about data frames. To learn about an installed package, use help(package = "dplyr") or help(package = "tidyverse").
1. Load the tidyverse
The tidyverse is a collection of R packages used for working with data. In this lab, we will use tibble to create a dataset and dplyr to transform it. library() makes the functions in a package available for this R session.
2. Create and inspect a tibble
A tibble is a modern version of an R data frame: a rectangular table with rows and columns. Rows are observations (one student here), and columns are variables (one characteristic measured for every student). tibble() creates a tibble, and each column below is given a name and a vector of six values.
A data frame and a tibble store the same kind of rectangular data, and both are useful. A data frame is built into base R; a tibble comes from the tidyverse. Tibbles are designed to be easier to read: when printed, they show only the first rows and the columns that fit on screen, along with each column’s data type. Tibbles also preserve the column names and data types you give them. In this lab, we use tibbles because they work especially well with dplyr.
# Create a tibble named students.
students <- tibble(
name = c("Avery", "Blair", "Casey", "Devon", "Emery", "Frankie"),
major = c("Data Science", "Business", "Data Science", "Psychology", "Business", "Data Science"),
class_year = c("First-year", "Sophomore", "Junior", "Senior", "First-year", "Junior"),
course_modality = c("Online", "In person", "Online", "In person", "Online", "In person"),
hours_studied = c(6, 4, 8, 5, 7, 3),
attendance_rate = c(92, 78, 96, 88, 91, 85),
quiz_score = c(88, 76, 95, 84, 91, 79)
)
# Print the full tibble in the rendered document.
students# A tibble: 6 × 7
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Avery Data Science First-year Online 6 92
2 Blair Business Sophomore In person 4 78
3 Casey Data Science Junior Online 8 96
4 Devon Psychology Senior In person 5 88
5 Emery Business First-year Online 7 91
6 Frankie Data Science Junior In person 3 85
# ℹ 1 more variable: quiz_score <dbl>
# Quickly inspect the column names, data types, and a few values in each column.
glimpse(students)Rows: 6
Columns: 7
$ name <chr> "Avery", "Blair", "Casey", "Devon", "Emery", "Frankie"
$ major <chr> "Data Science", "Business", "Data Science", "Psycholog…
$ class_year <chr> "First-year", "Sophomore", "Junior", "Senior", "First-…
$ course_modality <chr> "Online", "In person", "Online", "In person", "Online"…
$ hours_studied <dbl> 6, 4, 8, 5, 7, 3
$ attendance_rate <dbl> 92, 78, 96, 88, 91, 85
$ quiz_score <dbl> 88, 76, 95, 84, 91, 79
students$quiz_score extracts the quiz_score column. The pipe, |>, sends the data on its left into the function on its right. For example, students |> filter(quiz_score >= 85) means “start with students, then keep the rows whose quiz score is at least 85.”
3. Create, filter, sort, and summarize
# mutate() creates a new column or changes an existing column.
# pmin() compares each score with 100, so no score can exceed 100.
students |>
mutate(score_after_bonus = pmin(quiz_score + 2, 100))# A tibble: 6 × 8
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Avery Data Science First-year Online 6 92
2 Blair Business Sophomore In person 4 78
3 Casey Data Science Junior Online 8 96
4 Devon Psychology Senior In person 5 88
5 Emery Business First-year Online 7 91
6 Frankie Data Science Junior In person 3 85
# ℹ 2 more variables: quiz_score <dbl>, score_after_bonus <dbl>
# filter() keeps only rows that meet a condition.
# This keeps students with a quiz score of 85 or higher.
students |>
filter(quiz_score >= 85)# A tibble: 3 × 7
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Avery Data Science First-year Online 6 92
2 Casey Data Science Junior Online 8 96
3 Emery Business First-year Online 7 91
# ℹ 1 more variable: quiz_score <dbl>
# arrange() sorts rows. desc() means descending order, from highest to lowest.
students |>
arrange(desc(hours_studied))# A tibble: 6 × 7
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Casey Data Science Junior Online 8 96
2 Emery Business First-year Online 7 91
3 Avery Data Science First-year Online 6 92
4 Devon Psychology Senior In person 5 88
5 Blair Business Sophomore In person 4 78
6 Frankie Data Science Junior In person 3 85
# ℹ 1 more variable: quiz_score <dbl>
# summarise() reduces many rows to a small set of summary values.
# mean() calculates the arithmetic average of a numeric column.
students |>
summarise(
average_score = mean(quiz_score),
average_hours = mean(hours_studied)
)# A tibble: 1 × 2
average_score average_hours
<dbl> <dbl>
1 85.5 5.5
Build a pipeline step by step
A pipeline can look like one long command, but it is simply a sequence of small steps. Run each block below in order and compare the output. The output from one step becomes the input for the next step.
Start with the complete students tibble.
students# A tibble: 6 × 7
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Avery Data Science First-year Online 6 92
2 Blair Business Sophomore In person 4 78
3 Casey Data Science Junior Online 8 96
4 Devon Psychology Senior In person 5 88
5 Emery Business First-year Online 7 91
6 Frankie Data Science Junior In person 3 85
# ℹ 1 more variable: quiz_score <dbl>
Next, add filter(). The pipe sends students to filter(), which keeps only students who studied at least five hours.
students |>
filter(hours_studied >= 5)# A tibble: 4 × 7
name major class_year course_modality hours_studied attendance_rate
<chr> <chr> <chr> <chr> <dbl> <dbl>
1 Avery Data Science First-year Online 6 92
2 Casey Data Science Junior Online 8 96
3 Devon Psychology Senior In person 5 88
4 Emery Business First-year Online 7 91
# ℹ 1 more variable: quiz_score <dbl>
Finally, add another pipe and select(). select() keeps just the name and quiz_score columns from the already filtered result.
students |>
filter(hours_studied >= 5) |>
select(name, quiz_score)# A tibble: 4 × 2
name quiz_score
<chr> <dbl>
1 Avery 88
2 Casey 95
3 Devon 84
4 Emery 91
Read the finished pipeline from top to bottom: start with students, keep rows where hours_studied is at least 5, then keep only name and quiz_score.
Practice
Write a pipeline that keeps students with an attendance_rate of at least 90, sorts them from highest to lowest quiz_score, and then selects only name, major, attendance_rate, and quiz_score.
# Write your solution here
students %>%
filter(attendance_rate >= 90) %>%
arrange(desc(quiz_score)) %>%
select(name, major, attendance_rate, quiz_score)# A tibble: 3 × 4
name major attendance_rate quiz_score
<chr> <chr> <dbl> <dbl>
1 Casey Data Science 96 95
2 Emery Business 91 91
3 Avery Data Science 92 88
Reflection
In 2-3 sentences, describe what the pipe does and why a tibble is useful for data analysis.
The pipe (%>% or |>) passes the output from one step to the next, which makes the code easier to read.
The tibble displays data cleanly and works especially well with dplyr and other tidyverse tools.
Optional exploration: import a built-in dataset
Try working with a larger dataset included with ggplot2, one of the packages installed with tidyverse. The mpg dataset contains information about car models and fuel economy. Run the following code, then use glimpse() to see its columns and data types.
# Load the mpg dataset from the ggplot2 package.
data("mpg", package = "ggplot2")
## is mpg a tibble? Check with is_tibble().
is_tibble(mpg)[1] TRUE
# View and inspect the imported dataset.
mpg# A tibble: 234 × 11
manufacturer model displ year cyl trans drv cty hwy fl class
<chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
1 audi a4 1.8 1999 4 auto… f 18 29 p comp…
2 audi a4 1.8 1999 4 manu… f 21 29 p comp…
3 audi a4 2 2008 4 manu… f 20 31 p comp…
4 audi a4 2 2008 4 auto… f 21 30 p comp…
5 audi a4 2.8 1999 6 auto… f 16 26 p comp…
6 audi a4 2.8 1999 6 manu… f 18 26 p comp…
7 audi a4 3.1 2008 6 auto… f 18 27 p comp…
8 audi a4 quattro 1.8 1999 4 manu… 4 18 26 p comp…
9 audi a4 quattro 1.8 1999 4 auto… 4 16 25 p comp…
10 audi a4 quattro 2 2008 4 manu… 4 20 28 p comp…
# ℹ 224 more rows
glimpse(mpg)Rows: 234
Columns: 11
$ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "audi", "…
$ model <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 quattro", "…
$ displ <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0, 2.0, 2.…
$ year <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1999, 200…
$ cyl <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, 8, …
$ trans <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)", "auto…
$ drv <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4", "4", "4…
$ cty <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 17, 17, 1…
$ hwy <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 25, 25, 2…
$ fl <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p…
$ class <chr> "compact", "compact", "compact", "compact", "compact", "c…
In 2-3 sentences, describe one variable you notice in mpg and one question you could explore with this dataset. The variable mpg represents a vehicle’s highway miles per gallon. Can a vehicle with a higher engine displacement have lower highway fuel efficiency?