Why Use Pipes in R?

When you perform several transformations in R, your code can quickly become cluttered with nested parentheses or a series of temporary variables. Pipes offer a cleaner, more intuitive alternative: they let you write code that mirrors the logical flow of your analysis. Each step passes its output directly into the next, creating a readable sequence of operations that tells the story of your data transformation from start to finish.

First of all, let’s call the the dplyr package to use the pipe operator %>% and look at the dataset we will work with:

library(dplyr)
head(bfi)
      a1 a2 a3 a4 a5 c1 c2 c3 c4 c5 e1 e2 e3 e4 e5 n1 n2 n3 n4 n5 o1 o2 o3 o4
61617  2  4  3  4  4  2  3  3  4  4  3  3  3  4  4  3  4  2  2  3  3  6  3  4
61618  2  4  5  2  5  5  4  4  3  4  1  1  6  4  3  3  3  3  5  5  4  2  4  3
61620  5  4  5  4  4  4  5  4  2  5  2  4  4  4  5  4  5  4  2  3  4  2  5  5
61621  4  4  6  5  5  4  4  3  5  5  5  3  4  4  4  2  5  2  4  1  3  3  4  3
61622  2  3  3  4  5  4  4  5  3  2  2  2  5  4  5  2  3  4  4  3  3  3  4  3
61623  6  6  5  6  5  6  6  6  1  3  2  1  6  5  6  3  5  2  2  3  4  3  5  6
      o5    gen ed age agree consc extra neuro open     agree_z    consc_z
61617  3   male NA  16   4.0   2.8   3.8   2.8  3.0 -0.72583913 -1.5406915
61618  3 female NA  18   4.2   4.0   5.0   3.8  4.0 -0.50322161 -0.2793220
61620  2 female NA  17   3.8   4.0   4.2   3.6  4.8 -0.94845665 -0.2793220
61621  5 female NA  17   4.6   3.0   3.6   2.8  3.2 -0.05798656 -1.3304633
61622  3   male NA  17   4.0   4.4   4.8   3.2  3.6 -0.72583913  0.1411345
61623  1 female  3  21   4.6   5.6   5.6   3.0  5.0 -0.05798656  1.4025040
          extra_z     neuro_z     open_z    gm
61617 -0.32527289 -0.30281564 -1.9627661   boy
61618  0.80583785  0.53307316 -0.7257147 woman
61620  0.05176403  0.36589540  0.2639264  girl
61621 -0.51379134 -0.30281564 -1.7153558  girl
61622  0.61731939  0.03153988 -1.2205352   boy
61623  1.37139322 -0.13563788  0.5113367 woman

For example, consider this chain of operations applied to the bfi dataset:

  1. Select five personality scale scores.
  2. Compute their covariance matrix.
  3. Extract the variances from this matrix.
  4. Take the square roots to obtain standard deviations.

In base R, this can be written as nested function calls:

sqrt(
  diag(
    cov(
      bfi[c("agree", "consc", "extra", "neuro", "open")],
      use = "pairwise"
    )
  )
)
    agree     consc     extra     neuro      open 
0.8984019 0.9513469 1.0609041 1.1963314 0.8083739 

While technically correct, the structure is hard to follow. Alternatively, we can save intermediate results:

tmp <- bfi[c("agree", "consc", "extra", "neuro", "open")]
tmp <- cov(tmp, use = "pairwise")
tmp <- diag(tmp)
sqrt(tmp)
    agree     consc     extra     neuro      open 
0.8984019 0.9513469 1.0609041 1.1963314 0.8083739 

This approach is clearer but involves multiple temporary variables and assignments.

Using a pipe, we can express the same sequence in a single, logical flow that reads from top to bottom:

bfi %>%
  select(agree, consc, extra, neuro, open) %>%
  cov(use = "pairwise") %>%
  diag() %>%
  sqrt()
    agree     consc     extra     neuro      open 
0.8984019 0.9513469 1.0609041 1.1963314 0.8083739 

Here, the result of each function is passed directly into the next, eliminating unnecessary assignments and parentheses. Pipes enhance readability by allowing you to see the sequence of transformations at a glance, making your code easier to understand and maintain.

Practice

Use a pipeline to calculate the square root of the mean of the agreeableness scale score for males in the bfi data.

You can use the unlist() function to covert a list to a vector.

bfi %>%
  filter(gen == "male") %>%
  select(agree) %>%
  unlist() %>%
  mean(na.rm = TRUE) %>%
  sqrt()
[1] 2.094169
Back to top