简体   繁体   中英

Using recode() with variable names generated through paste()

I am trying to recode a variable which contains the labels of the answers as a character into numeric values. I am using recode() from dplyr for this.

To automate this I wanted to use paste() to generate the variable names but apparently recode() can't take the output from paste .

I already tried noquote() and as.name() but for both R tells me that recode can't use objects of the class "noquote"/"name".

Example:

item1 <- c("Don't agree at all", "Totally agree")
item2 <- c("Indifferent", "Totally agree")

for (i in 1:2) {
recode(paste("item", i, sep=""), "Totally agree"=1, "Indifferent"=2, "Don't agree at all"=3)
}

I would then expect

> item1
  [1] 3 1

How can I solve this?

UPDATE

I found a work around by first extracting the relevant columns into another dataframe and then applying the recode() function with sapply() . Now I can remerge the dataframes.

Regarding "but apparently recode() can't take the output from paste.": This has nothing to do with recode but (almost) any R function works this way. paste returns a string, and recode expects a vector as its first argument... (notable exception, amongst others: library where we can pass a string or the library name as an object).

What you could do, if you insist on the "for loop" approach is to use a combination of assign and something like eval(sym("a string")) :

item1 <- c("Don't agree at all", "Totally agree")
item2 <- c("Indifferent", "Totally agree")


library(dplyr)
for (i in 1:2) {
  assign(paste("item", i, sep="") , recode(eval(sym(paste("item", i, sep=""))), "Totally agree"=1, "Indifferent"=2, "Don't agree at all"=3))
}

That results in:

item1

[1] 3 1

item2

[1] 2 1

Edit:

A probably more straightforward and a bit more "dplyr"-y approach would be something along the lines of:

tdd <- data.frame(item1, item2) %>% 
  mutate_at(vars(starts_with("item")), ~recode(., "Totally agree"=1, "Indifferent"=2, "Don't agree at all"=3))

And tdd is now:

tdd
 item1 item2 1 3 2 2 1 1

You simply could put a named vector v together with a list of your variables from mget into Map and subset it.

v <- c("Totally agree"=1, "Indifferent"=2, "Don't agree at all"=3)

Map(function(x, y) unname(y[x]), mget(ls(pattern="^item")), list(v))
# $item1
# [1] 3 1
# 
# $item2
# [1] 2 1

Or, suppose you have a data frame like this one,

head(dat1)
#   id         item1              item2         x
# 1  1 Totally agree      Totally agree 0.0356312
# 2  2 Totally agree      Totally agree 1.3149588
# 3  3 Totally agree        Indifferent 0.9781675
# 4  4 Totally agree        Indifferent 0.8817912
# 5  5   Indifferent        Indifferent 0.4822047
# 6  6   Indifferent Don't agree at all 0.9657529

then you may do this in a similar way. We may even simplify the code because we don't need the Map to return unname d objects anymore.

v1 <- c("Totally agree"=1, "Indifferent"=2, "Don't agree at all"=3)

item_nm <- c("item1", "item2")
dat1[item_nm] <- Map(`[`, list(v1), dat2[item_nm])
dat1
#    id item1 item2          x
# 1   1     1     1  0.0356312
# 2   2     1     1  1.3149588
# 3   3     1     2  0.9781675
# 4   4     1     2  0.8817912
# 5   5     2     2  0.4822047
# 6   6     2     3  0.9657529
# 7   7     2     3 -0.8145709
# 8   8     1     1  0.2839578
# 9   9     3     1 -0.1616986
# 10 10     3     3  1.9355718

The second argument gets recycled for each Map iteration (ie list(v1, v1) would also work).

And more generally, for each column you want to recode numerically, list one vector more in the second argument of Map .

head(dat2)
#   id         item1  item2         x
# 1  1 Totally agree Always 0.0356312
# 2  2 Totally agree Always 1.3149588
# 3  3 Totally agree   Both 0.9781675
# 4  4 Totally agree   Both 0.8817912
# 5  5   Indifferent   Both 0.4822047
# 6  6   Indifferent  Never 0.9657529

v2 <- c("Always"=1, "Both"=2, "Never"=3)

dat2[item_nm] <- Map(`[`, list(v1, v2), dat2[item_nm])
dat2
#    id item1 item2          x
# 1   1     1     1  0.0356312
# 2   2     1     1  1.3149588
# 3   3     1     2  0.9781675
# 4   4     1     2  0.8817912
# 5   5     2     2  0.4822047
# 6   6     2     3  0.9657529
# 7   7     2     3 -0.8145709
# 8   8     1     1  0.2839578
# 9   9     3     1 -0.1616986
# 10 10     3     3  1.9355718

Data:

dat1 <- structure(list(id = 1:10, item1 = c("Totally agree", "Totally agree", 
"Totally agree", "Totally agree", "Indifferent", "Indifferent", 
"Indifferent", "Totally agree", "Don't agree at all", "Don't agree at all"
), item2 = c("Totally agree", "Totally agree", "Indifferent", 
"Indifferent", "Indifferent", "Don't agree at all", "Don't agree at all", 
"Totally agree", "Totally agree", "Don't agree at all"), x = c(0.0356311982051355, 
1.31495884897891, 0.978167526364279, 0.881791226863203, 0.482204688262918, 
0.965752878105794, -0.814570938270238, 0.283957806364306, -0.161698647607024, 
1.93557176599585)), class = "data.frame", row.names = c(NA, -10L
))

dat2 <- structure(list(id = 1:10, item1 = c("Totally agree", "Totally agree", 
"Totally agree", "Totally agree", "Indifferent", "Indifferent", 
"Indifferent", "Totally agree", "Don't agree at all", "Don't agree at all"
), item2 = c("Always", "Always", "Both", "Both", "Both", "Never", 
"Never", "Always", "Always", "Never"), x = c(0.0356311982051355, 
1.31495884897891, 0.978167526364279, 0.881791226863203, 0.482204688262918, 
0.965752878105794, -0.814570938270238, 0.283957806364306, -0.161698647607024, 
1.93557176599585)), class = "data.frame", row.names = c(NA, -10L
))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM