【问题标题】:How to convert character string to executable code in R?如何将字符串转换为R中的可执行代码?
【发布时间】:2021-02-06 11:39:37
【问题描述】:

我有一个数据框,例如

df_reprex <- data.frame(id = rep(paste0("S",round(runif(100, 1000000, 9999999),0)), each=10),
                        date = rep(seq.Date(today(), by=-7, length.out = 10), 100),
                        var1 = runif(1000, 10, 20),
                        var2 = runif(1000, 20, 50),
                        var3 = runif(1000, 2, 5),
                        var250 = runif(1000, 100, 200),
                        var1_baseline = rep(runif(100, 5, 10), each=10),
                        var2_baseline = rep(runif(100, 50, 80), each=10),
                        var3_baseline = rep(runif(100, 1, 3), each=10),
                        var250_baseline = rep(runif(100, 20, 70), each=10))

我想编写一个包含 for 循环的函数,对于数据框中的每一行,该函数将从具有相同名称的非基线列中减去每个“_baseline”列。

我创建了一个脚本,它会自动创建一个包含我要运行的代码的字符串:

df <- df_reprex

# get only numeric columns
df_num <- df %>% dplyr::select_if(., is.numeric)

# create a version with no baselines
df_nobaselines <- df_num %>% select(-contains("baseline"))

#extract names of non-baseline columns
numeric_cols <- names(df_nobaselines)

#initialise empty string  
mutatestring <- ""

#write loop to fill in string:
for (colname in numeric_cols) {
  
 mutatestring <- paste(mutatestring, ",", paste0(colname, "_change"), "=", colname, "-", paste0(colname, "_baseline")) 
 
 # df_num <- df_num %>%
 #   mutate(paste0(col, "_change") = col - paste0(col, "_baseline"))
  
}

mutatestring <- substr(mutatestring, 4, 9999999) # remove stuff at start (I know it's inefficient)
mutatestring2 <- paste("df %>% mutate(", mutatestring, ")") # add mutate call

但是当我尝试调用“mutatestring2”时,它只会打印字符串,例如:

[1] "df %>% mutate( var1_change = var1 - var1_baseline , var2_change = var2 - var2_baseline , var3_change = var3 - var3_baseline , var250_change = var250 - var250_baseline )"

我认为这部分会相对简单,我确定我错过了一些明显的东西,但我就是无法让该字符串中的文本运行!

我尝试了各种略显荒谬的方法,但都没有返回所需的输出(即字符串作为命令输入到控制台时返回的结果):

call(mutatestring2)
eval(mutatestring2)
parse(mutatestring2)
str2lang(mutatestring2)
mget(mutatestring2)

diff_func <- function() {mutatestring2}
diff_func1 <- function() {
  a <-mutatestring2
  return(a)}
diff_func2 <- function() {str2lang(mutatestring2)}
diff_func3 <- function() {eval(mutatestring2)}
diff_func4 <- function() {parse(mutatestring2)}
diff_func5 <- function() {call(mutatestring2)}

diff_func()
diff_func1()
diff_func2()
diff_func3()
diff_func4()
diff_func5()

我确信一定有一种非常简单的方法可以做到这一点,但我就是想不通!

如何将字符串转换为可以运行或传递给 magrittr 管道的字符串?

【问题讨论】:

  • 你需要在parse中使用text参数,然后eval的结果。例如,您可以使用eval(parse(text = "print(5)"))。但是,重要的是要注意,这通常是一个非常糟糕的主意,并且通常有一个更明智的选择。

标签: r string function loops


【解决方案1】:

你需要在parse中使用text参数,然后eval的结果。例如,您可以这样做:

eval(parse(text = "print(5)"))
#> [1] 5

但是,使用eval(parse()) 通常是一个非常糟糕的主意,通常还有更明智的选择。

在您的情况下,您可以在不诉诸 eval(parse()) 的情况下执行此操作,例如在基础 R 中,您可以像这样将所有适当的变量相互减去:

baseline <- grep("_baseline$", names(df_reprex), value = TRUE)

non_baseline <- gsub("_baseline", "", baseline)

df_new <- cbind(df_reprex, as.data.frame(setNames(mapply(
                  function(i, j) df_reprex[[i]] - df_reprex[[j]], 
                  baseline, non_baseline, SIMPLIFY = FALSE), 
                paste0(non_baseline, "_corrected"))))

或者,如果您想将整个内容保存在一个管道中而不存储中间变量,您可以这样做:

mapply(function(i, j) df_reprex[[i]] - df_reprex[[j]],
       grep("_baseline$", names(df_reprex), value = TRUE), 
       gsub("_baseline", "", grep("_baseline$", names(df_reprex), value = TRUE)), 
       SIMPLIFY = FALSE) %>%
  setNames(gsub("_baseline", "_corrected", 
                grep("_baseline$", names(df_reprex), value = TRUE))) %>%
  as.data.frame() %>%
  {cbind(df_reprex, .)}

【讨论】:

    猜你喜欢
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2011-12-06
    • 2018-11-13
    相关资源
    最近更新 更多