Mutate all columns matching a pattern each time based on the previous columns

This is actually vectorised operation so you can do this without any loops.

Using vector recycling :

df[, c(FALSE, TRUE)] <- df[, c(FALSE, TRUE)]/100 * df[, c(TRUE, FALSE)]
df

#           a         fooa        b       foob         c     fooc
#1  0.5543269  0.003664775 48.26791 1.49628246  98.06053 5.918428
#2 -0.2802719 -0.002461827 51.15647 0.08114656 113.96432 2.620614
#3  1.7751634  0.015808878 52.34582 1.20765132 101.00663 9.765657
#4  0.1873201  0.001060757 50.58978 0.83478430  98.85561 5.976363
#5  1.1425261  0.006781434 50.35224 1.59495949 107.02225 6.845194

If you want to perform this based on names of the column.

cols <- grep('foo', names(df))
df[cols] <- df[cols]/100 * df[-cols]

One option could be:

df %>%
 mutate(across(starts_with("foo"))/100 * across(!matches("foo")))

           a         fooa        b       foob         c     fooc
1  0.5543269  0.003664775 48.26791 1.49628246  98.06053 5.918428
2 -0.2802719 -0.002461827 51.15647 0.08114656 113.96432 2.620614
3  1.7751634  0.015808878 52.34582 1.20765132 101.00663 9.765657
4  0.1873201  0.001060757 50.58978 0.83478430  98.85561 5.976363
5  1.1425261  0.006781434 50.35224 1.59495949 107.02225 6.845194

Here is another approach using across() and cur_column(). I personally would not recommend to make calculations based on the position of columns, and would instead recommend to work with the columns names, since this seems safer.

In the example below we loop over the columns a,b and c with across and access the values of each corresponding foo column by using get() and cur_column.

set.seed(13)
dfrows = 5
df = data.frame(a = rnorm(dfrows),
                fooa = runif(dfrows),
                b = rnorm(dfrows, mean=50, sd=5),
                foob = runif(dfrows, min=0, max=5),
                c = rnorm(dfrows, mean=100, sd=10),
                fooc = runif(dfrows, min=0, max=10))

library(dplyr)

df %>% 
  mutate(across(matches("^[a-z]$"),
                ~ get(paste0("foo", cur_column())) / 100 * .x,
                .names = "foo{col}"))
#>            a         fooa        b       foob         c     fooc
#> 1  0.5543269  0.003664775 48.26791 1.49628246  98.06053 5.918428
#> 2 -0.2802719 -0.002461827 51.15647 0.08114656 113.96432 2.620614
#> 3  1.7751634  0.015808878 52.34582 1.20765132 101.00663 9.765657
#> 4  0.1873201  0.001060757 50.58978 0.83478430  98.85561 5.976363
#> 5  1.1425261  0.006781434 50.35224 1.59495949 107.02225 6.845194

Created on 2021-01-27 by the reprex package (v0.3.0)

Tags:

R

Dplyr