Jackdaw
Jackdaw

Reputation: 67

Adding different numbers to different columns of a dataframe

Suppose I am working with the mtcars dataset, and I would like to add:
1 to all values in the column: mpg
2 to all values in the column: cyl
3 to all values in the column: disp
I would like to keep all columns in mtcars, and refer to the columns by their names rather than their index.

Here's my current attempt:

library("tidyverse")
library("rlang")
data(mtcars)

mtcars_colnames <- quo(c("mpg", "cyl", "disp"))
num <- c(1, 2, 3)

mtcars %>% mutate(across(!!! mtcars_colnames, function(x) {x + num[col(.)]}))

I'm stuck on how to dynamically add (1,2,3) to columns (mpg, cyl, disp). Thanks in advance.

Upvotes: 0

Views: 158

Answers (2)

Ronak Shah
Ronak Shah

Reputation: 388982

Here are 3 base R approaches :

mtcars_colnames <- c("mpg", "cyl", "disp")
num <- c(1, 2, 3)
df <- mtcars

#option 1
df[mtcars_colnames] <- sweep(df[mtcars_colnames], 2, num, `+`)
#option 2
df[mtcars_colnames] <- Map(`+`, df[mtcars_colnames], num)
#option 3
df[mtcars_colnames] <- t(t(df[mtcars_colnames]) + num)

Upvotes: 1

akrun
akrun

Reputation: 887118

We could change the input by passing just a vector of strings instead of quosures and a named vector for 'num', then use the cur_column inside the across to match with the named vector of 'num', get the corresponding value and do the addition

library(dplyr)
mtcars_colnames <- c("mpg", "cyl", "disp")
num <- setNames(c(1, 2, 3), mtcars_colnames)
mtcars1 <- mtcars %>%
    mutate(across(all_of(mtcars_colnames), ~ num[cur_column()] + .))

-check the output

# // old data
mtcars %>% 
    select(all_of(mtcars_colnames)) %>% 
    slice_head(n = 5)
#                   mpg cyl disp
#Mazda RX4         21.0   6  160
#Mazda RX4 Wag     21.0   6  160
#Datsun 710        22.8   4  108
#Hornet 4 Drive    21.4   6  258
#Hornet Sportabout 18.7   8  360

# // new data
mtcars1 %>% 
    select(all_of(mtcars_colnames)) %>%
    slice_head(n = 5)
#                   mpg cyl disp
#Mazda RX4         22.0   8  163
#Mazda RX4 Wag     22.0   8  163
#Datsun 710        23.8   6  111
#Hornet 4 Drive    22.4   8  261
#Hornet Sportabout 19.7  10  363

Or if we prefer to pass a unnamed 'num' vector, then match the cur_column with the 'mtcars_colnamesinside theacross` to return the index and then use that to subset the 'num'

mtcars1 <- mtcars %>%
    mutate(across(all_of(mtcars_colnames), 
           ~ num[match(cur_column(), mtcars_colnames)] + .))

Upvotes: 1

Related Questions