【问题标题】:How to loop through a string (variables) and recode values?如何遍历字符串(变量)并重新编码值?
【发布时间】:2016-07-05 23:59:25
【问题描述】:

我有一个包含大量变量的数据框。这些变量的一个子集的名称中包含一个数字(例如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. 我如何使用 apply 之类的东西来解决这个问题。

我认为制作一个列表是有意义的,但我想将我的所有数据保留在最后的数据框类中。

【问题讨论】:

  • library(car) 我猜想引用recode()
  • 提供一个您希望输出的示例可能会有所帮助?

标签: r loops vectorization


【解决方案1】:
  1. 这是不起作用的位:

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

    var 需要一个向量变量时,您正在为var 传递一个类似“data$x1_v”的字符串。如果您想进入组合字符串以形成表达式和函数调用的领域,您应该查看eval(),但我认为这对于您正在尝试做的事情来说太过分了。避免这种编程风格的另一个原因是它不能很好地与%&gt;% 配合使用。

  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() 内部,. 指的是“我正在操作的列”。不是“管道传递的输出。”

    也许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 &lt;- 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"))
     )
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多