dplyr Basics
Reviewed & published by Brayan K
dplyr is a tidyverse package for transforming data frames with a small set of readable verbs — filter, select, mutate, and arrange — that you chain together with the pipe.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll filter rows, select and add columns, sort data, and combine these verbs into a single readable pipeline with the pipe operator.
What You'll Learn in This Lesson
- How to keep rows with filter()
- How to choose columns with select()
- How to add or change columns with mutate()
- How to sort rows with arrange() and desc()
- How the pipe |> chains steps readably
- How to load dplyr with library(dplyr)
1️⃣ filter() and select()
filter() keeps rows matching a condition; select() keeps columns. Inside dplyr verbs you refer to columns by bare name — no df$ needed.
library(dplyr)
# A small data frame to work with:
df <- data.frame(
name = c("Ada", "Bob", "Cara", "Dan"),
dept = c("eng", "sales", "eng", "sales"),
salary = c(95, 60, 88, 72)
)
# filter() keeps rows that match a condition:
filter(df, salary > 80)
# name dept salary
# 1 Ada eng 95
# 2 Cara eng 88
# select() keeps columns:
select(df, name, salary)2️⃣ mutate() and arrange()
mutate() adds new columns computed from existing ones; arrange() sorts rows, with desc() for descending order.
library(dplyr)
df <- data.frame(
product = c("pen", "pad", "ink"),
price = c(2.5, 5.0, 9.0),
units = c(120, 80, 45)
)
# mutate() ADDS or changes columns:
df2 <- mutate(df, revenue = price * units)
# arrange() SORTS rows (desc() for descending):
arrange(df2, desc(revenue))
# product price units revenue
# 1 ink 9.0 45 405
# 2 pad 5.0 80 400
# 3 pen 2.5 120 3003️⃣ Chaining with the Pipe
The real power comes from chaining. The pipe |> passes each step's result into the next, so a multi-step transformation reads top to bottom like a sentence.
library(dplyr)
df <- data.frame(
name = c("Ada", "Bob", "Cara", "Dan"),
dept = c("eng", "sales", "eng", "sales"),
salary = c(95, 60, 88, 72)
)
# The pipe |> (or %>%) passes the result on to the next verb,
# so you read the steps top to bottom like a sentence.
df |>
filter(dept == "eng") |> # 1. keep engineers
mutate(bonus = salary * 0.1) |> # 2. add a bonus column
select(name, bonus) |> # 3. keep two columns
arrange(desc(bonus)) # 4. highest bonus firstYour turn. Fill in the ___ blank, run it, and compare with the expected output.
library(dplyr)
# 🎯 YOUR TURN — replace each ___ then run it.
orders <- data.frame(
item = c("a", "b", "c", "d"),
qty = c(3, 10, 1, 6),
price = c(20, 5, 50, 8)
)
result <- orders |>
mutate(total = qty * price) |>
___ |> # 👉 replace ___ with filter(total > 40)
arrange(desc(total))
print(result)
# ✅ Expected output:
# item qty price total
# 1 a 3 20 60
# 2 b 10 5 50
# 3 c 1 50 50
# 4 d 6 8 48Mini-Challenge: Top Earners
Write the whole pipeline from the outline, run it, and check it against the example output. This is the core dplyr workflow you'll use daily.
# 🎯 MINI-CHALLENGE: top earners report.
#
# Start from this data frame:
# staff <- data.frame(
# name = c("Mia","Leo","Zoe","Sam","Ari"),
# team = c("X","Y","X","Y","X"),
# pay = c(70, 110, 95, 60, 130)
# )
#
# Using a pipe, in one chain:
# 1. mutate() a column "raise" = pay * 0.05
# 2. filter() to keep pay >= 90
# 3. select() name and raise
# 4. arrange() by raise, highest first
#
# ✅ Example output:
# name raise
# 1 Ari 6.50
# 2 Leo 5.50
# 3 Zoe 4.75
# your code hereCommon Errors (and the fix)
- "could not find function 'filter'" — you didn't load dplyr. Run library(dplyr) first.
- Using = instead of == in filter — filter(df, x == 5) tests equality; a single = is wrong here.
- filter() vs base subset confusion — dplyr's filter() can clash with stats::filter(). If results look odd, restart and load dplyr last, or use dplyr::filter().
- Pipe placement — each |> must end a line (or precede the next call). A dangling pipe with nothing after it errors.
Pro Tips
- 💡 Read the pipe as "then": "take df, then filter, then mutate" — it mirrors how you'd describe the task.
- 💡 select helpers: starts_with(), ends_with(), and -col (drop) make column choices flexible.
- 💡 Build pipelines incrementally: add one verb at a time and run, so you catch mistakes early.
📋 Quick Reference — dplyr Verbs
| Verb | What it does |
|---|---|
| filter(df, x > 1) | keep rows matching a condition |
| select(df, a, b) | keep (or drop) columns |
| mutate(df, c = a + b) | add or change a column |
| arrange(df, desc(x)) | sort rows |
| df |> verb() | pipe into the next step |
| library(dplyr) | load the package |
🎉 Lesson Complete!
- ✅ filter() keeps rows; select() keeps columns
- ✅ mutate() adds columns; arrange() sorts
- ✅ The pipe |> chains steps top to bottom
- ✅ Refer to columns by bare name inside verbs
- ✅ Load with library(dplyr) each session
Practice quiz
Which dplyr verb keeps only the ROWS that match a condition?
- select()
- filter()
- mutate()
- arrange()
Answer: filter(). filter() keeps rows matching a condition; select() chooses columns.
Which verb chooses (keeps or drops) COLUMNS?
- select()
- filter()
- summarise()
- arrange()
Answer: select(). select() picks columns; filter() picks rows.
Which verb ADDS or changes a column computed from existing ones?
- arrange()
- filter()
- mutate()
- select()
Answer: mutate(). mutate() creates or modifies columns.
Which verb SORTS the rows of a data frame?
- group_by()
- select()
- filter()
- arrange()
Answer: arrange(). arrange() sorts rows; wrap a column in desc() for descending order.
How do you sort in DESCENDING order with arrange()?
- arrange(desc(x))
- arrange(-sort(x))
- arrange(x, rev = TRUE)
- arrange(descending(x))
Answer: arrange(desc(x)). arrange(df, desc(x)) sorts by x from high to low.
What does the pipe in df |> filter(x > 1) do?
- Comments out the filter call
- Passes df as the first argument to filter()
- Runs filter() before df is created
- Compares df with the filter result
Answer: Passes df as the first argument to filter(). The pipe feeds the left-hand value as the first argument to the right-hand function.
Inside a dplyr verb, how do you refer to a column named salary?
- By the bare name salary
- Always as df$salary
- As "salary" in quotes
- As .salary
Answer: By the bare name salary. dplyr verbs let you use bare column names; no df$ prefix is needed.
Which function loads dplyr at the start of a session?
- import(dplyr)
- require.dplyr()
- library(dplyr)
- use(dplyr)
Answer: library(dplyr). library(dplyr) attaches the package so its verbs are available.
Inside filter(), how do you test that dept equals "eng"?
- dept = "eng"
- dept == "eng"
- dept -> "eng"
- dept := "eng"
Answer: dept == "eng". Use == for equality; a single = is assignment and is wrong here.
Which native pipe operator works in base R 4.1+ without any package?
- %>%
- ->>
- |>
- %|%
Answer: |>. |> is the native pipe in R 4.1+; %>% comes from magrittr/dplyr.
Continue this course
- Previous: The apply Family
- Next: tidyr & Pipes — Reshape messy data into tidy form and chain steps with the pipe
- Quick reference: R cheat sheet › dplyr
Frequently asked questions
What is dplyr and why is it so popular?
dplyr is a package in the tidyverse for manipulating data frames with a small set of verb functions: filter() for rows, select() for columns, mutate() to add columns, arrange() to sort, and summarise() to aggregate. Its appeal is readability — code reads like a description of what you want, and the steps chain together cleanly. It's also fast and consistent. Once you learn the five core verbs, you can express almost any data transformation.
What does the pipe operator do?
The pipe (|> in modern R, or %>% from the magrittr/dplyr package) takes the result on its left and feeds it as the first argument to the function on its right. So df |> filter(x > 1) is the same as filter(df, x > 1). Chained together, pipes let you read a sequence of transformations top-to-bottom like a recipe — 'take the data, then filter, then mutate, then arrange' — instead of nesting functions inside out.
How is dplyr different from base R data frame operations?
You can do everything dplyr does with base R — df[df$x > 1, ] for filtering, df$new <- ... for new columns — but dplyr is usually more readable and less error-prone, especially as operations stack up. dplyr lets you refer to columns by bare name (no df$ prefix inside verbs) and chain steps with the pipe. Base R is always available and worth knowing; dplyr is the everyday tool most analysts reach for.
Do I need to install anything to use dplyr?
Yes — dplyr isn't part of base R, so install it once with install.packages("dplyr") (or install.packages("tidyverse") to get dplyr plus its companions). Then load it in each session with library(dplyr). The native pipe |> works without any package in R 4.1+; the older %>% pipe comes with dplyr/magrittr. After that, all the verbs in this lesson are available.