dplyr::rowwise()

Function of the Week

Lets you apply operations to each row of a data frame individually
Author

Kelsey Zionskowski

Published

March 6, 2025

1. dplyr::rowwise()

In this document, I will introduce the rowwise() function and demonstrate its use.

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.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
library(palmerpenguins)
library(formatR)
library(gapminder)

1.1 What is it for?

The rowwise() function in dplyr lets you apply operations to each row of a data frame individually. Unlike typical dplyr functions that work column-wise like mutate(), rowwise() focuses to rows. It’s particularly useful for calculations across multiple columns per row, working with list-columns, or applying row-specific functions.

1.2 Example Usage

Example 1: Row-wise Summation

Let’s use the mtcars dataset to calculate a combined performance score for each car by summing horsepower (hp), miles per gallon (mpg), and weight (wt).

data <- mtcars %>%
    select(hp, mpg, wt) %>%
    rowwise() %>%
    mutate(performance_sum = round(sum(c(hp, mpg, wt)), 2)) %>%
    ungroup()

head(data)
# A tibble: 6 × 4
     hp   mpg    wt performance_sum
  <dbl> <dbl> <dbl>           <dbl>
1   110  21    2.62            134.
2   110  21    2.88            134.
3    93  22.8  2.32            118.
4   110  21.4  3.22            135.
5   175  18.7  3.44            197.
6   105  18.1  3.46            127.

For each car, rowwise() makes sure that sum() function is applied separately to hp, mpg, and wt within each row, creating a new column called performance_sum. This provides a rough aggregate performance metric for each car. Without rowwise(), sum() would operate across entire columns instead of computing row-specific values.

Example 2: Applying Functions to Each Row

Let’s use the iris dataset to compute the average of sepal and petal lengths for each flower, simulating a per-row measurement summary.

data <- iris %>%
    rowwise() %>%
    mutate(avg_length = mean(c(Sepal.Length, Petal.Length)))

head(data)
# A tibble: 6 × 6
# Rowwise: 
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species avg_length
         <dbl>       <dbl>        <dbl>       <dbl> <fct>        <dbl>
1          5.1         3.5          1.4         0.2 setosa        3.25
2          4.9         3            1.4         0.2 setosa        3.15
3          4.7         3.2          1.3         0.2 setosa        3   
4          4.6         3.1          1.5         0.2 setosa        3.05
5          5           3.6          1.4         0.2 setosa        3.2 
6          5.4         3.9          1.7         0.4 setosa        3.55

Here, rowwise() ensures mean() calculates the average of Sepal.Length and Petal.Length for each flower individually. Without rowwise(), mean() would compute a single average across all rows, losing the per-flower detail.

Example 3: Row-wise Calculations After Grouping

Using the gapminder dataset, let’s compute a custom “wealth index” for each country in its most recent year, combining GDP per capita and population with a row-specific formula.

result <- gapminder %>%
    group_by(country) %>%
    filter(year == max(year)) %>%
    rowwise() %>%
    mutate(wealth_index = log(gdpPercap * pop/1e+06)) %>%
    select(country, year, wealth_index)

head(result)
# A tibble: 6 × 3
# Rowwise:  country
  country      year wealth_index
  <fct>       <int>        <dbl>
1 Afghanistan  2007        10.3 
2 Albania      2007         9.97
3 Algeria      2007        12.2 
4 Angola       2007        11.0 
5 Argentina    2007        13.2 
6 Australia    2007        13.5 

Here, we first group by country and use filter(year == max(year)) to keep only the most recent year for each country. Then use rowwise() to apply a custom function that takes the log of GDP (in millions). This example shows how rowwise() works for more than just basic math and can be useful for more complex row-by-row calculations.

1.3 Is it helpful?

Yes! rowwise() is great for row-level operations without loops or apply() functions and for keeping your code tidyverse-friendly. It works best with list-columns (Example 1), per-row summaries (Example 2), or custom row-wise calculations (Example 3). When vectorized operations are sufficent, like mutate() or across(), it’s better to avoid rowwise() since it can slow down computations. For large datasets rowwise() can also be computationally expensive since it forces operations to be done row-by-row instead of using vectorized approaches.