在 R 中编码时处理字符串上的引号
Manipulating the quotes on strings when coding in R
这实际上是关于 R 中值的引用字符类型的一系列问题。当我回忆起我认为有趣且与该主题相关的任何其他相关问题时,会添加更多项目符号。为了简单起见,在这里我将使用一些简单的随机示例来解释我的问题。希望这会有所帮助:
当使用 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.name
和 noquote
函数在仅引用 vector/dataset 时起作用,但在尝试为目标变量赋值时不起作用,如果可能的话,任何人都可以分享为什么会发生这种情况吗?)
当我们从 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)
scan
比 strsplit
更重型,也可以处理更复杂的输入,例如带引号字段的数据:
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)
.
模拟此行为
这实际上是关于 R 中值的引用字符类型的一系列问题。当我回忆起我认为有趣且与该主题相关的任何其他相关问题时,会添加更多项目符号。为了简单起见,在这里我将使用一些简单的随机示例来解释我的问题。希望这会有所帮助:
当使用 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.name
和 noquote
函数在仅引用 vector/dataset 时起作用,但在尝试为目标变量赋值时不起作用,如果可能的话,任何人都可以分享为什么会发生这种情况吗?)
当我们从 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)
scan
比 strsplit
更重型,也可以处理更复杂的输入,例如带引号字段的数据:
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)
.