如何遍历字符串(变量)并重新编码值?

时间:2016-07-05 23:59:26

标签: r loops vectorization

我有一个包含大量变量的数据框。这些变量的子集名称中包含一个数字(例如x1_vx2_v),我想为任意大小的子集重新编码这些变量的值。我使用for循环尝试了以下操作,但它没有重新编码。

library(car)
library(magrittr)

# Sample df
x1_v <- seq(1:5)
x2_v <- rep(5,5)
fun <- c("a","b","c","r","q")
data <- data.frame(x1_v, x2_v, fun)

# Loop
for (i in 1:2){
 paste0("data$x", i, "_v") %>% 
     assign(paste0("data$x", i, "_v") %>%
     recode("c(0, 5) = NA"))
}

我知道这通过使用循环和assign()违反了几乎所有R协议,但我试图理解

  1. 为什么这不起作用
  2. 我如何使用像申请这样的东西来解决这个问题。
  3. 我认为制作一个列表是有道理的,但我想在最后将所有数据保存在数据框类中。

1 个答案:

答案 0 :(得分:0)

  1. 这是不起作用的一点:

    assign(paste0("data$x", i, "_v") %>%
        recode("c(0, 5) = NA")
    

    您正在传递recode字符串,用于&#34;数据$ x1_v&#34;当var需要向量变量时。如果你想进入组合字符串以形成表达式和函数调用的领域,你应该看看eval(),但我认为这样做对你正在尝试做的事情有些过分。避免这种编程风格的另一个原因是它不能很好地与%>%一起使用。

  2. 如果我正确阅读了您的代码,您正在尝试重新编码数据框中与名称中的某个模式匹配的列。您已经要求提供矢量化解决方案,dplyr具有可以提供帮助的设施。 dplyr::mutate_at()将是不错的选择。有一个dplyr::recode(),但它需要您详尽地指定所有案例,并且对类型非常挑剔。例如,这是我用dplyr::recode()来捕捉你的意图的最接近的地方:

    library(dplyr)
    data %>% 
        mutate_at( .funs = funs(recode(., `0` = NA_real_, 
                                          `5` = NA_real_,
                                          `1` = 1,
                                          `2` = 2,
                                          `3` = 3,
                                          `4` = 4)),
                  .cols = vars(matches("x[0-9].*_v"))
        )
    

    请注意使用正在对列名进行正则表达式匹配的.cols = vars(matches("x[0-9].*_v")来查找x#_v个。此外,在funs().指的是我正在操作的列。&#39;不是&#39;管道传递的输出。&#39;

    也许ifelse()if_else()是更好的选择。 ifelse()(速度较慢,类型较安全):

    data %>% 
        mutate_at( .funs = funs(ifelse(. == 0| . == 5, 
                                       yes = NA,
                                       no = .)),
                   .cols = vars(matches("x[0-9].*_v"))
        )
    

    if_else()需要x2_vx1_v的类型相同,而目前它们并不相同。 x2_v <- rep(as.integer(5),5)会解决这个问题。然后你可以这样做:

    data %>% 
        mutate_at( .funs = funs(if_else(. == 0| . == 5, 
                                        true = NA_integer_,
                                        false = .)),
                   .cols = vars(matches("x[0-9].*_v"))
     )