在 R 中编码时处理字符串上的引号

Manipulating the quotes on strings when coding in R

这实际上是关于 R 中值的引用字符类型的一系列问题。当我回忆起我认为有趣且与该主题相关的任何其他相关问题时,会添加更多项目符号。为了简单起见,在这里我将使用一些简单的随机示例来解释我的问题。希望这会有所帮助:

  1. 当使用 for 循环构建一组数据集并希望输出一系列向量时,其名称在循环中名为 name_list = ("a", "b", "c", "d", "e", "f") 的列表中恢复,我们希望将其定义为

    for(i in 1:4){  
        a <- data[data$Year == 2010,]  
        b <- unique(data$Name)  
        c <- summarise(group_by(data,Year,Name), avg = mean(quantity))  
        ...  
        f <- left_join(data,data1, by = c("Year", "Names)  
    }
    

是否有任何函数允许我使用 function(name_list[1])function(name_list[6]) 来替换 for 循环中的 a 到 f?这个问题也适用于尝试使用某些嵌入代码块的 tables/data 框架中的列名创建列。 (as.namenoquote 函数在仅引用 vector/dataset 时起作用,但在尝试为目标变量赋值时不起作用,如果可能的话,任何人都可以分享为什么会发生这种情况吗?)

  1. 当我们从 SQL 或其他数据源中提取一些信息时,我们可能会将一些信息以逗号或其他分隔符分隔为一个变量。我们如何测试某些值是否属于以逗号分隔的值之一?请参阅下面的示例:

    1567 %in% c(1567,1456,123)
    TRUE
    a <- "c(1567,1456,123)"
    noquote(a)
    c(1567,1456,123)
    1567 %in% noquote(a)
    FALSE
    1567 %in% list(noquote(a))
    FALSE
    b <- "1567,1456,123"
    noquote(b)
    1567,1456,123
    1567 %in% noquote(strsplit(a,","))
    FALSE
    1567 %in% list(noquote(strsplit(a,",")))
    FALSE
    

我有点明白为什么 %in% 在这里不起作用,好像 R 将 1567,1456,123 作为一个元素。所以我用 strsplit 来分隔它们。但似乎它仍然无法正常工作。想知道有什么方法可以让 R 将字符串作为命令吗?

如果你需要做的只是将"1567,1456,123"这样的逗号分隔列表转换成c(1567, 1456, 123)这样的R向量,你绝对不需要把它们包在c(...)中并尝试直接将它们评估为向量。您应该只使用 strsplit 来拆分数据:

data_str <- "1567,1456,123"
data_vec <- as.integer(strsplit(string_data, ","))
stopifnot(1567 %in% data_vec)

注意strsplit returns一个列表,因为它也可以是长度大于1的字符向量:

stopifnot(
  all.equal(
    list(c("a", "b"), c("x", "y")),
    strsplit(c("a,b", "x,y"), ",")) == TRUE)

这对于在 SQL 输出的列上进行操作非常有用:

| id | concatenated_field |
|----|--------------------|
|  1 |    5362,395,9000,7 |
|  2 |       319,75624,63 |
           (etc.)

d <- data.frame(
  id = c(1, 2),
  concatenated_field = c("5362,395,9000,7", "319,75624,63"))
d$split_field <- strsplit(d$concatenated_field, ",")
sapply(d, class)
#             id concatenated_field        split_field
#      "numeric"        "character"             "list"
d$split_field[[1]]
# [1] "5362" "395"  "9000" "7"

或者,如果您正在读取一大串以逗号分隔的数据,您可以使用 scan:

data_vec <- scan(
  what = 0,  # arcane way to say "expect numeric input"
  sep = ",",
  text = "1,2,3,4,5,6,7,8,9,10")
stopifnot(all.equal(data_vec, 1:10) == TRUE)

scanstrsplit 更重型,也可以处理更复杂的输入,例如带引号字段的数据:

weird_data <- scan(what="", sep=",", text='marvin,ruby,"joe,joseph",dean')
print(weird_data)
# [1] "marvin"     "ruby"       "joe,joseph" "dean"

如果你真的确定你需要能够接受和评估作为输入传递的 R 代码(这可能非常危险,因为这意味着你将执行任意未经验证的 R 代码),您可以使用

r_code_string <- 'c("a", "b"), c("x", "y"))'
stopifnot(
  all.equal(
    c("a", "b"), c("x", "y")),
    eval(parse(r_code_string))) == TRUE)

parse 将原始文本转换为未计算的 "expression",它是以特殊 R 对象的形式表示 R 代码,eval 将表达式传递给解释器执行。

至于 noquote,它并不像您想象的那样。它实际上并没有修改字符串,它只是向变量添加了一个标志,以便它打印时不带引号。您可以使用 print(..., quote = FALSE).

模拟此行为