olec_c
olec_c

Reputation: 67

R - Subtract the same value from multiple columns

I have a set of survey data that uses Likert scale responses, coded 1-5 ('strongly disagree' to 'strongly agree'). I am trying to re-centre the scores around 0, such that -2 is 'strongly disagree' and +2 is 'strongly agree'.

An obvious way of getting there is to subtract all columns by 3, but I do not know to subtract the same number from multiple columns in one line of code, I am sure there's a way...

Example data:

likert_data <- data.frame(id=c(1:10),
                          a=sample(x = 1:5, size = 10,replace=T),
                          b=sample(x = 1:5, size = 10,replace=T),
                          c=sample(x = 1:5, size = 10,replace=T)
                          )

I could of course do something like this...

likert_data %<>% 
  mutate(across(c(a:c), ~case_when(. == 1 ~ as.numeric(-2),
                                   . == 2 ~ as.numeric(-1),
                                   . == 3 ~ as.numeric(0),
                                   . == 4 ~ as.numeric(1),
                                   . == 5 ~ as.numeric(2))))

... but I don't think it's very elegant.

Is there a way of subtracting columns a:c by 3? Doesn't have to be using dplyr, but would really appreciate a dplyr solution if one exists! :)

Upvotes: 4

Views: 3464

Answers (3)

Duck
Duck

Reputation: 39613

Maybe try this using across():

library(dplyr)
#Data
new <- likert_data <- data.frame(id=c(1:10),
                          a=sample(x = 1:5, size = 10,replace=T),
                          b=sample(x = 1:5, size = 10,replace=T),
                          c=sample(x = 1:5, size = 10,replace=T)
)
#Code
new <- likert_data %>% mutate(across(a:c,~.-3))

Output:

   id  a  b  c
1   1  2 -2  1
2   2  2 -2  0
3   3 -2 -1 -2
4   4  0  0 -1
5   5  2 -2  2
6   6  1  2  2
7   7  0  0  1
8   8  0  1 -2
9   9  0 -1 -1
10 10  2  0 -2

Upvotes: 4

maop
maop

Reputation: 213

I would use data.table, especially if your data is big.

library(dplyr)
library(data.table)    
likert_data <- data.frame(id=c(1:10),
                          a=sample(x = 1:5, size = 10,replace=T),
                          b=sample(x = 1:5, size = 10,replace=T),
                          c=sample(x = 1:5, size = 10,replace=T)
) %>% data.table()

cols <- c("a", "b", "c")

likert_data[, (cols) := lapply(.SD, function(x) (x-3)), .SDcols = cols]

If you want to create other columns to store new values:

newcols <- c("a-3", "b-3", "c-3")
likert_data[, (newcols) := lapply(.SD, function(x) (x-3)), .SDcols = cols]

Upvotes: 2

SteveM
SteveM

Reputation: 2301

Since R is vectorized, simply substract 3 from the columns:

cars <- mtcars
cars[1:3] <- cars[1:3] - 3
cars
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           18.0   3 157.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       18.0   3 157.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          19.8   1 105.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      18.4   3 255.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   15.7   5 357.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             15.1   3 222.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          11.3   5 357.0 245 3.21 3.570 15.84  0  0    3    4
      

Upvotes: 5

Related Questions