Skip to content
AgileLogics
7 min read

dplyr: filter, select, and arrange

Prerequisites: Tibbles, Scope and anonymous functions

dplyr is the tidyverse package for transforming data. Each of its functions — called verbs — does one job, takes a data frame as the first argument, and returns a new data frame. Chained together with the pipe |>, they read like a recipe.

library(dplyr, warn.conflicts = FALSE)

warn.conflicts = FALSE hides the message about dplyr functions (such as filter) replacing base R functions with the same name. You'll see that message the first time — it's informational, not an error.

We'll use this small dataset:

library(dplyr, warn.conflicts = FALSE)

staff <- tibble(
  name = c("Ada", "Linus", "Grace", "Alan", "Margaret"),
  team = c("Data", "Infra", "Data", "Research", "Infra"),
  salary = c(72000, 65000, 91000, 58000, 83000),
  years = c(5, 3, 12, 2, 8)
)

staff |> filter(team == "Data")
# A tibble: 2 × 4
  name  team  salary years
  <chr> <chr>  <dbl> <dbl>
1 Ada   Data   72000     5
2 Grace Data   91000    12

filter — keep rows

Inside dplyr verbs you refer to columns by bare names — no staff$ prefix. Conditions separated by commas must all be true:

library(dplyr, warn.conflicts = FALSE)

staff <- tibble(
  name = c("Ada", "Linus", "Grace", "Alan", "Margaret"),
  team = c("Data", "Infra", "Data", "Research", "Infra"),
  salary = c(72000, 65000, 91000, 58000, 83000),
  years = c(5, 3, 12, 2, 8)
)

staff |> filter(salary > 60000, years >= 5)
staff |> filter(team %in% c("Infra", "Research"))
# A tibble: 3 × 4
  name     team  salary years
  <chr>    <chr>  <dbl> <dbl>
1 Ada      Data   72000     5
2 Grace    Data   91000    12
3 Margaret Infra  83000     8
# A tibble: 3 × 4
  name     team     salary years
  <chr>    <chr>     <dbl> <dbl>
1 Linus    Infra     65000     3
2 Alan     Research  58000     2
3 Margaret Infra     83000     8

select — keep columns

library(dplyr, warn.conflicts = FALSE)

staff <- tibble(
  name = c("Ada", "Linus"),
  team = c("Data", "Infra"),
  salary = c(72000, 65000),
  years = c(5, 3)
)

staff |> select(name, salary)
staff |> select(-years)
# A tibble: 2 × 2
  name  salary
  <chr>  <dbl>
1 Ada    72000
2 Linus  65000
# A tibble: 2 × 3
  name  team  salary
  <chr> <chr>  <dbl>
1 Ada   Data   72000
2 Linus Infra  65000

-years drops a column. Helpers such as starts_with("sales_"), ends_with("_id"), and where(is.numeric) select groups of columns.

arrange — sort rows

library(dplyr, warn.conflicts = FALSE)

staff <- tibble(
  name = c("Ada", "Linus", "Grace", "Alan", "Margaret"),
  team = c("Data", "Infra", "Data", "Research", "Infra"),
  salary = c(72000, 65000, 91000, 58000, 83000)
)

staff |> arrange(desc(salary)) |> head(3)
staff |> arrange(team, name)
# A tibble: 3 × 3
  name     team  salary
  <chr>    <chr>  <dbl>
1 Grace    Data   91000
2 Margaret Infra  83000
3 Ada      Data   72000
# A tibble: 5 × 3
  name     team     salary
  <chr>    <chr>     <dbl>
1 Ada      Data      72000
2 Grace    Data      91000
3 Linus    Infra     65000
4 Margaret Infra     83000
5 Alan     Research  58000

desc() sorts from largest to smallest; several columns sort by the first, then the next.

Common mistakes

  • Writing filter(team = "Data") — one = is an argument name, not a comparison. dplyr's error message suggests ==.
  • Forgetting to save the result. Verbs return a new data frame; write data_team <- staff |> filter(...) to keep it.