在R中编码时操作字符串上的引号

时间:2017-03-29 02:06:39

标签: r string function quotes

这实际上是关于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)  
    }
    
  2. 是否有任何函数允许我使用function(name_list[1])function(name_list[6])替换for循环中的a到f?这个问题也适用于在嵌入一大块代码的一些表/数据帧中使用列名创建列。 (as.namenoquote函数仅在引用向量/数据集时起作用,但在尝试将值分配给目标变量时不起作用,如果可能,任何人都可以分享为什么会发生这种情况?)

    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
      
    2. 我知道为什么%in%在这里不起作用,似乎R将1567,1456,123作为一个元素。所以我用strsplit分隔它们。但似乎它还没有奏效。想知道是否有任何方法可以让我们把字符串作为命令?

1 个答案:

答案 0 :(得分:2)

如果你需要做的只是将逗号分隔的列表(如"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会返回列表,因为它也可以是长度大于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将原始文本转换为未经评估的“表达式”,它以特殊R对象的形式表示R代码,eval将表达式传递给解释器以供执行。

至于noquote,它并不像你认为的那样做。它实际上并没有修改字符串,它只是为变量添加一个标志,以便它将打印而不带引号。您可以使用print(..., quote = FALSE)来模拟此行为。